#!/usr/bin/env expect
############################################################################
# Purpose: Test of SLURM functionality
#          Bluegene/Q only: Test advanced reservation creation with mutliple
#          blocks.
#
# Output:  "TEST: #.#" followed by "SUCCESS" if test was successful, OR
#          "FAILURE: ..." otherwise with an explanation of the failure, OR
#          anything else indicates a failure mode that must be investigated.
############################################################################
# Copyright (C) 2009-2011 Lawrence Livermore National Security
# Portions copyright (C) 2011 SchedMD LLC
# Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
# Written by Dave Bremer <dbremer@llnl.gov>, Morris Jette <jette@schedmd.com>
# CODE-OCEC-09-009. All rights reserved.
#
#
# This file is part of SLURM, a resource management program.
# For details, see <http://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 test_id       "8.24"
set exit_code     0
set res_name      ""
set res_name_save ""
set user_name     ""
set def_partition ""
set def_node      ""
set ii 0

print_header $test_id

if {([test_bluegene] == 0) || [string compare [get_bluegene_type] "Q"]} {
	send_user "\nWARNING: This test is only compatable with Bluegene/Q systems\n"
	exit $exit_code
}

#
# Procedure to create a new reservation and validate it.
# Modifies the global var res_name in the process
#
proc create_res { res_params failure_expected node_cnt_expected} {
	#exp_internal 1
	global alpha_numeric_under
	global exit_code
	global res_name
	global scontrol

	set node_cnt_match 0
	set ret_code 0
	set res_name ""

	#
	# Create a reservation using the list of params in res_params
	#
	set arglist [linsert $res_params 0 $scontrol create res]
	eval spawn $arglist
	expect {
		-re "Reservation created: ($alpha_numeric_under)" {
			set res_name $expect_out(1,string)
		}
		-re "Error creating the reservation: Invalid user" {
			if {!$failure_expected} {
				send_user "\nFAILURE: user not authorized "
				send_user "to create reservation\n"
			}
			set ret_code 1
			exp_continue
		}
		-nocase "Error" {
			if {!$failure_expected} {
				send_user "\nFAILURE: problem creating "
				send_user "reservation with args: $res_params\n"
			}
			set ret_code 1
			exp_continue
		}
		timeout {
			send_user "\nFAILURE: scontrol not responding\n"
			set ret_code 1
		}
		eof {
			wait
		}
	}
	if { $ret_code != 0 } {
		return $ret_code
	}

	spawn $scontrol show res $res_name
	expect {
		-re "ReservationName=($alpha_numeric_under)" {
			set tmp_res_name $expect_out(1,string)
			if {$tmp_res_name != $res_name} {
				if {!$failure_expected} {
					send_user "\nFAILURE: problem showing "
					send_user "reservation created with:  "
					send_user "$res_params\n"
				}
				set ret_code 1
			}
			exp_continue
		}
		-re "NodeCnt=$node_cnt_expected" {
			set node_cnt_match 1
		}
		-re "No reservations in the system" {
			if {!$failure_expected} {
				send_user "\nFAILURE: no reservations found  "
				send_user "after reservation created with:  "
				send_user "$res_params\n"
			}
			set ret_code 1
			exp_continue
		}
		-re "Reservation ($alpha_numeric_under) not found" {
			if {!$failure_expected} {
				send_user "\nFAILURE: Reservation $res_name not"
				send_user "found after reservation created "
				send_user "with:  $res_params\n"
			}
			set ret_code 1
			exp_continue
		}
		timeout {
			send_user "\nFAILURE: scontrol not responding\n"
			set ret_code 1
		}
		eof {
			wait
		}
	}
	if {$node_cnt_expected == 0 || $node_cnt_match == 0} {
		send_user "\nFAILURE: Expected node count of "
		send_user "$node_cnt_expected\n"
		set exit_code 1
	}
	#exp_internal 0

	return $ret_code
}


#
# Procedure to delete a reservation
#
proc delete_res { res_name } {
	global scontrol
	set ret_code 0

	spawn $scontrol delete ReservationName=$res_name
	expect {
		-re "invalid" {
			send_user "\nFAILURE: problem deleting reservation $res_name\n"
			set ret_code 1
			exp_continue
		}
		-re "reservation is in use" {
			send_user "\nFAILURE: $res_name is in use\n"
			set ret_code 1
			exp_continue
		}
	}
	return $ret_code
}


#
# Identify usable nodes in default partition
#
spawn $sinfo -h -o %32P
expect {
	-re "($alpha_numeric_under)(\\*)" {
		set def_partition $expect_out(1,string)
		exp_continue
	}
	eof {
		wait
	}
}
if {[string compare $def_partition ""] == 0} {
	send_user "\nFAILURE: failed to find default partition\n"
	exit 1
}
spawn $sinfo -h -o "NodeList=%N NodeCnt=%D" -p $def_partition
expect {
	-re "NodeList=($alpha_numeric_nodelist)" {
		set def_node $expect_out(1,string)
		set def_node_cnt $expect_out(2,string)
		exp_continue
	}
	-re "NodeCnt=($number)\.($number)K" {
		set def_node_cnt $expect_out(1,string)
		set def_node_cnt [expr $def_node_cnt * 1024 + 512]
		exp_continue
	}
	-re "NodeCnt=($number)K" {
		set def_node_cnt $expect_out(1,string)
		set def_node_cnt [expr $def_node_cnt * 1024]
		exp_continue
	}
	-re "NodeCnt=($number)" {
		set def_node_cnt $expect_out(1,string)
		exp_continue
	}
	eof {
		wait
	}
}
if {[string compare $def_node ""] == 0} {
	send_user "\nFAILURE: default partition seems to have no nodes\n"
	exit 1
}
send_user "\nNodeCnt=$def_node_cnt\n"

