#!/usr/bin/env expect
############################################################################
# Purpose: Test of Slurm functionality
#          Submit job directly to slurmd without use of slurmctld scheduler.
#          (--no-allocate option). NOTE: Needs to run as SlurmUser or root.
############################################################################
# Copyright (C) 2002-2007 The Regents of the University of California.
# Copyright (C) 2008 Lawrence Livermore National Security.
# Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
# Written by Morris Jette <jette1@llnl.gov>
# CODE-OCEC-09-009. All rights reserved.
#
# 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 iterations 100

if {![is_super_user]} {
	skip "This test can't be run except as SlurmUser"
}

if {[get_config_param "FrontendName"] ne "MISSING"} {
    skip "This test is incompatible with front-end systems"
}

set switch [get_config_param "SwitchType"]
if {$switch ne "switch/none"} {
        skip "This test is incompatible with $switch"
}

#
# Submit a 1 node job and record the node name
#
set output [run_command_output -fail "$srun -v -N1 -l -t1 $bin_printenv SLURMD_NODENAME"]
if {![regexp {on host (\S+),} $output - nodelist_name]} {
	fail "Unable to parse assigned task host name from srun output"
}
if {![regexp -line {^0: (\S+)} $output - host_0]} {
	fail "Unable to parse value of SLURMD_NODENAME from srun output"
}

#
# Verify node count
#
if {[string compare $host_0 ""] == 0} {
	fail "Did not get hostname of task 0"
}
if {[string compare $nodelist_name ""] == 0} {
	fail "Did not get nodelist_name of task 0"
}
if {[string compare $host_0 $nodelist_name] != 0} {
	log_warn "Hostname inconsistency"
}
set include_node $host_0

#
# Submit a job directly to that node
#
set output [run_command_output -fail "$srun -N1 -l --nodelist=$include_node --no-allocate -t1 $bin_printenv SLURMD_NODENAME"]
if {![regexp -line {^0: (\S+)} $output - host_1]} {
	fail "Unable to parse value of SLURMD_NODENAME from srun output"
}
subtest {$host_1 eq $include_node} "Allocation was on included host" "$host_1 !=$include_node"

#
# Run three tasks at a time on some node and do so repeatedly
# This checks for slurmd race conditions
# The sleep between cycles is to make sure the job step completion
# logic has time to be processed (slurmd -> slurmctld messages)
# Note: process output in order of expected completion
#
set successes 0
for {set inx 0} {$inx < $iterations} {incr inx} {
	exec $bin_sleep 0.25

	set failures 0
	set srun_pid [spawn $srun -N1 --nodelist=$nodelist_name -t1 -l $bin_printenv SLURMD_NODENAME]
	set   alloc $spawn_id

	set srun_pid1 [spawn $srun -N1 --nodelist=$include_node -t1 -Z $bin_sleep 0.5]
	set   noalloc1 $spawn_id

	set srun_pid2 [spawn $srun -N1 --nodelist=$include_node -t1 -Z $bin_sleep 0.25]
	set   noalloc2 $spawn_id

	set timeout 20
	set spawn_id $noalloc2
	expect {
		-i $noalloc2
		-re "error:.*configuring interconnect" {
			log_debug "Can't avoid this possible error"
			exp_continue
		}
		-re "error:" {
			log_error "Some error happened"
			set failures 1
			exp_continue
		}
		timeout {
			log_error "srun not responding"
			slow_kill $srun_pid2
			set failures 1
		}
		eof {
			wait
		}
	}

	set spawn_id $noalloc1
	expect {
		-i $noalloc1
		-re "error:.*configuring interconnect" {
			log_debug "Can't avoid this possible error"
			exp_continue
		}
		-re "error:" {
			log_error "Some error happened"
			set failures 1
			exp_continue
		}
		timeout {
			log_error "srun not responding"
			slow_kill $srun_pid1
			set failures 1
		}
		eof {
			wait
		}
	}

	set timeout $max_job_delay
	set spawn_id $alloc
	expect {
		-i $alloc
		-re "Invalid node name specified" {
			log_error "Some error happened"
			set failures 1
			exp_continue
		}
		-re "error:.*configuring interconnect" {
			log_debug "Can't avoid this possible error"
			exp_continue
		}
		-re "error:" {
			log_error "Some error happened"
			set failures 1
			exp_continue
		}
		-re "0: ($re_word_str)" {
			set host_0 $expect_out(1,string)
			exp_continue
		}
		timeout {
			log_error "srun not responding"
			slow_kill $srun_pid
			set failures 1
		}
		eof {
			wait
		}
	}

	if {$failures == 0} {
		incr successes
	}
}
subtest {$successes == $iterations} "Race condition check" "[expr $iterations - $successes] out of $iterations iterations failed"
