#! /usr/bin/env perl
##**************************************************************
##
## Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
## University of Wisconsin-Madison, WI.
## 
## Licensed under the Apache License, Version 2.0 (the "License"); you
## may not use this file except in compliance with the License.  You may
## obtain a copy of the License at
## 
##    http://www.apache.org/licenses/LICENSE-2.0
## 
## Unless required by applicable law or agreed to in writing, software
## distributed under the License is distributed on an "AS IS" BASIS,
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
## See the License for the specific language governing permissions and
## limitations under the License.
##
##**************************************************************

# This is a basic test to determine that DAGMan works correctly with late
# materialization. It tests two simple things:
# 1. We never exceed the max_materialize number of jobs (set to 2). 
# 2. The second factory does not get submitted until the first one is complete.

use CondorTest;
use CondorUtils;

# Instruct the test to start a new personal Condor instance with late
# materialization active.

#testreq: personal
my $config = <<CONDOR_TESTREQ_CONFIG;
	# this is now the default
	#SCHEDD_ALLOW_LATE_MATERIALIZE = true
	SUBMIT_FACTORY_JOBS_BY_DEFAULT = true
	DAGMAN_USE_DIRECT_SUBMIT = false
CONDOR_TESTREQ_CONFIG
#endtestreq


my $testDescription =  'Condor DAGMan - Late Materialization Test A';
my $testName = "job_dagman_latemat-A";

my $dagFileName = 'job_dagman_latemat-A.dag';
my $dagmanArgs = "-verbose";
my $nodesLogFile = "job_dagman_latemat-A.dag.nodes.log";

# Cleanup old files
runcmd("rm -f job_dagman_latemat-A.dag.*");

# Generate the DAG files we need
my $dagFileContent = "
	JOB NodeA job_dagman_latemat-A-nodeA.cmd
	JOB NodeB job_dagman_latemat-A-nodeB.cmd
	PARENT NodeA CHILD NodeB
";
my $nodeAFileContent = "
	executable          = x_sleep.pl
	max_materialize     = 2
	queue 10
";
my $nodeBFileContent = "
	executable          = x_sleep.pl
	max_materialize     = 2
	queue 5
";
emit_file("job_dagman_latemat-A.dag", $dagFileContent);
emit_file("job_dagman_latemat-A-nodeA.cmd", $nodeAFileContent);
emit_file("job_dagman_latemat-A-nodeB.cmd", $nodeBFileContent);


# Describe a series of regular expressions we expect to see in the nodes

# Note #1: We must find these lines in the specified order. Extra lines will 
#   appear in the log file; we can ignore these. We're only concerned that we 
#   see all these events, and that they appear in the correct order.

# Note #2: These will all be evaluated as regular expressions. They are written
#   here as strings because Perl does not allow regex arrays.

my @nodesOutputRegex = (
	# Start with the NodeA jobs.
	"-01\.000(.*)Cluster submitted",
	"000\.000(.*)Job submitted",
	"001\.000(.*)Job submitted",
	"Job terminated",
	"002\.000(.*)Job submitted",
	# From this point until the end of NodeA, there is no guaranteed ordering of 
	# events. Our main focus is to make sure that not all jobs are getting
	# submitted at once. We only need to look for every other submit event, and 
	# make sure they are being interspersed with terminate events.
	# Is there a better way to do this?
	"Job terminated",
	"004\.000(.*)Job submitted",
	"Job terminated",
	"006\.000(.*)Job submitted",
	"Job terminated",
	"008\.000(.*)Job submitted",
	"Job terminated",
	"-01\.000(.*)Cluster removed",
	# Now we move on to the NodeB jobs. The second factory should not get 
	# submitted until the first one is removed!
	"-01\.000(.*)Cluster submitted",
	"000\.000(.*)Job submitted",
	"001\.000(.*)Job submitted",
	"Job terminated",
	"002\.000(.*)Job submitted",
	"Job terminated",
	"004\.000(.*)Job submitted",
	"Job terminated",
	"-01\.000(.*)Cluster removed"
);

# truly const variables in perl
sub IDLE{1};
sub HELD{5};
sub RUNNING{2};

# Debug: dump all condor config values
runcmd("condor_config_val -write:up -");

$abnormal = sub 
{
	die "Error: Want to see only submit, execute and successful completion\n";
};

$aborted = sub 
{
	die "Error: DAG should not abort!\n";
};

$held = sub 
{
	die "Error: Held event NOT expected\n";
};

$executed = sub
{
	my %info = @_;

	CondorTest::debug("Good. We need the dag to run<$info{cluster}>\n",1);
};

$submitted = sub
{
	CondorTest::debug("Submitted: This test will see submit, executing and successful completion\n",1);
};

$success = sub
{
	CondorTest::debug("DAG completed successfully\n",1);
	CondorTest::debug("Verifying output\n",1);
	$didItPass = 1;

	# Make sure all expected lines are in the node output file, in the
	# correct order.
	# Extra lines are allowed because of the undeterministic nature of late
	# materialized jobs.
	CondorTest::debug("Checking $nodesLogFile\n",1);
	open(CHECK, "<$nodesLogFile") ||
			die "Error: Cannot open $nodesLogFile: $!\n";
	@output_lines = <CHECK>;
	close(CHECK);
	
	$max = $#node_output_lines > $#output_lines ? $#node_output_lines : $#output_lines;
	$regexindex = 0;
	
	for ($lineindex = 0; $lineindex <= $max; $lineindex++) {
		$line = $output_lines[$lineindex];
		$regex = $nodesOutputRegex[$regexindex];
		chomp($line);
		#CondorTest::debug("Comparing <$line> to <$regex>\n");
		if ($line =~ /$regex/) {
			CondorTest::debug("\tGot a match: $line\n");
			$regexindex += 1;
		}

		# If regexindex exceeds the number of regex's we're looking for, then
		# we're all done
		if($regexindex > $#nodesOutputRegex) {
			CondorTest::debug("Matched all regex expressions!");
			last;
		}
	}

	# If we didn't match every regex in the ordered list, the job failed
	if($regexindex <= $#nodesOutputRegex) {
		CondorTest::debug("Did not match all regex expressions");
		$didItPass = 0;
	}

	if($didItPass == 0) {
		die "Error: All expected files and correct output failed\n";
	}
};

my $on_evictedwithoutcheckpoint = sub {
	CondorTest::debug("Evicted Without Checkpoint from removing jobs.\n",1);
};

$failure = sub
{
	die "Error: DAG is not expected to fail!\n";
};

CondorTest::RegisterEvictedWithoutCheckpoint($testName, $on_evictedwithoutcheckpoint);
CondorTest::RegisterExitedSuccess( $testName, $success );
CondorTest::RegisterExitedFailure( $testName, $failure );
CondorTest::RegisterExecute($testName, $executed );
CondorTest::RegisterExitedAbnormal( $testName, $abnormal );
CondorTest::RegisterAbort( $testName, $aborted );
CondorTest::RegisterHold( $testName, $held );
CondorTest::RegisterSubmit( $testName, $submitted );

if( CondorTest::RunDagTest($testName, $dagFileName, 0, $dagmanArgs) ) {
	CondorTest::debug("$testName: SUCCESS\n",1);
	exit(0);
} else {
	die "Error: $testName: CondorTest::RunTest() failed\n";
}


sub emit_file {
	my $namex = shift;
	my $content = shift;

	my $fname = $testname . $namex;
	open (FH, ">$fname") || die "error writing to $fname: $!\n";
	print FH $content;
	close (FH);
	if ( ! CondorUtils::is_windows()) { chmod (0755, $fname); }
}