#
# Get the user name
#
spawn $bin_id -un
expect {
	-re "($alpha_numeric_under)" {
		set user_name $expect_out(1,string)
	}
	eof {
		wait
	}
}


#
# Make a list of lists with a series of parameters to test.  All the tests
# in goodtests should pass, all those in badtests should fail.
#
send_user "\nTESTING invalid reservation\n===========================\n"
set badtests "
	{StartTime=now   Duration=5   NodeCnt=1,A}
	{StartTime=now   Duration=5   NodeCnt=A,B}
	{StartTime=now   Duration=5   NodeCnt=1b,32}
"

foreach test $badtests {
	set ret_code [create_res $test 1 0]
	if {$ret_code == 0} {
		send_user "\nFAILURE: Reservation $test did not fail but should have\n"
		delete_res $res_name
		exit 1
	} else {
		send_user "Expected error.  You can turn that frown upside-down.\n"
	}
}

if {[test_super_user] == 0} {
	send_user "\nWARNING: Can not test more unless SlurmUser or root\n"
	exit $exit_code
}
if {[string compare [get_bluegene_layout] Dynamic]} {
	send_user "\nWARNING: Can not test more unless dynamic bluegene system\n"
	exit $exit_code
}

if {$def_node_cnt >= 512} {
	send_user "\nTESTING 512 node reservation\n============================\n"
	set goodtests "
		{StartTime=now   Duration=5   User=$user_name   NodeCnt=32,32,32,32,32}
		{StartTime=now   Duration=5   User=$user_name   NodeCnt=2}
		{StartTime=now   Duration=5   User=$user_name   NodeCnt=32,2,32}
	"
	set good_size(0) "512"
	set good_size(1) "512"
	set good_size(2) "512"

	set inx 0
	foreach test $goodtests {
		set ret_code [create_res $test 0 $good_size($inx)]
		if {$ret_code != 0} {
			send_user "\nFAILURE: Unable to create a valid reservation\n"
			exit $ret_code
		}
		set ret_code [delete_res $res_name]
		if {$ret_code != 0} {
			send_user "\nFAILURE: Unable to delete a reservation\n"
			exit $ret_code
		}
		incr inx
	}
}
spawn $scontrol show res

if {$def_node_cnt >= 1024} {
	send_user "\nTESTING 1024 node reservation\n=============================\n"
	set goodtests "
		{StartTime=now   Duration=5   User=$user_name   NodeCnt=32,32,512,32,32,32}
		{StartTime=now   Duration=5   User=$user_name   NodeCnt=800}
		{StartTime=now   Duration=5   User=$user_name   NodeCnt=32,500,32}
	"
	set good_size(0) "1024"
	set good_size(1) "1024"
	set good_size(2) "1024"

	set inx 0
	foreach test $goodtests {
		set ret_code [create_res $test 0 $good_size($inx)]
		if {$ret_code != 0} {
			send_user "\nFAILURE: Unable to create a valid reservation\n"
			exit $ret_code
		}
		set ret_code [delete_res $res_name]
		if {$ret_code != 0} {
			send_user "\nFAILURE: Unable to delete a reservation\n"
			exit $ret_code
		}
		incr inx
	}
}
spawn $scontrol show res

if {$def_node_cnt >= 2048} {
	send_user "\nTESTING 2048 node reservation\n=============================\n"
	set goodtests "
		{StartTime=now   Duration=5   User=$user_name   NodeCnt=2000}
		{StartTime=now   Duration=5   User=$user_name   NodeCnt=1k,1k}
		{StartTime=now   Duration=5   User=$user_name   NodeCnt=32,1k,32}
	"
	set good_size(0) "2048"
	set good_size(1) "2048"
	set good_size(2) "1536"

	set inx 0
	foreach test $goodtests {
		set ret_code [create_res $test 0 $good_size($inx)]
		if {$ret_code != 0} {
			send_user "\nFAILURE: Unable to create a valid reservation\n"
			exit $ret_code
		}
		set ret_code [delete_res $res_name]
		if {$ret_code != 0} {
			send_user "\nFAILURE: Unable to delete a reservation\n"
			exit $ret_code
		}
		incr inx
	}
}
spawn $scontrol show res

if {$def_node_cnt >= 4096} {
	send_user "\nTESTING 4096 node reservation\n=============================\n"
	set goodtests "
		{StartTime=now   Duration=5   User=$user_name   NodeCnt=32,2k,32,1k,32,512}
		{StartTime=now   Duration=5   User=$user_name   NodeCnt=3k,1k}
		{StartTime=now   Duration=5   User=$user_name   NodeCnt=2k,2k}
		{StartTime=now   Duration=5   User=$user_name   NodeCnt=1k,1k,1k,1k}
	"
	set good_size(0) "4096"
	set good_size(1) "4096"
	set good_size(2) "4096"
	set good_size(3) "4096"

	set inx 0
	foreach test $goodtests {
		set ret_code [create_res $test 0 $good_size($inx)]
		if {$ret_code != 0} {
			send_user "\nFAILURE: Unable to create a valid reservation\n"
			exit $ret_code
		}
		set ret_code [delete_res $res_name]
		if {$ret_code != 0} {
			send_user "\nFAILURE: Unable to delete a reservation\n"
			exit $ret_code
		}
		incr inx
	}
}
spawn $scontrol show res

if {$exit_code == 0} {
	send_user "\nSUCCESS\n"
}
exit $exit_code
