#!/usr/bin/env expect
############################################################################
# Purpose: Test scancel with --full and/or --batch.
#
# Note:    This script generates and then deletes files in the working directory
#          named test6.15.input, test6.15.output, and test6.15.error
############################################################################
# Copyright (C) 2015-2019 SchedMD LLC.
# Written by Morris Jette <jette@schedmd.com>
# Rewritten by Albert Gil <albert.gil@schedmd.com>
#
# This file is part of Slurm, a resource management program.
# For details, see <https://slurm.schedmd.com/>.
# Please also read the included file: DISCLAIMER.
#
# Slurm is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Slurm is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along
# with Slurm; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA.
############################################################################
source ./globals

set file_in     "test$test_id.input"
set file_out    "test$test_id.output"
set file_prog   "test$test_id.prog"

set exit_code   0

#
# Delete vestigial files
#
file delete $file_out $file_prog

# Build prog
exec $bin_cc -o $file_prog $file_prog.c

#
# Build input script files
#
make_bash_script $file_in "
catch()
{
	echo 'Signaled: script'
	exit 0
}

trap catch USR1

./test6.15.prog &
$srun ./test6.15.prog step
wait
exit 0
"

set proctracktype [get_config_param "ProctrackType"]
log_debug "Proctrack: $proctracktype"
if {$proctracktype ne "proctrack/cgroup" && $proctracktype ne "proctrack/linuxproc" && $proctracktype ne "proctrack/pgid"} {
	skip "This test only works for proctrack/cgroup, proctrack/linuxproc or proctrack/pgid"
}

#
# Main test function
#
# It submits a batch script that runs a background command and a step.
# Both command and step are the same app that creates parent and child process.
# All three, the script, the command and the step have a signal handler
# for SIGUSR1 to print that the signal is received.
#
# The function uses scancel to signal the job, and finally check the stdout
# to verify that the signals are received as expected.
# The scancel can be used with $params to checck them.
#
proc test_signaling { batch full } {
	global wait_for_file wait_for_job cancel_job slow_kill
	global max_job_delay proctracktype
	global bin_sleep bin_cat
	global sbatch scancel file_out file_in
	global number re_word_str

	set job_id      0
	set rc          0

	#
	# Submit sbatch job
	#
	log_debug "Submit the job"
	set timeout $max_job_delay
	set sbatch_pid [spawn $sbatch --output=$file_out -t2 $file_in]
	expect {
		-re "Submitted batch job ($number)" {
			set job_id $expect_out(1,string)
			exp_continue
		}
		timeout {
			log_error "sbatch not responding"
			slow_kill $sbatch_pid
			return 1
		}
		eof {
			wait
		}
	}
	if {$job_id == 0} {
		log_error "Batch submit failure"
		return 1
	}

	#
	# Wait for job to start running
	#
	if {[wait_for_job $job_id "RUNNING"] != 0} {
		log_error "Waiting for job to start running"
		return 1
	}

	#
	# Signal the job
	#
	set params ""
	if { $batch } {
		set params [concat $params " --batch"]
	}
	if { $full } {
		set params [concat $params " --full"]
	}

	exec $bin_sleep 2
	log_debug "Signal the job"
	set cmd_str "$scancel -s SIGUSR1 $params $job_id"
	spawn [lindex $cmd_str 0] {*}[lrange $cmd_str 1 end]
	expect {
		eof {
			wait
		}
	}

	#
	# Wait for completion
	#
	if {[wait_for_job $job_id DONE] != 0} {
		log_error "Error completing job $job_id"
		cancel_job $job_id
		return 1
	}

	set expected_script_signaled 0
	set expected_parent_step_signaled 0
	set expected_parent_command_signaled 0
	set expected_child_step_signaled 0
	set expected_child_command_signaled 0

	if {$batch && !$full} {
		set expected_script_signaled 1
	} elseif {!$batch && !$full} {
		set expected_parent_step_signaled 1
		if {$proctracktype == "proctrack/linuxproc" || $proctracktype == "proctrack/pgid"} {
			set expected_child_step_signaled 1
		}
	} else {
		set expected_script_signaled 1
		set expected_parent_step_signaled 1
		set expected_parent_command_signaled 1
		set expected_child_command_signaled 1
		if {$proctracktype == "proctrack/linuxproc" || $proctracktype == "proctrack/pgid"} {
			set expected_child_step_signaled 1
		}
	}

	#
	# Grep the output file for the signaled process
	#
	set script_signaled          0
	set parent_step_signaled     0
	set parent_command_signaled  0
	set child_step_signaled      0
	set child_command_signaled   0

	if {[wait_for_file $file_out] == 0} {

		spawn $bin_cat $file_out
		expect {
			-re "Signaled: ($re_word_str)" {
				set signaled $expect_out(1,string)
				if {$signaled == "script"} {
					incr script_signaled
				} elseif {$signaled == "parent_step"} {
					incr parent_step_signaled
				} elseif {$signaled == "parent_command"} {
					incr parent_command_signaled
				} elseif {$signaled == "child_step"} {
					incr child_step_signaled
				} elseif {$signaled == "child_command"} {
					incr child_command_signaled
				}
				exp_continue
			}
			eof {
				wait
			}
		}
		if {$script_signaled != $expected_script_signaled} {
			log_error "Script signaled mismatch with expected ($script_signaled != $expected_script_signaled)"
			incr rc
		}
		if {$parent_step_signaled != $expected_parent_step_signaled} {
			log_error "Parent step signaled mismatch with expected ($parent_step_signaled != $expected_parent_step_signaled)"
			incr rc
		}
		if {$parent_command_signaled != $expected_parent_command_signaled} {
			log_error "Parent command signaled mismatch with expected ($parent_command_signaled != $expected_parent_command_signaled)"
			incr rc
		}
		if {$child_step_signaled != $expected_child_step_signaled} {
			log_error "Child step signaled mismatch with expected ($child_step_signaled != $expected_child_step_signaled)"
			incr rc
		}
		if {$child_command_signaled != $expected_child_command_signaled} {
			log_error "Child command signaled mismatch with expected ($child_command_signaled != $expected_child_command_signaled)"
			incr rc
		}
	} else {
		log_error "Error reading output file"
		set rc 1
	}

	return $rc
}

#
# Run the tests
#
if {[test_signaling 0 0]} { # No options
	log_error "TestCase: "
	incr exit_code
}

if {[test_signaling 1 0]} { # batch only
	log_error "TestCase: --batch"
	incr exit_code
}

if {[test_signaling 0 1]} { # full only
	log_error "TestCase: --full"
	incr exit_code
}

if {[test_signaling 1 1]  != 0} { # both
	log_error "TestCase: --full --batch"
	incr exit_code
}

#
# Cleaning
#
exec $bin_rm -f $file_in $file_out $file_prog

#
# Final results
#
if {$exit_code != 0} {
	fail "Test failed due to previous errors (\$exit_code = $exit_code)"
}
