+#!/usr/bin/perl\r
+##############################################################################\r
+#\r
+# Name: rantest\r
+#\r
+# Description: This script is a test driver script capable of running tests\r
+# individually or from a file. There are many facilities for\r
+# specifying input and options to this program - see the usage\r
+# and help subroutines for clues. Basically you can run rantest\r
+# by itself and it will interactively prompt you for what to do\r
+# and what information or options it needs. Additionally you can\r
+# set options in the environment such as RANTEST_VIEW or\r
+# RANTEST_UNIT to serve as defaults. Or you can use -view or\r
+# -type, for example, at the command line to supply such parms.\r
+# If rantest still doesn't have all it needs it will prompts.\r
+#\r
+# Note that options and/or test cases can be specified in config\r
+# files specified by RANTEST_FILE or -file. Embedded in the\r
+# config file can be additional options in the form of:\r
+#\r
+# b2_l3_rnc_irt_001.test:\r
+# ----------------------\r
+# view: p6258c_SIMCQ00000100_intview\r
+# type: rnc\r
+# unit: 4\r
+# exec: tc CN_SIM/TC_CN_Simulation_RANAP_Setup.profile -timeout 60\r
+# exec: tc CN_SIM/TC_CN_Simulation.profile -timeout -1 -pause 5\r
+# exec: tc RBS_SIM/TC_RBS_Sim_Cell_Setup.profile -timeout 180\r
+# exec: tc l3_rnc/irt/TC_b2_l3_rnc_irt_001.profile -timeout 180\r
+#\r
+# Above we've set view, type and unit for the test run\r
+# and defined test steps of tc\r
+# CN_SIM/TC_CN_Simulation_RANAP_Setup.profile,\r
+# CN_SIM/TC_CN_Simulation.profile,\r
+# RBS_SIM/TC_RBS_Sim_Cell_Setup.profile and\r
+# l3_rnc/irt/TC_b2_l3_rnc_irt_001.profile\r
+#\r
+# Note that you can specify optional additional\r
+# parameters after the test name like -timeout and a\r
+# bunch of other parameters as described in the "Command\r
+# Line in East" document.\r
+#\r
+# This would be run as so:\r
+#\r
+# $ rantest -file b2_l3_rnc_irt_001.test\r
+#\r
+# Suite files, those ending in .suite, are different\r
+# from .test files in that they merely contain a list of\r
+# .test files (relative to <view>/vobs/simdev/test) to\r
+# execute for this suite. Note that parameters can be\r
+# added after the suite file name:\r
+#\r
+# nightly.suite:\r
+# --------------\r
+# # RNC IRT tests\r
+# b2_l3_rnc_irt_007.test -unit 4\r
+# b2_l3_rnc_irt_014.test\r
+#\r
+# # RNC SCH tests\r
+# b2_l3_rnc_sch_001.test -view official_view\r
+# b2_l3_rnc_sch_003a.test\r
+#\r
+# Author: Andrew@ClearSCM.com\r
+#\r
+# Copyright (c) 2008, 2009 General Dynamics\r
+#\r
+# All rights reserved except as subject to DFARS 252.227-7014 of contract\r
+# number CP02H8901N issued under prime contract N00039-04-C-2009.\r
+#\r
+# Warning: This document contains technical data whose export is restricted\r
+# by the Arms Export Control Act (Title 22, U.S.C., Sec 2751, et seq.) or the\r
+# Export Administration Act of 1979, as amended, Title, 50, U.S.C., App. 2401\r
+# et seq. Violations of these export laws are subject to severe criminal\r
+# penalties. Disseminate in accordance with provisions of DoD Directive\r
+# 5230.25.\r
+#\r
+##############################################################################\r
+use strict;\r
+use warnings;\r
+\r
+use File::Basename;\r
+use File::Glob ':glob';\r
+use File::Path;\r
+use FindBin;\r
+use Getopt::Long;\r
+use Net::Domain qw (hostname);\r
+use Term::ANSIColor qw (:constants);\r
+use Term::ReadLine;\r
+use Term::ReadLine::Gnu;\r
+\r
+# Use the SDE Tools libraries. Sorry for this long path. I didn't come\r
+# up with it!\r
+#use lib "/cleartrig/ent/SNSD/muos/ccadm_tools/vobs/ranccadm/scripts/lib";\r
+use lib "$FindBin::Bin/../lib";\r
+\r
+use DateUtils;\r
+use Display;\r
+use Utils;\r
+use GetConfig;\r
+use Logger;\r
+\r
+error "$FindBin::Script only runs on seast1", 1\r
+ unless hostname eq "seast1";\r
+\r
+use lib "$FindBin::Bin/../lib";\r
+\r
+use GD::RantestDB;\r
+use GD::Nethawk::East;\r
+\r
+use constant VERSION_NBR=> "1.2.5";\r
+use constant VERSION => BOLD GREEN VERSION_NBR;\r
+use constant PROMPT => BOLD YELLOW "$FindBin::Script>";\r
+use constant DESC => BOLD RED "$FindBin::Script",\r
+ RESET "Version", VERSION\r
+ . RESET ": "\r
+ . BOLD CYAN "RAN T"\r
+ . RESET "ool for "\r
+ . BOLD CYAN "E"\r
+ . RESET "xecution of "\r
+ . BOLD CYAN "S"\r
+ . RESET "ystem "\r
+ . BOLD CYAN "T"\r
+ . RESET "ests";\r
+\r
+use constant HISTORY_FILE => "$ENV{HOME}/.rantest_hist";\r
+use constant LOGBASE => "$ENV{MNT_DIR}/testlogs";\r
+\r
+############################################################################\r
+# Globals\r
+############################################################################\r
+my $_east;\r
+my $_connected = 0;\r
+my $_debugging;\r
+my $_log;\r
+my $_term;\r
+my $_rantestdb;\r
+my $_testNbr = 0;\r
+my $_validationNbr = 0;\r
+\r
+my %_stats;\r
+\r
+my %_executionResults;\r
+\r
+my (%_opts, %_cmdline_opts);\r
+\r
+# Seed opts from the environment.\r
+$_opts{eastview} = $ENV{RANTEST_EASTVIEW} if $ENV{RANTEST_EASTVIEW};\r
+$_opts{eastview} = $ENV{RANTEST_VIEW} if $ENV{RANTEST_VIEW} && !$_opts{eastview};\r
+$_opts{tm500view} = $ENV{RANTEST_TM500VIEW} if $ENV{RANTEST_TM500VIEW};\r
+$_opts{nmsview} = $ENV{RANTEST_NMSVIEW} if $ENV{RANTEST_NMSVIEW};\r
+$_opts{type} = $ENV{RANTEST_TYPE} if $ENV{RANTEST_TYPE};\r
+$_opts{class} = $ENV{RANTEST_CLASS} if $ENV{RANTEST_CLASS};\r
+$_opts{unit} = $ENV{RANTEST_UNIT} if $ENV{RANTEST_UNIT};\r
+$_opts{test} = $ENV{RANTEST_TEST} if $ENV{RANTEST_TEST};\r
+$_opts{file} = $ENV{RANTEST_FILE} if $ENV{RANTEST_FILE};\r
+$_opts{rfr} = $ENV{RANTEST_RFR} if $ENV{RANTEST_RFR};\r
+$_opts{checkin_on_error}= $ENV{CHECKIN_ON_ERROR} if $ENV{CHECKIN_ON_ERROR};\r
+$_opts{feature} = $ENV{RANTEST_FEATURE} if $ENV{RANTEST_FEATURE};\r
+$_opts{regression} = $ENV{RANTEST_REGRESSION} if $ENV{RANTEST_REGRESSION};\r
+$_opts{secure} = $ENV{RANTEST_SECURE} if $ENV{RANTEST_SECURE};\r
+\r
+# Explicitly default secure to either $ENV{RANTEST_SECURE}, if defined, otherwise 1\r
+$_opts{secure} = $ENV{RANTEST_SECURE} ? $ENV{RANTEST_SECURE} : 1;\r
+\r
+sub usage (;$) {\r
+ my ($msg) = @_;\r
+\r
+ my $usage = "ERROR: $msg\n\n" if $msg;\r
+\r
+ $usage .= <<END;\r
+Usage: $FindBin::Script\t[-us|age] [-v|erbose] [-d|ebug]\r
+ [-view|-eastview <view>] [-tm500view <view>] [-nmsview <view>]\r
+ [-type <type>] [-class <class>] [-rfr <testcase ID>] [-checkin_on_error]\r
+ [-unit <unit #>] [-test <test>] [-file <file>] [-feature <feature>]\r
+ [-[no]s|ecure]\r
+\r
+Where:\r
+\r
+ -us|age: Display usage\r
+ -ve|rbose: Turn on verbose mode\r
+ -d|ebug: Turn on debug mode\r
+ -[ea|st]view <tag> View tag to run test(s) under\r
+ -tm|500view <tag> TM 500 view to set into the environment for\r
+ test\r
+ -nm|sview <tag> NMS view to set into the environment for\r
+ test\r
+ -ty|pe <type> Type of unit to test (i.e. rbs | rnc)\r
+ -c|lass <class> Class of test (i.e. one of the following):\r
+\r
+ Load LoadTCRunner\r
+ Pool RegressionLoadRunner\r
+ TC RegressionRunner\r
+ TS RegressionTSRunner\r
+ Manual Manual test\r
+\r
+ -un|it <unit #> Unit number to test on\r
+ -te|st <test> Name of test (Optional: If not specific you will\r
+ be prompted for test case names)\r
+ -f|ile <file> File containing a list of tests to execute (Optional:\r
+ Contains a file of test classes and names to test)\r
+ -rfr <testcase ID> Run for record: ID is the test case ID to store\r
+ results under\r
+ -checkin_on_error Checks in rfr log files even if a test(s) fails\r
+ -regression Run regression tests. These tests will log there\r
+ results.\r
+ -feature <feature> If specified then FEATURE will be set into the\r
+ environment on the blade before calling\r
+ start_east_auto.\r
+ -[no]s|ecure Indicates whether or not to secure the node before\r
+ attempting to connect to it. (Default: secure).\r
+\r
+NOTE: Set ANSI_COLORS_DISABLED to turn off colors\r
+\r
+If you specify -file you cannot specify -test nor -class. -class'es are\r
+read from -file.\r
+\r
+Additionally, options above can be specified in the environment by\r
+preceeding the environment variable with \"RANTEST_\". For example,\r
+\r
+ \$ export RANTEST_TYPE=rbs\r
+ \$ export RANTEST_UNIT=2\r
+ \$ rantest\r
+\r
+Also such options can be specified in the -file:\r
+\r
+ unit: 5\r
+ executionlevel: 2\r
+ ts ts1.profile -timeout -1 -pause 5\r
+ ts ts2.profile -displaylevel 3\r
+ ts ts3.profile -activecalls 10\r
+\r
+Options after test profile name are passed directory to EAST's command\r
+line. The exceptions are -timeout and -pause:\r
+\r
+ -timeout <n> Specifies the timeout for this test's execution.\r
+ If negative the test will be placed in the\r
+ background. No result is recovered from\r
+ background tests nor are any logfiles analysed\r
+ or stored. If positive then this sets the\r
+ timeout period for this test in seconds.\r
+\r
+ -pause <n> Used in conjunction with -timeout. If test is\r
+ backgrounded then $FindBin::Script will wait\r
+ pause seconds before returning control from\r
+ this test. This allows the backgrounded test\r
+ time to start.\r
+\r
+ -name <name> Names a test. Used in conditional execution.\r
+\r
+ -if (<name> <status>) Run this test if the named test returned <status>\r
+ where <status> is one of\r
+\r
+ . Success\r
+ . Failure\r
+ . In Progress\r
+ . Timed out\r
+ . Failed to execute\r
+ . Rendezvous\r
+ . Failed to rendezvous\r
+\r
+Note: Required options not supplied will be prompted for.\r
+END\r
+\r
+ my $pager = $ENV{PAGER} ? $ENV{PAGER} : "more";\r
+\r
+ system "echo \"$usage\" | $pager";\r
+\r
+ exit 1 if $msg;\r
+} # usage\r
+\r
+sub help () {\r
+ display DESC . RESET;\r
+ display <<END;\r
+\r
+Valid commands are:\r
+\r
+help: This display\r
+usage: Displays command line usage\r
+version: Displays version of $FindBin::Script\r
+exit|quit: Exits $FindBin::Script\r
+source <file> Execute the contents of <file>\r
+set <option>=<value> Set <option> to <value>\r
+get <option> Displays <option> (if set)\r
+elock <pattern> Display elock status (default all units)\r
+\r
+Running tests:\r
+\r
+load <test profile> <options> Run a test case by profile (LoadTCRunner)\r
+pool <test profile> <options> Run a regression load (RegressionLoadRunner)\r
+tc <test profile> <options> Run a regression (RegressionRunner)\r
+ts <test profile> <options> Run a regression test suite (RegressionTSRunner)\r
+manual\r
+\r
+Note: ReadLine is supported thus you can edit previous commands.\r
+Try the up arrow!\r
+END\r
+} # Help\r
+\r
+sub getParm ($) {\r
+ my ($prompt) = @_;\r
+\r
+ my $value;\r
+\r
+ while (!$value or $value eq "") {\r
+ display_nolf BOLD YELLOW . "$FindBin::Script needs the following parameter - $prompt" . RESET;\r
+\r
+ $value = <STDIN>;\r
+\r
+ chomp $value;\r
+ } # while\r
+\r
+ return $value;\r
+} # getParm\r
+\r
+sub eLock (;$) {\r
+ my ($unit) = @_;\r
+\r
+ my ($status, @locks) = Execute "ls $ENV{MNT_DIR}/$ENV{EAST_REL}/DUT/*/desktop.lock 2> /dev/null";\r
+\r
+ $status >>= 8;\r
+\r
+ foreach (@locks) {\r
+ my $unit_found;\r
+\r
+ if (/.*DUT\/(\w+)\/desktop/) {\r
+ $unit_found = $1;\r
+\r
+ next if $unit && $unit_found !~ /$unit/i;\r
+ } # if\r
+\r
+ my @fields = split /\//, $_;\r
+ my $uid = (stat $_)[4];\r
+ my $mtime = (stat $_)[9];\r
+ my $userid = (getpwuid ($uid))[0];\r
+ my $name = (getpwuid ($uid))[6];\r
+\r
+ display BOLD CYAN "$fields[5]\t"\r
+ . RESET "locked since "\r
+ . BOLD YELLOW localtime ((stat $_)[9])\r
+ . RESET " by "\r
+ . MAGENTA $name\r
+ . RESET " ("\r
+ . GREEN $userid\r
+ . RESET ")";\r
+ } # foreach\r
+} # eLock\r
+\r
+sub displaySummary () {\r
+ my $msg = "Summary:";\r
+\r
+ foreach (sort keys %_stats) {\r
+ $msg .= " $_stats{$_} $_";\r
+ } # foreach\r
+\r
+ $_log->msg ($msg) if $_log;\r
+} # displaySummary\r
+\r
+sub announceTestrun ($) {\r
+ my ($testname) = @_;\r
+\r
+ my $user = $ENV{USER} ? $ENV{USER}\r
+ : $ENV{LOGNAME} ? $ENV{LOGNAME}\r
+ : "Unknown";\r
+ my $timestamp = YMDHMS;\r
+\r
+ $_testNbr++;\r
+\r
+ verbose BOLD YELLOW "Test #" . $_testNbr . "\t"\r
+ . RESET CYAN $testname\r
+ . RESET " run on $timestamp by "\r
+ . YELLOW $user\r
+ . RESET " on "\r
+ . MAGENTA $_opts{type}\r
+ . RESET " unit "\r
+ . CYAN $_opts{unit}\r
+ . RESET;\r
+\r
+ $_log->log ("Test #$_testNbr $testname run on: $timestamp by $user on $_opts{type} unit $_opts{unit}");\r
+} # announceTestrun\r
+\r
+sub saveHistory {\r
+ $_term->WriteHistory (HISTORY_FILE) if $_term;\r
+} # saveHistory\r
+\r
+sub executeTestStep () {\r
+ if (!$_connected) {\r
+ # Get required parameters if not specified in the command line or environment\r
+ $_opts{eastview} = getParm "View:" unless $_opts{eastview};\r
+ $_opts{type} = getParm "Type:" unless $_opts{type};\r
+ $_opts{class} = getParm "Class:" unless $_opts{class};\r
+ $_opts{unit} = getParm "Unit:" unless $_opts{unit};\r
+\r
+ # Connect to it\r
+ my $msg = $_east->connect (\r
+ $_opts{eastview},\r
+ $_opts{type},\r
+ $_opts{unit},\r
+ $_opts{tm500view},\r
+ $_opts{nmsview},\r
+ $_opts{feature},\r
+ $_opts{secure}\r
+ );\r
+\r
+ if ($msg) {\r
+ $_log->err ("Unable to connect to EAST\n$msg");\r
+ verbose RED "Skipping renaming test steps" . RESET;\r
+ $_stats{Failed}++;\r
+ return -1;\r
+ } else {\r
+ $_connected = 1;\r
+ } # if\r
+ } # if\r
+\r
+ my ($status, $msg) = Nethawk::East::validTestType ($_opts{class});\r
+\r
+ if ($status != 0) {\r
+ $_log->err ($msg);\r
+ return $status;\r
+ } # if\r
+\r
+ if (!$_opts{test}) {\r
+ # Manual tests only have classes\r
+ unless ($_opts{class} eq 'manual') {\r
+ $_log->err ("No test specified");\r
+ return 1;\r
+ } # unless\r
+ } # if\r
+\r
+ $_east->setCollectLogFiles (1);\r
+\r
+ verbose_nolf $_stats{Run} . ": " . CYAN "$_opts{class}\t" . BOLD YELLOW $_opts{test} . RESET;\r
+\r
+ my $testStepResult;\r
+\r
+ my $startTime = time;\r
+ my $stepName = "Unknown";\r
+\r
+ if ($_opts{test} =~ /(.*)\.profile/) {\r
+ $stepName = $1;\r
+ } elsif ($_opts{class} eq "manual") {\r
+ $stepName = "Manual";\r
+ } elsif ($_opts{class} eq "shell") {\r
+ $stepName = $_opts{test};\r
+ } elsif ($_opts{test} =~ /^rantvl/) {\r
+ $stepName = $_opts{test};\r
+\r
+ $_east->setRantvlStartTime (time);\r
+ } # if\r
+\r
+ my ($stepID, $errMsg) = $_rantestdb->startSteprun ($stepName);\r
+\r
+ ($status, $testStepResult) = $_east->exec (\%_opts, \%_executionResults);\r
+\r
+ # Collect any extended logs\r
+ if ((!defined $_opts{timeout} or $_opts{timeout} > 0) and\r
+ ($_east->{class} eq "load" or\r
+ $_east->{class} eq "tc" or\r
+ $_east->{class} eq "ts" or\r
+ $_east->{class} eq "pool")) {\r
+ $_east->collectExtendedLogFiles;\r
+ } # if\r
+\r
+ my $endTime = time;\r
+\r
+ if ($status == 0) {\r
+ if ($testStepResult eq "Success") {\r
+ verbose GREEN " $testStepResult" . RESET;\r
+ $_stats{Passed}++;\r
+ } elsif ($testStepResult eq "In progress" or\r
+ $testStepResult eq "Logging started") {\r
+ verbose MAGENTA " $testStepResult" . RESET;\r
+ $_stats{Concurrent}++;\r
+ } elsif ($testStepResult eq "Rendezvous") {\r
+ verbose BOLD . " $testStepResult" . RESET;\r
+ $_stats{Rendezvous}++;\r
+ } else {\r
+ verbose RED " $testStepResult" . RESET;\r
+ $status = 1;\r
+ $_stats{Failed}++;\r
+ } # if\r
+ } else {\r
+ if ($testStepResult eq "Skipped") {\r
+ verbose BOLD . " $testStepResult" . RESET;\r
+ $_stats{Skipped}++;\r
+ } elsif ($testStepResult eq "Timed out") {\r
+ verbose CYAN " $testStepResult" . RESET;\r
+ $status = 1;\r
+ $_stats{Timedout}++;\r
+ } else {\r
+ verbose RED " $testStepResult" . RESET;\r
+ $status = 1;\r
+ $_stats{Failed}++;\r
+ } # if\r
+ } # if\r
+\r
+ # Log test step result\r
+ $_log->log ("$_stats{Run}: $_opts{class}\t$_opts{test} $testStepResult");\r
+\r
+ my ($dbErrNbr, $dbErrMsg) = $_rantestdb->endSteprun (\r
+ runID => $_east->{runID},\r
+ stepID => $stepID,\r
+ start => UnixDatetime2SQLDatetime (scalar (localtime ($startTime))),\r
+ end => UnixDatetime2SQLDatetime (scalar (localtime ($endTime))),\r
+ result => $testStepResult,\r
+ );\r
+\r
+ error $dbErrMsg if $dbErrNbr != 0;\r
+\r
+ return $status;\r
+} # executeTestStep\r
+\r
+sub testTimeout {\r
+ error "Test timed out ($_opts{testtimeout}) seconds passed)";\r
+\r
+ $_east->disconnect;\r
+\r
+ # Collect logfiles\r
+ $_east->collectLogFiles;\r
+} # testTimeout\r
+\r
+sub interrupted {\r
+ use Term::ReadKey;\r
+\r
+ display BLUE "\nInterrupted" . RESET;\r
+\r
+ displaySummary;\r
+\r
+ display_nolf\r
+ CYAN . BOLD "C" . RESET CYAN "ontinue" . RESET . " or " .\r
+ MAGENTA . BOLD "A" . RESET MAGENTA "bort run" . RESET . " (" .\r
+ CYAN . BOLD "C" . RESET "/" .\r
+ MAGENTA . BOLD "a" . RESET ")?";\r
+\r
+ ReadMode ("cbreak");\r
+ my $answer = ReadKey (0);\r
+ ReadMode ("normal");\r
+\r
+ if ($answer eq "\n") {\r
+ display "c";\r
+ } else {\r
+ display $answer;\r
+ } # if\r
+\r
+ $answer = lc $answer;\r
+\r
+ if ($answer eq "c") {\r
+ display "Continuing...";\r
+ } elsif ($answer eq "a") {\r
+ display RED "Aborting run" . RESET;\r
+ $_east->setCollectLogFiles (0);\r
+ saveHistory;\r
+ exit;\r
+ } # if\r
+} # interrupted\r
+\r
+sub interpolate ($) {\r
+ my ($str) = @_;\r
+\r
+ # Perform psuedo variable interpolation. The following psuedo\r
+ # variables are supported:\r
+ #\r
+ # view: Absolute path to your view\r
+ my $view = "$ENV{MNT_DIR}/snapshot_views/$_east->{userdir}/$_east->{view}";\r
+ my $simdev = "$view/vobs/simdev";\r
+\r
+ # msgdefs: Absolute path to msgdefs\r
+ my $msgdefs = "$simdev/msgdefs";\r
+\r
+ # validation: Absolute path to validation\r
+ my $validation = "$simdev/validation";\r
+\r
+ # logpath: Absolute path into the "testlogs" area where\r
+ # logfiles are written\r
+ my $logpath = LOGBASE . "/" . $_east->getSaveTo;\r
+\r
+ while ($str =~ /\$/) {\r
+ my ($var, $slice);\r
+\r
+ if ($str =~ /\$(\w+)/) { \r
+ # Regular $var\r
+ $var = $1;\r
+ } elsif ($str =~ /\$(\[.+?\])\[(.+?)\]/) {\r
+ # A $[fileset][slice] reference\r
+ $var = $1;\r
+ $slice = $2;\r
+ } elsif ($str =~ /\$(\[.+?\])/) { \r
+ # A $[fileset] reference\r
+ $var = $1;\r
+ } # if\r
+\r
+ if ($var eq "logpath") {\r
+ $str =~ s/\$$var/$logpath/;\r
+ } elsif ($var eq "msgdefs") {\r
+ $str =~ s/\$$var/$msgdefs/;\r
+ } elsif ($var eq "validation") {\r
+ $str =~ s/\$$var/$validation/;\r
+ } elsif ($var eq "view") {\r
+ $str =~ s/\$$var/$view/;\r
+ } elsif ($var =~ /\[(.+)\]/) {\r
+ my $fileset = $1;\r
+\r
+ my @fileset = glob $fileset;\r
+ my $list;\r
+\r
+ if (defined $slice) {\r
+ $fileset = quotemeta $fileset;\r
+\r
+ # Here we handle a slice, but if the slice is of the form x..y\r
+ # then we need to handled it differently\r
+ if ($slice =~ /(\d+)\.\.(\d+)/) {\r
+ # Need to turn off warnings for this next construct of\r
+ # @array[$1..$2]. Otherwise it complains. If we use\r
+ # $array[$1..$2] then it doesn't work! Also take on the\r
+ # base fileset defined above.\r
+ #\r
+ # Adjust bounds\r
+ $2 = $#fileset if $2 > $#fileset;\r
+\r
+ no warnings;\r
+ $list = join ",", @fileset[$1..$2];\r
+ use warnings;\r
+ } else {\r
+ # Not a slice really but an array reference\r
+ $list = "$fileset[$slice]";\r
+ } # if\r
+\r
+ $str =~ s/\$\[$fileset\]\[$slice\]/$list/;\r
+ } else {\r
+ $list = join ",", @fileset;\r
+ $str =~ s/\$\[$fileset\]/$list/;\r
+ } # if\r
+\r
+ if (defined $slice) {\r
+ $str =~ s/\$\[$fileset\]\[$slice\]//;\r
+ } else {\r
+ $str =~ s/\$\[$fileset\]//;\r
+ } # if\r
+ } else {\r
+ error "Unknown variable ($var) encountered in val line:\n$str", 1;\r
+ } # if\r
+ } # while\r
+\r
+ return $str;\r
+} # interpolate\r
+\r
+sub runValidation ($$) {\r
+ my ($cmd, $logfile) = @_;\r
+\r
+ my $origCmd = $cmd;\r
+\r
+ my ($stepID, $errMsg);\r
+\r
+ ($stepID, $errMsg) = $_rantestdb->startSteprun ($origCmd);\r
+\r
+ if ($stepID == 0) {\r
+ error "Unable to startSteprun\n$errMsg";\r
+ return 1;\r
+ } # if\r
+\r
+ my $startTime = time;\r
+\r
+ $cmd = interpolate ($cmd);\r
+\r
+ my ($status, @lines) = Execute ("$cmd >> $logfile 2>&1");\r
+\r
+ $status >>= 8;\r
+\r
+ my $endTime = time;\r
+\r
+ my ($dbErrNbr, $dbErrMsg) = $_rantestdb->endSteprun (\r
+ runID => $_east->{runID},\r
+ stepID => $stepID,\r
+ start => UnixDatetime2SQLDatetime (scalar (localtime ($startTime))),\r
+ end => UnixDatetime2SQLDatetime (scalar (localtime ($endTime))),\r
+ result => $status ? "Failure" : "Success",\r
+ );\r
+\r
+ error $dbErrMsg if $dbErrNbr != 0;\r
+\r
+ # Output lines to stdout\r
+ if (-e $logfile) {\r
+ verbose "$_\n" foreach (ReadFile $logfile);\r
+ } else {\r
+ verbose "Unable to read $logfile";\r
+ $status++;\r
+ } # if\r
+\r
+ $_validationNbr++;\r
+\r
+ verbose BOLD YELLOW . "Test #$_testNbr validation #$_validationNbr \t" . RESET CYAN $origCmd\r
+ . (($status == 0) ? GREEN " Success" : RED " Failure") . RESET;\r
+\r
+ $_log->log ("Test #$_testNbr validation #$_validationNbr\t$origCmd " . (($status == 0) ? "Success" : "Failure"));\r
+\r
+ return $status;\r
+} # runValidation\r
+\r
+sub runValidations (@) {\r
+ my @validations = @_;\r
+\r
+ my $validationErrs = 0;\r
+\r
+ # Make Validation log directory\r
+ my $validationDir = LOGBASE . "/" . $_east->getSaveTo . "/Validations";\r
+\r
+ eval { mkpath $validationDir };\r
+\r
+ error "Unable to create Validation directory - $validationDir\n$@", 1 if $@;\r
+\r
+ chmod 0775, $validationDir;\r
+\r
+ my $viewPath = "$ENV{MNT_DIR}/snapshot_views/$_east->{userdir}/$_east->{view}";\r
+ my $vobPath = "vobs/simdev";\r
+\r
+ foreach (@validations) {\r
+ my @tokens = split;\r
+ my $outfile = $tokens[0] . ".log";\r
+\r
+ $validationErrs += runValidation $_, "$validationDir/$outfile";\r
+ } # foreach\r
+\r
+ $_stats{Failed} += $validationErrs;\r
+\r
+ return $validationErrs;\r
+} # runValidations\r
+\r
+sub runTestFile ($) {\r
+ my ($file) = @_;\r
+\r
+ my $testName = fileparse $file, ".test";\r
+\r
+ my $testID = $_rantestdb->startTest ($testName);\r
+\r
+ my %fileopts = GetConfig ($file);\r
+\r
+ # GetConfig leaves keys %fileopts as case sensitive but we want them\r
+ # case insentive so fix that here.\r
+ foreach (keys (%fileopts)) {\r
+ my $key = lc $_;\r
+\r
+ # Make "view" an alias for "eastview" but only if there is no\r
+ # eastview already defined\r
+ if ($key eq "view") {\r
+ if (!$fileopts{eastview}) {\r
+ $fileopts{eastview} = delete $fileopts{view};\r
+ $_ = $key = "eastview";\r
+ } # if\r
+ } # if\r
+\r
+ # Set into %_opts only if that key doesn't exist already. This\r
+ # allows command line options to override options specified in the\r
+ # file. The exception to this is the exec array. This gets\r
+ # replaced in suite runs.\r
+ if ($key eq "exec" || !$_opts{$key}) {\r
+ $_opts{$key} = $fileopts{$_};\r
+ } # if\r
+ } # foreach\r
+\r
+ my $testStartTime = time;\r
+\r
+ $_east->setSaveTo ("$testName/$_opts{type}$_opts{unit}/" . YMDHMS ($testStartTime));\r
+\r
+ eval { mkpath LOGBASE . "/" . $_east->getSaveTo };\r
+\r
+ error "Unable to create log directory\n$@", 1 if $@;\r
+\r
+ chmod 0775, LOGBASE . "/" . $_east->getSaveTo;\r
+\r
+ unless ($_log) {\r
+ $_log = new Logger (\r
+ name => $testName,\r
+ path => LOGBASE . "/" . $_east->getSaveTo,\r
+ append => "yes",\r
+ );\r
+\r
+ $_log->log ("$FindBin::Script Version " . VERSION_NBR . "\nUsing view: $_opts{eastview}");\r
+ } # unless\r
+\r
+ verbose BOLD CYAN "Using view: " . RESET $_opts{eastview};\r
+\r
+ announceTestrun $testName;\r
+\r
+ my @tokens;\r
+\r
+ my $testFailures = 0;\r
+ my $result = 0;\r
+ my $errMsg;\r
+\r
+ # Set testTimer if specified\r
+ if ($_opts{testtimeout}) {\r
+ $SIG{ALRM} = \&testTimeout;\r
+ alarm $_opts{testtimeout};\r
+ } # if\r
+\r
+ ($_east->{runID}, $errMsg) = $_rantestdb->startTestrun (UnixDatetime2SQLDatetime localtime $testStartTime);\r
+\r
+ return ($_east->{runID}, $errMsg) if $_east->{runID} == 0;\r
+\r
+ $_validationNbr = 0;\r
+\r
+ if (ref $_opts{exec} eq "ARRAY") {\r
+ foreach (@{$_opts{exec}}) {\r
+ @tokens = split;\r
+\r
+ $_opts{class} = shift @tokens;\r
+ $_opts{test} = join " ", @tokens;\r
+\r
+ $_stats{Run}++;\r
+\r
+ $result = executeTestStep;\r
+\r
+ if ($result == -1) {\r
+ $testFailures++;\r
+ last;\r
+ } else {\r
+ $testFailures += $result;\r
+ } # if\r
+ } # foreach\r
+ } else {\r
+ if ($_opts{exec}) {\r
+ @tokens = split /\s+/, $_opts{exec};\r
+\r
+ $_opts{class} = shift @tokens;\r
+ $_opts{test} = join " ", @tokens;\r
+\r
+ $_stats{Run}++;\r
+\r
+ $result = executeTestStep;\r
+\r
+ if ($result == -1) {\r
+ $testFailures++;\r
+ } else {\r
+ $testFailures += $result;\r
+ } # if\r
+ } # if\r
+ } # if\r
+\r
+ my $execType = $_opts{rfr} ? "Run for Record"\r
+ : $_opts{regression} ? "Regression" : "Normal";\r
+\r
+ return 1 if $result == -1;\r
+\r
+ # Disconnect from EAST\r
+ $_east->disconnect;\r
+\r
+ # Assign 'Failed' and 'Timedout' 0 if they are not initialized\r
+ $_stats{Failed} ||= 0;\r
+ $_stats{Timedout} ||= 0;\r
+\r
+ my $testErrors = $_stats{Failed} + $_stats{Timedout};\r
+\r
+ # Collect log files and check them in based on checkin_on_error option\r
+ $_east->collectLogFiles($testErrors, $_opts{checkin_on_error});\r
+\r
+ if ($testFailures == 0 and $_opts{val}) {\r
+ my @validations = ref $_opts{val} eq "ARRAY"\r
+ ? @{$_opts{val}}\r
+ : ($_opts{val});\r
+\r
+ $testFailures += runValidations @validations;\r
+ } # if\r
+\r
+ # Log test results\r
+ verbose BOLD YELLOW . "Test #$_testNbr\t" . RESET CYAN $testName\r
+ . (($testFailures == 0) ? GREEN " Success" : RED " Failure") . RESET;\r
+\r
+ $_log->log ("Test #$_testNbr\t$testName " . (($testFailures == 0) ? "Success" : "Failure"));\r
+\r
+ my ($_runID, $dbErrMsg) = $_rantestdb->endTestrun (\r
+ runID => $_east->{runID},\r
+ suiteID => $_east->{suiteID} ? $_east->{suiteID} : 0,\r
+ name => fileparse ($file, ".test"),\r
+ execType => $execType,\r
+ start => UnixDatetime2SQLDatetime (scalar (localtime ($testStartTime))),\r
+ result => $testFailures == 0 ? "Success" : "Failure",\r
+ unit => "$_east->{unitType}$_east->{unitNbr}",\r
+ rantest_version => VERSION_NBR,\r
+ east_version => $ENV{EAST_REL},\r
+ ran_version => $_east->{ran_version},\r
+ tm500_version => $_east->{tm500_version},\r
+ nms_version => $_east->{nms_version},\r
+ eastlogs => LOGBASE . "/" . $_east->getSaveTo,\r
+ );\r
+\r
+ error $dbErrMsg if $_runID == 0;\r
+\r
+ return $testFailures;\r
+} # runTestFile\r
+\r
+sub setPath ($) {\r
+ my ($view) = @_;\r
+\r
+ return if $ENV{PATH} =~ /$view/;\r
+\r
+ my $userdir;\r
+\r
+ if ($view =~ /(\S+)_SIM/) {\r
+ $userdir = $1;\r
+ } else {\r
+ error "Unable to find userdir", 1;\r
+ } # if\r
+\r
+ my @paths = (\r
+ "$ENV{MNT_DIR}/snapshot_views/$userdir/$view/vobs/simdev/sbin",\r
+ "$ENV{MNT_DIR}/snapshot_views/$userdir/$view/vobs/simdev/bin",\r
+ "$ENV{MNT_DIR}/snapshot_views/$userdir/$view/vobs/gdtools/rantest_auto/bin",\r
+ );\r
+\r
+ $ENV{PATH} = join (":", @paths) . ":" . $ENV{PATH};\r
+} # setPath\r
+\r
+sub runSuiteFile ($) {\r
+ my ($file) = @_;\r
+\r
+ error "View must be specified when running in suite mode", 1 unless $_opts{eastview};\r
+\r
+ setPath $_opts{eastview};\r
+\r
+ my $userdir;\r
+\r
+ if ($_opts{eastview} =~ /(\S+)_SIM/) {\r
+ $userdir = $1;\r
+ } else {\r
+ error "Unable to find userdir", 1;\r
+ } # if\r
+\r
+ unless (open FILE, $file) {\r
+ error "Unable to open file $file - $!";\r
+ return 1\r
+ } # unless\r
+\r
+ my @lines = <FILE>;\r
+\r
+ chomp @lines;\r
+\r
+ close FILE;\r
+\r
+ my $i = 0;\r
+ my $suiteStartTime = time;\r
+ my $suiteFailures = 0;\r
+ my $suiteName = fileparse ($file, ".suite");\r
+\r
+ $_log = new Logger (\r
+ name => $suiteName,\r
+ path => LOGBASE,\r
+ append => "yes",\r
+ );\r
+\r
+ $_log->log ("$FindBin::Script Version " . VERSION_NBR);\r
+\r
+ ($_east->{suiteID}) = $_rantestdb->startSuiterun ($suiteName);\r
+\r
+ verbose BOLD MAGENTA "Suite\t" . RESET GREEN $suiteName . RESET;\r
+\r
+ $_log->log ("Suite\t$suiteName");\r
+\r
+ foreach (@lines) {\r
+ $i++;\r
+ next if /(^#|^$)/;\r
+\r
+ my @components = split;\r
+\r
+\r
+ my $viewPath = "$ENV{MNT_DIR}/snapshot_views/$userdir/$_opts{eastview}/vobs/simdev/test/";\r
+ my $testFile = "$viewPath/" . shift @components;\r
+\r
+ unless (-e $testFile) {\r
+ error "Unable to find test file $testFile (Line: $i)";\r
+ next;\r
+ } # unless\r
+\r
+ unless (/\.test/) {\r
+ error "Not a .test file: $testFile (Line: $i)";\r
+ next;\r
+ } # unless\r
+\r
+ # Get test options. It seems GetOptions doesn't support taking\r
+ # input from anything but @ARGV so we'll have to save a copy and\r
+ # restore it.\r
+ my @savedOptions = @ARGV;\r
+\r
+ @ARGV = split;\r
+\r
+ my %suiteOptions;\r
+\r
+ my $status = GetOptions (\r
+ \%suiteOptions,\r
+ "eastview=s",\r
+ "tm500view=s",\r
+ "nmsview=s",\r
+ "type=s",\r
+ "class=s",\r
+ "unit=s",\r
+ "test=s",\r
+ "file=s",\r
+ "rfr=s",\r
+ "regression",\r
+ ) || usage "Invalid parameter";\r
+\r
+ # Restore @ARGV\r
+ @ARGV = @savedOptions;\r
+\r
+ # Restore the original command line options:\r
+ %_opts = %_cmdline_opts;\r
+\r
+ # Merge in %suiteOptions: Set into %_opts only if that key doesn't\r
+ # exist already. This allows command line options to override\r
+ # options specified on the .test line in the .suite file\r
+ foreach (keys %suiteOptions) {\r
+ $_opts{$_} = $suiteOptions{$_} unless $_opts{$_};\r
+ } # foreach\r
+\r
+ $suiteFailures += runTestFile $testFile;\r
+\r
+ # Need to disconnect $_east to shut down the previous run\r
+ my $savedSuiteID = $_east->{suiteID};\r
+\r
+ $_east->disconnect;\r
+\r
+ # Collect logfiles\r
+ $_east->collectLogFiles;\r
+\r
+ if ($suiteFailures == 0 and $_opts{val}) {\r
+ my @validations = ref $_opts{val} eq "ARRAY"\r
+ ? @{$_opts{val}}\r
+ : ($_opts{val});\r
+\r
+ $suiteFailures += runValidations @validations;\r
+ } # if\r
+\r
+ $_east = new Nethawk::East;\r
+\r
+ $_east->{suiteID} = $savedSuiteID;\r
+\r
+ $_connected = 0;\r
+ } # foreach\r
+\r
+ # Log suite results\r
+ verbose BOLD MAGENTA "Suite\t" . RESET GREEN $suiteName\r
+ . (($suiteFailures == 0) ? GREEN " Success" : RED " Failure") . RESET;\r
+\r
+ $_log->log ("Suite\t$suiteName" . ($suiteFailures == 0) ? "Success" : "Failure");\r
+\r
+ my $errMsg;\r
+\r
+ ($_east->{suiteID}, $errMsg) = $_rantestdb->endSuiterun (\r
+ name => fileparse ($file, ".suite"),\r
+ start => UnixDatetime2SQLDatetime (scalar (localtime ($suiteStartTime))),\r
+ result => $suiteFailures ? "Failure" : "Success",\r
+ );\r
+\r
+ error $errMsg if $_east->{suiteID} != 0;\r
+\r
+ return $suiteFailures;\r
+} # runSuiteFile\r
+\r
+sub runFile ($) {\r
+ my ($file) = @_;\r
+\r
+ unless (-e $file) {\r
+ error "File $file does not exist";\r
+ return;\r
+ } # if\r
+\r
+ $_term->AddHistory ("source $file")\r
+ unless $_debugging or !-t STDIN;\r
+\r
+ $SIG{INT} = \&interrupted;\r
+\r
+ # Determine file type\r
+ if ($file =~ /\.test$/) {\r
+ runTestFile $file;\r
+ } elsif ($file =~ /\.suite$/) {\r
+ return runSuiteFile $file\r
+ } else {\r
+ error "File $file is not a .suite or .test file", 1;\r
+ } # if\r
+} # runFile\r
+\r
+$SIG{TERM} =\r
+$SIG{QUIT} = \&saveHistory;\r
+\r
+# Set a more friendly umask\r
+umask 002;\r
+\r
+GetOptions (\r
+ \%_opts,\r
+ verbose => sub { set_verbose },\r
+ debug => sub { set_debug },\r
+ usage => sub { usage; exit 0 },\r
+ "eastview:s",\r
+ "view:s",\r
+ "tm500view:s",\r
+ "nmsview:s",\r
+ "type:s",\r
+ "class:s",\r
+ "unit:s",\r
+ "test:s",\r
+ "file:s",\r
+ "rfr:s",\r
+ "checkin_on_error",\r
+ "feature:s",\r
+ "secure!",\r
+ "regression",\r
+) || usage "Invalid parameter";\r
+\r
+# Special case elock command\r
+if (scalar @ARGV > 0 and $ARGV[0] =~ /elock/i) {\r
+ eLock ($ARGV[1]);\r
+ exit;\r
+} # if\r
+\r
+usage "Extraneous parameters: " . join " ", @ARGV if scalar @ARGV > 0;\r
+\r
+# Check for mutually exclusive options\r
+if ($_opts{file}) {\r
+ my $suffix = $ENV{RANTEST_FILE} ? "\nNote: The environment variable RANTEST_FILE is set" : "";\r
+\r
+ if ($_opts{test}) {\r
+ $suffix .= $ENV{RANTEST_TEST} ? "\nNote: The environment variable RANTEST_TEST is set" : "";\r
+ } elsif ($_opts{class}) {\r
+ $suffix .= $ENV{RANTEST_CLASS} ? "\nNote: The environment variable RANTEST_CLASS is set" : "";\r
+ } # if\r
+\r
+ usage "<test> and <file> are mutually exclusive$suffix" if $_opts{test};\r
+ usage "<class> and <file> are mutually exclusive$suffix" if $_opts{class};\r
+} # if\r
+\r
+if ($_opts{eastview}) {\r
+ my $suffix = $ENV{RANTEST_VIEW} ? "\nNote: The environment variable RANTEST_VIEW is set" : "";\r
+ $suffix .= $ENV{RANTEST_EASTVIEW} ? "\nNote: The environment variable RANTEST_EASTVIEW is set" : "";\r
+\r
+ usage "<eastview> and <view> are mutually exclusive$suffix" if $_opts{view};\r
+} # if\r
+\r
+usage "-rfr and -regression are mutually exclusive" if $_opts{rfr} && $_opts{regression};\r
+\r
+# Make "view" an alias for "eastview" but only if there is no eastview\r
+# already defined\r
+$_opts{eastview} = delete $_opts{view} if $_opts{view} && !$_opts{eastview};\r
+\r
+# Check for required parameters\r
+usage "-view or -eastview specified but no view given"\r
+ if defined $_opts{view} and $_opts{view} eq "";\r
+usage "-tm500view specified but no view given"\r
+ if defined $_opts{tm500view} and $_opts{tm500view} eq "";\r
+usage "-nmsview specified but no view given"\r
+ if defined $_opts{nmsview} and $_opts{nmsview} eq "";\r
+usage "-type specified but no type given"\r
+ if defined $_opts{type} and $_opts{type} eq "";\r
+usage "-class specified but no class given"\r
+ if defined $_opts{class} and $_opts{class} eq "";\r
+usage "-unit specified but no unit # given"\r
+ if defined $_opts{unit} and $_opts{unit} eq "";\r
+usage "-test specified but no test given"\r
+ if defined $_opts{test} and $_opts{test} eq "";\r
+usage "-file specified but no file given"\r
+ if defined $_opts{file} and $_opts{file} eq "";\r
+usage "-rfr specified but no testcase ID given"\r
+ if defined $_opts{rfr} and $_opts{rfr} eq "";\r
+\r
+# Save these original command line options. If we are in suite mode\r
+# then we must allow the individual .test options override these\r
+# original command line options. If -rfr is on then we are by default\r
+# verbose\r
+%_cmdline_opts = %_opts;\r
+\r
+set_verbose if $_opts{rfr};\r
+\r
+# Instantiate a new East object\r
+$_east = new Nethawk::East;\r
+\r
+# Set testcase ID into East object\r
+$_east->setTestCaseID ($_opts{rfr});\r
+\r
+$_debugging = get_debug;\r
+\r
+# If we are debugging (and thus STDIN gets confused between the debugger's\r
+# STDIN and rantest's STDIN) or if we don't have a tty (-t - we would not \r
+# have a tty if run from say cron(1m), then do not perform these actions\r
+# on $_term.\r
+unless ($_debugging or !-t STDIN) {\r
+ $_term = new Term::ReadLine $FindBin::Script;\r
+\r
+ $_term->{AUTORESET} = 1;\r
+\r
+ # Restore previous history, if any\r
+ $_term->ReadHistory (HISTORY_FILE);\r
+} # unless\r
+\r
+# Announce ourselves\r
+verbose DESC . RESET;\r
+\r
+# Open Rantest Database\r
+$_rantestdb = new RantestDB ("pswit", "!qaz2w3e");\r
+\r
+if ($_opts{test}) {\r
+ $SIG{INT} = \&interrupted;\r
+\r
+ $_stats{Run}++;\r
+\r
+ # Separate off options\r
+ my $testName = $_opts{test};\r
+\r
+ if ($_opts{test} =~ /(\S+)\s+\-.*$/) {\r
+ $testName = $1;\r
+ } # if\r
+\r
+ $testName = fileparse ($testName, "\.profile");\r
+\r
+ $_east->setSaveTo ("$testName/$_opts{type}$_opts{unit}/" . YMDHMS);\r
+\r
+ eval { mkpath LOGBASE . "/" . $_east->getSaveTo };\r
+\r
+ return (1, $@) if $@;\r
+\r
+ chmod 0775, LOGBASE . "/" . $_east->getSaveTo;\r
+\r
+ $_log = new Logger (\r
+ name => $testName,\r
+ path => LOGBASE . "/" . $_east->getSaveTo,\r
+ append => "yes",\r
+ );\r
+\r
+ $_log->log ("$FindBin::Script Version " . VERSION_NBR . "\nUsing view: $_opts{eastview}");\r
+\r
+ executeTestStep;\r
+\r
+ $_term->AddHistory ("$_opts{class} $_opts{test}") unless $_debugging && -t STDIN;\r
+\r
+ # Disconnect from EAST\r
+ $_east->disconnect;\r
+\r
+ # Collect logfiles\r
+ $_east->collectLogFiles;\r
+} elsif ($_opts{file}) {\r
+ runFile $_opts{file};\r
+} else {\r
+ $_east->setSaveTo ("rantest/" . YMDHMS);\r
+\r
+ eval { mkpath LOGBASE . "/" . $_east->getSaveTo };\r
+\r
+ return (1, $@) if $@;\r
+\r
+ chmod 0777, LOGBASE . "/" . $_east->getSaveTo;\r
+\r
+ $_log = new Logger (\r
+ path => LOGBASE . "/" . $_east->getSaveTo,\r
+ append => "yes"\r
+ );\r
+\r
+ display DESC if !get_verbose;\r
+\r
+ if ($_opts{eastview}) {\r
+ $_log->log ("$FindBin::Script Version " . VERSION_NBR . "\nUsing view: $_opts{eastview}");\r
+ } else {\r
+ $_log->log ("$FindBin::Script Version " . VERSION_NBR);\r
+ } # if\r
+\r
+ set_verbose;\r
+\r
+ while () {\r
+ my $cmd;\r
+\r
+ unless ($_debugging) {\r
+ $cmd = $_term->readline (PROMPT . RESET);\r
+ } else {\r
+ display_nolf PROMPT . RESET;\r
+\r
+ $cmd = <STDIN>;\r
+ } # if\r
+\r
+ # Handle Control-d\r
+ unless (defined $cmd) {\r
+ display "";\r
+ saveHistory;\r
+ exit 0;\r
+ } # if\r
+\r
+ chomp $cmd;\r
+\r
+ next if $cmd eq "";\r
+\r
+ if ($cmd =~ /exit|quit/i) {\r
+ $_term->remove_history ($_term->where_history);\r
+ saveHistory;\r
+ exit 0;\r
+ } # if\r
+\r
+ if ($cmd =~ /^elock/i) {\r
+ if ($cmd =~ /^elock\s+(\w+)/i) {\r
+ eLock $1;\r
+ } else {\r
+ eLock;\r
+ } # if\r
+\r
+ next;\r
+ } # if\r
+\r
+ my @tokens = split /\s+/, $cmd;\r
+\r
+ $_opts{class} = shift @tokens;\r
+ $_opts{test} = join " ", @tokens;\r
+\r
+ $cmd = lc $_opts{class};\r
+\r
+ if ($cmd eq "help") {\r
+ help;\r
+ $_term->remove_history ($_term->where_history) unless $_debugging;\r
+ next;\r
+ } elsif ($cmd eq "usage") {\r
+ usage;\r
+ $_term->remove_history ($_term->where_history) unless $_debugging;\r
+ next;\r
+ } elsif ($cmd eq "version") {\r
+ display DESC;\r
+ $_term->remove_history ($_term->where_history) unless $_debugging;\r
+ next;\r
+ } elsif ($cmd eq "source") {\r
+ runFile $tokens[0];\r
+ } elsif ($cmd eq "set") {\r
+ if ($_opts{test} =~ /\s*(\w+)\s*=\s*(.+)/) {\r
+ my $optionName = $1;\r
+ my $value = $2;\r
+\r
+ # Remove quotes, if any. Note no check for balancing.\r
+ $value =~ s/[\"\']//g;\r
+\r
+ # Set option\r
+ $_opts{$optionName} = $value;\r
+ } # if\r
+ } elsif ($cmd eq "get") {\r
+ if ($_opts{$tokens[0]}) {\r
+ display "$tokens[0] = $_opts{$tokens[0]}";\r
+ } else {\r
+ display "$tokens[0] is not set";\r
+ } # if\r
+ } else {\r
+ $_stats{Run}++;\r
+ $_opts{class} = lc $_opts{class};\r
+\r
+ if ( $_opts{class} eq "manual" ) {\r
+ $_opts{test} = " ";\r
+ } # if\r
+\r
+ executeTestStep;\r
+ } # if\r
+ } # while\r
+\r
+ # Disconnect from EAST\r
+ $_east->disconnect;\r
+\r
+ # Assign 'Failed' and 'Timedout' 0 if they are not initialized\r
+ $_stats{Failed} ||= 0;\r
+ $_stats{Timedout} ||= 0;\r
+\r
+ my $testErrors = $_stats{Failed} + $_stats{Timedout};\r
+\r
+ # Collect log files and check them in based on checkin_on_error option\r
+ $_east->collectLogFiles($testErrors, $_opts{checkin_on_error});\r
+\r
+} # if\r
+\r
+saveHistory;\r
+displaySummary;\r
+\r
+# The combination of Failed and Timedout represents our exit\r
+# status. If either or both of them is defined then they will be\r
+# non-zero and thus we exit with a non-zero status. Only if both are\r
+# undefined, and thus set to 0 by the code below, will we exit 0.\r
+$_stats{Failed} = 0 unless $_stats{Failed};\r
+$_stats{Timedout} = 0 unless $_stats{Timedout};\r
+\r
+# Now exit with the correct status\r
+exit ($_stats{Failed} + $_stats{Timedout});\r