2 ##############################################################################
\r
6 # Description: This script is a test driver script capable of running tests
\r
7 # individually or from a file. There are many facilities for
\r
8 # specifying input and options to this program - see the usage
\r
9 # and help subroutines for clues. Basically you can run rantest
\r
10 # by itself and it will interactively prompt you for what to do
\r
11 # and what information or options it needs. Additionally you can
\r
12 # set options in the environment such as RANTEST_VIEW or
\r
13 # RANTEST_UNIT to serve as defaults. Or you can use -view or
\r
14 # -type, for example, at the command line to supply such parms.
\r
15 # If rantest still doesn't have all it needs it will prompts.
\r
17 # Note that options and/or test cases can be specified in config
\r
18 # files specified by RANTEST_FILE or -file. Embedded in the
\r
19 # config file can be additional options in the form of:
\r
21 # b2_l3_rnc_irt_001.test:
\r
22 # ----------------------
\r
23 # view: p6258c_SIMCQ00000100_intview
\r
26 # exec: tc CN_SIM/TC_CN_Simulation_RANAP_Setup.profile -timeout 60
\r
27 # exec: tc CN_SIM/TC_CN_Simulation.profile -timeout -1 -pause 5
\r
28 # exec: tc RBS_SIM/TC_RBS_Sim_Cell_Setup.profile -timeout 180
\r
29 # exec: tc l3_rnc/irt/TC_b2_l3_rnc_irt_001.profile -timeout 180
\r
31 # Above we've set view, type and unit for the test run
\r
32 # and defined test steps of tc
\r
33 # CN_SIM/TC_CN_Simulation_RANAP_Setup.profile,
\r
34 # CN_SIM/TC_CN_Simulation.profile,
\r
35 # RBS_SIM/TC_RBS_Sim_Cell_Setup.profile and
\r
36 # l3_rnc/irt/TC_b2_l3_rnc_irt_001.profile
\r
38 # Note that you can specify optional additional
\r
39 # parameters after the test name like -timeout and a
\r
40 # bunch of other parameters as described in the "Command
\r
41 # Line in East" document.
\r
43 # This would be run as so:
\r
45 # $ rantest -file b2_l3_rnc_irt_001.test
\r
47 # Suite files, those ending in .suite, are different
\r
48 # from .test files in that they merely contain a list of
\r
49 # .test files (relative to <view>/vobs/simdev/test) to
\r
50 # execute for this suite. Note that parameters can be
\r
51 # added after the suite file name:
\r
56 # b2_l3_rnc_irt_007.test -unit 4
\r
57 # b2_l3_rnc_irt_014.test
\r
60 # b2_l3_rnc_sch_001.test -view official_view
\r
61 # b2_l3_rnc_sch_003a.test
\r
63 # Author: Andrew@ClearSCM.com
\r
65 # Copyright (c) 2008, 2009 General Dynamics
\r
67 # All rights reserved except as subject to DFARS 252.227-7014 of contract
\r
68 # number CP02H8901N issued under prime contract N00039-04-C-2009.
\r
70 # Warning: This document contains technical data whose export is restricted
\r
71 # by the Arms Export Control Act (Title 22, U.S.C., Sec 2751, et seq.) or the
\r
72 # Export Administration Act of 1979, as amended, Title, 50, U.S.C., App. 2401
\r
73 # et seq. Violations of these export laws are subject to severe criminal
\r
74 # penalties. Disseminate in accordance with provisions of DoD Directive
\r
77 ##############################################################################
\r
82 use File::Glob ':glob';
\r
86 use Net::Domain qw (hostname);
\r
87 use Term::ANSIColor qw (:constants);
\r
89 use Term::ReadLine::Gnu;
\r
91 # Use the SDE Tools libraries. Sorry for this long path. I didn't come
\r
93 #use lib "/cleartrig/ent/SNSD/muos/ccadm_tools/vobs/ranccadm/scripts/lib";
\r
94 use lib "$FindBin::Bin/../lib";
\r
102 error "$FindBin::Script only runs on seast1", 1
\r
103 unless hostname eq "seast1";
\r
105 use lib "$FindBin::Bin/../lib";
\r
108 use GD::Nethawk::East;
\r
110 use constant VERSION_NBR=> "1.2.5";
\r
111 use constant VERSION => BOLD GREEN VERSION_NBR;
\r
112 use constant PROMPT => BOLD YELLOW "$FindBin::Script>";
\r
113 use constant DESC => BOLD RED "$FindBin::Script",
\r
114 RESET "Version", VERSION
\r
116 . BOLD CYAN "RAN T"
\r
119 . RESET "xecution of "
\r
125 use constant HISTORY_FILE => "$ENV{HOME}/.rantest_hist";
\r
126 use constant LOGBASE => "$ENV{MNT_DIR}/testlogs";
\r
128 ############################################################################
\r
130 ############################################################################
\r
132 my $_connected = 0;
\r
138 my $_validationNbr = 0;
\r
142 my %_executionResults;
\r
144 my (%_opts, %_cmdline_opts);
\r
146 # Seed opts from the environment.
\r
147 $_opts{eastview} = $ENV{RANTEST_EASTVIEW} if $ENV{RANTEST_EASTVIEW};
\r
148 $_opts{eastview} = $ENV{RANTEST_VIEW} if $ENV{RANTEST_VIEW} && !$_opts{eastview};
\r
149 $_opts{tm500view} = $ENV{RANTEST_TM500VIEW} if $ENV{RANTEST_TM500VIEW};
\r
150 $_opts{nmsview} = $ENV{RANTEST_NMSVIEW} if $ENV{RANTEST_NMSVIEW};
\r
151 $_opts{type} = $ENV{RANTEST_TYPE} if $ENV{RANTEST_TYPE};
\r
152 $_opts{class} = $ENV{RANTEST_CLASS} if $ENV{RANTEST_CLASS};
\r
153 $_opts{unit} = $ENV{RANTEST_UNIT} if $ENV{RANTEST_UNIT};
\r
154 $_opts{test} = $ENV{RANTEST_TEST} if $ENV{RANTEST_TEST};
\r
155 $_opts{file} = $ENV{RANTEST_FILE} if $ENV{RANTEST_FILE};
\r
156 $_opts{rfr} = $ENV{RANTEST_RFR} if $ENV{RANTEST_RFR};
\r
157 $_opts{checkin_on_error}= $ENV{CHECKIN_ON_ERROR} if $ENV{CHECKIN_ON_ERROR};
\r
158 $_opts{feature} = $ENV{RANTEST_FEATURE} if $ENV{RANTEST_FEATURE};
\r
159 $_opts{regression} = $ENV{RANTEST_REGRESSION} if $ENV{RANTEST_REGRESSION};
\r
160 $_opts{secure} = $ENV{RANTEST_SECURE} if $ENV{RANTEST_SECURE};
\r
162 # Explicitly default secure to either $ENV{RANTEST_SECURE}, if defined, otherwise 1
\r
163 $_opts{secure} = $ENV{RANTEST_SECURE} ? $ENV{RANTEST_SECURE} : 1;
\r
168 my $usage = "ERROR: $msg\n\n" if $msg;
\r
171 Usage: $FindBin::Script\t[-us|age] [-v|erbose] [-d|ebug]
\r
172 [-view|-eastview <view>] [-tm500view <view>] [-nmsview <view>]
\r
173 [-type <type>] [-class <class>] [-rfr <testcase ID>] [-checkin_on_error]
\r
174 [-unit <unit #>] [-test <test>] [-file <file>] [-feature <feature>]
\r
179 -us|age: Display usage
\r
180 -ve|rbose: Turn on verbose mode
\r
181 -d|ebug: Turn on debug mode
\r
182 -[ea|st]view <tag> View tag to run test(s) under
\r
183 -tm|500view <tag> TM 500 view to set into the environment for
\r
185 -nm|sview <tag> NMS view to set into the environment for
\r
187 -ty|pe <type> Type of unit to test (i.e. rbs | rnc)
\r
188 -c|lass <class> Class of test (i.e. one of the following):
\r
191 Pool RegressionLoadRunner
\r
192 TC RegressionRunner
\r
193 TS RegressionTSRunner
\r
196 -un|it <unit #> Unit number to test on
\r
197 -te|st <test> Name of test (Optional: If not specific you will
\r
198 be prompted for test case names)
\r
199 -f|ile <file> File containing a list of tests to execute (Optional:
\r
200 Contains a file of test classes and names to test)
\r
201 -rfr <testcase ID> Run for record: ID is the test case ID to store
\r
203 -checkin_on_error Checks in rfr log files even if a test(s) fails
\r
204 -regression Run regression tests. These tests will log there
\r
206 -feature <feature> If specified then FEATURE will be set into the
\r
207 environment on the blade before calling
\r
209 -[no]s|ecure Indicates whether or not to secure the node before
\r
210 attempting to connect to it. (Default: secure).
\r
212 NOTE: Set ANSI_COLORS_DISABLED to turn off colors
\r
214 If you specify -file you cannot specify -test nor -class. -class'es are
\r
217 Additionally, options above can be specified in the environment by
\r
218 preceeding the environment variable with \"RANTEST_\". For example,
\r
220 \$ export RANTEST_TYPE=rbs
\r
221 \$ export RANTEST_UNIT=2
\r
224 Also such options can be specified in the -file:
\r
228 ts ts1.profile -timeout -1 -pause 5
\r
229 ts ts2.profile -displaylevel 3
\r
230 ts ts3.profile -activecalls 10
\r
232 Options after test profile name are passed directory to EAST's command
\r
233 line. The exceptions are -timeout and -pause:
\r
235 -timeout <n> Specifies the timeout for this test's execution.
\r
236 If negative the test will be placed in the
\r
237 background. No result is recovered from
\r
238 background tests nor are any logfiles analysed
\r
239 or stored. If positive then this sets the
\r
240 timeout period for this test in seconds.
\r
242 -pause <n> Used in conjunction with -timeout. If test is
\r
243 backgrounded then $FindBin::Script will wait
\r
244 pause seconds before returning control from
\r
245 this test. This allows the backgrounded test
\r
248 -name <name> Names a test. Used in conditional execution.
\r
250 -if (<name> <status>) Run this test if the named test returned <status>
\r
251 where <status> is one of
\r
257 . Failed to execute
\r
259 . Failed to rendezvous
\r
261 Note: Required options not supplied will be prompted for.
\r
264 my $pager = $ENV{PAGER} ? $ENV{PAGER} : "more";
\r
266 system "echo \"$usage\" | $pager";
\r
272 display DESC . RESET;
\r
275 Valid commands are:
\r
278 usage: Displays command line usage
\r
279 version: Displays version of $FindBin::Script
\r
280 exit|quit: Exits $FindBin::Script
\r
281 source <file> Execute the contents of <file>
\r
282 set <option>=<value> Set <option> to <value>
\r
283 get <option> Displays <option> (if set)
\r
284 elock <pattern> Display elock status (default all units)
\r
288 load <test profile> <options> Run a test case by profile (LoadTCRunner)
\r
289 pool <test profile> <options> Run a regression load (RegressionLoadRunner)
\r
290 tc <test profile> <options> Run a regression (RegressionRunner)
\r
291 ts <test profile> <options> Run a regression test suite (RegressionTSRunner)
\r
294 Note: ReadLine is supported thus you can edit previous commands.
\r
304 while (!$value or $value eq "") {
\r
305 display_nolf BOLD YELLOW . "$FindBin::Script needs the following parameter - $prompt" . RESET;
\r
318 my ($status, @locks) = Execute "ls $ENV{MNT_DIR}/$ENV{EAST_REL}/DUT/*/desktop.lock 2> /dev/null";
\r
325 if (/.*DUT\/(\w+)\/desktop/) {
\r
328 next if $unit && $unit_found !~ /$unit/i;
\r
331 my @fields = split /\//, $_;
\r
332 my $uid = (stat $_)[4];
\r
333 my $mtime = (stat $_)[9];
\r
334 my $userid = (getpwuid ($uid))[0];
\r
335 my $name = (getpwuid ($uid))[6];
\r
337 display BOLD CYAN "$fields[5]\t"
\r
338 . RESET "locked since "
\r
339 . BOLD YELLOW localtime ((stat $_)[9])
\r
348 sub displaySummary () {
\r
349 my $msg = "Summary:";
\r
351 foreach (sort keys %_stats) {
\r
352 $msg .= " $_stats{$_} $_";
\r
355 $_log->msg ($msg) if $_log;
\r
358 sub announceTestrun ($) {
\r
359 my ($testname) = @_;
\r
361 my $user = $ENV{USER} ? $ENV{USER}
\r
362 : $ENV{LOGNAME} ? $ENV{LOGNAME}
\r
364 my $timestamp = YMDHMS;
\r
368 verbose BOLD YELLOW "Test #" . $_testNbr . "\t"
\r
369 . RESET CYAN $testname
\r
370 . RESET " run on $timestamp by "
\r
373 . MAGENTA $_opts{type}
\r
375 . CYAN $_opts{unit}
\r
378 $_log->log ("Test #$_testNbr $testname run on: $timestamp by $user on $_opts{type} unit $_opts{unit}");
\r
379 } # announceTestrun
\r
382 $_term->WriteHistory (HISTORY_FILE) if $_term;
\r
385 sub executeTestStep () {
\r
386 if (!$_connected) {
\r
387 # Get required parameters if not specified in the command line or environment
\r
388 $_opts{eastview} = getParm "View:" unless $_opts{eastview};
\r
389 $_opts{type} = getParm "Type:" unless $_opts{type};
\r
390 $_opts{class} = getParm "Class:" unless $_opts{class};
\r
391 $_opts{unit} = getParm "Unit:" unless $_opts{unit};
\r
394 my $msg = $_east->connect (
\r
405 $_log->err ("Unable to connect to EAST\n$msg");
\r
406 verbose RED "Skipping renaming test steps" . RESET;
\r
414 my ($status, $msg) = Nethawk::East::validTestType ($_opts{class});
\r
416 if ($status != 0) {
\r
421 if (!$_opts{test}) {
\r
422 # Manual tests only have classes
\r
423 unless ($_opts{class} eq 'manual') {
\r
424 $_log->err ("No test specified");
\r
429 $_east->setCollectLogFiles (1);
\r
431 verbose_nolf $_stats{Run} . ": " . CYAN "$_opts{class}\t" . BOLD YELLOW $_opts{test} . RESET;
\r
433 my $testStepResult;
\r
435 my $startTime = time;
\r
436 my $stepName = "Unknown";
\r
438 if ($_opts{test} =~ /(.*)\.profile/) {
\r
440 } elsif ($_opts{class} eq "manual") {
\r
441 $stepName = "Manual";
\r
442 } elsif ($_opts{class} eq "shell") {
\r
443 $stepName = $_opts{test};
\r
444 } elsif ($_opts{test} =~ /^rantvl/) {
\r
445 $stepName = $_opts{test};
\r
447 $_east->setRantvlStartTime (time);
\r
450 my ($stepID, $errMsg) = $_rantestdb->startSteprun ($stepName);
\r
452 ($status, $testStepResult) = $_east->exec (\%_opts, \%_executionResults);
\r
454 # Collect any extended logs
\r
455 if ((!defined $_opts{timeout} or $_opts{timeout} > 0) and
\r
456 ($_east->{class} eq "load" or
\r
457 $_east->{class} eq "tc" or
\r
458 $_east->{class} eq "ts" or
\r
459 $_east->{class} eq "pool")) {
\r
460 $_east->collectExtendedLogFiles;
\r
463 my $endTime = time;
\r
465 if ($status == 0) {
\r
466 if ($testStepResult eq "Success") {
\r
467 verbose GREEN " $testStepResult" . RESET;
\r
469 } elsif ($testStepResult eq "In progress" or
\r
470 $testStepResult eq "Logging started") {
\r
471 verbose MAGENTA " $testStepResult" . RESET;
\r
472 $_stats{Concurrent}++;
\r
473 } elsif ($testStepResult eq "Rendezvous") {
\r
474 verbose BOLD . " $testStepResult" . RESET;
\r
475 $_stats{Rendezvous}++;
\r
477 verbose RED " $testStepResult" . RESET;
\r
482 if ($testStepResult eq "Skipped") {
\r
483 verbose BOLD . " $testStepResult" . RESET;
\r
484 $_stats{Skipped}++;
\r
485 } elsif ($testStepResult eq "Timed out") {
\r
486 verbose CYAN " $testStepResult" . RESET;
\r
488 $_stats{Timedout}++;
\r
490 verbose RED " $testStepResult" . RESET;
\r
496 # Log test step result
\r
497 $_log->log ("$_stats{Run}: $_opts{class}\t$_opts{test} $testStepResult");
\r
499 my ($dbErrNbr, $dbErrMsg) = $_rantestdb->endSteprun (
\r
500 runID => $_east->{runID},
\r
502 start => UnixDatetime2SQLDatetime (scalar (localtime ($startTime))),
\r
503 end => UnixDatetime2SQLDatetime (scalar (localtime ($endTime))),
\r
504 result => $testStepResult,
\r
507 error $dbErrMsg if $dbErrNbr != 0;
\r
510 } # executeTestStep
\r
513 error "Test timed out ($_opts{testtimeout}) seconds passed)";
\r
515 $_east->disconnect;
\r
518 $_east->collectLogFiles;
\r
524 display BLUE "\nInterrupted" . RESET;
\r
529 CYAN . BOLD "C" . RESET CYAN "ontinue" . RESET . " or " .
\r
530 MAGENTA . BOLD "A" . RESET MAGENTA "bort run" . RESET . " (" .
\r
531 CYAN . BOLD "C" . RESET "/" .
\r
532 MAGENTA . BOLD "a" . RESET ")?";
\r
534 ReadMode ("cbreak");
\r
535 my $answer = ReadKey (0);
\r
536 ReadMode ("normal");
\r
538 if ($answer eq "\n") {
\r
544 $answer = lc $answer;
\r
546 if ($answer eq "c") {
\r
547 display "Continuing...";
\r
548 } elsif ($answer eq "a") {
\r
549 display RED "Aborting run" . RESET;
\r
550 $_east->setCollectLogFiles (0);
\r
556 sub interpolate ($) {
\r
559 # Perform psuedo variable interpolation. The following psuedo
\r
560 # variables are supported:
\r
562 # view: Absolute path to your view
\r
563 my $view = "$ENV{MNT_DIR}/snapshot_views/$_east->{userdir}/$_east->{view}";
\r
564 my $simdev = "$view/vobs/simdev";
\r
566 # msgdefs: Absolute path to msgdefs
\r
567 my $msgdefs = "$simdev/msgdefs";
\r
569 # validation: Absolute path to validation
\r
570 my $validation = "$simdev/validation";
\r
572 # logpath: Absolute path into the "testlogs" area where
\r
573 # logfiles are written
\r
574 my $logpath = LOGBASE . "/" . $_east->getSaveTo;
\r
576 while ($str =~ /\$/) {
\r
579 if ($str =~ /\$(\w+)/) {
\r
582 } elsif ($str =~ /\$(\[.+?\])\[(.+?)\]/) {
\r
583 # A $[fileset][slice] reference
\r
586 } elsif ($str =~ /\$(\[.+?\])/) {
\r
587 # A $[fileset] reference
\r
591 if ($var eq "logpath") {
\r
592 $str =~ s/\$$var/$logpath/;
\r
593 } elsif ($var eq "msgdefs") {
\r
594 $str =~ s/\$$var/$msgdefs/;
\r
595 } elsif ($var eq "validation") {
\r
596 $str =~ s/\$$var/$validation/;
\r
597 } elsif ($var eq "view") {
\r
598 $str =~ s/\$$var/$view/;
\r
599 } elsif ($var =~ /\[(.+)\]/) {
\r
602 my @fileset = glob $fileset;
\r
605 if (defined $slice) {
\r
606 $fileset = quotemeta $fileset;
\r
608 # Here we handle a slice, but if the slice is of the form x..y
\r
609 # then we need to handled it differently
\r
610 if ($slice =~ /(\d+)\.\.(\d+)/) {
\r
611 # Need to turn off warnings for this next construct of
\r
612 # @array[$1..$2]. Otherwise it complains. If we use
\r
613 # $array[$1..$2] then it doesn't work! Also take on the
\r
614 # base fileset defined above.
\r
617 $2 = $#fileset if $2 > $#fileset;
\r
620 $list = join ",", @fileset[$1..$2];
\r
623 # Not a slice really but an array reference
\r
624 $list = "$fileset[$slice]";
\r
627 $str =~ s/\$\[$fileset\]\[$slice\]/$list/;
\r
629 $list = join ",", @fileset;
\r
630 $str =~ s/\$\[$fileset\]/$list/;
\r
633 if (defined $slice) {
\r
634 $str =~ s/\$\[$fileset\]\[$slice\]//;
\r
636 $str =~ s/\$\[$fileset\]//;
\r
639 error "Unknown variable ($var) encountered in val line:\n$str", 1;
\r
646 sub runValidation ($$) {
\r
647 my ($cmd, $logfile) = @_;
\r
649 my $origCmd = $cmd;
\r
651 my ($stepID, $errMsg);
\r
653 ($stepID, $errMsg) = $_rantestdb->startSteprun ($origCmd);
\r
655 if ($stepID == 0) {
\r
656 error "Unable to startSteprun\n$errMsg";
\r
660 my $startTime = time;
\r
662 $cmd = interpolate ($cmd);
\r
664 my ($status, @lines) = Execute ("$cmd >> $logfile 2>&1");
\r
668 my $endTime = time;
\r
670 my ($dbErrNbr, $dbErrMsg) = $_rantestdb->endSteprun (
\r
671 runID => $_east->{runID},
\r
673 start => UnixDatetime2SQLDatetime (scalar (localtime ($startTime))),
\r
674 end => UnixDatetime2SQLDatetime (scalar (localtime ($endTime))),
\r
675 result => $status ? "Failure" : "Success",
\r
678 error $dbErrMsg if $dbErrNbr != 0;
\r
680 # Output lines to stdout
\r
682 verbose "$_\n" foreach (ReadFile $logfile);
\r
684 verbose "Unable to read $logfile";
\r
690 verbose BOLD YELLOW . "Test #$_testNbr validation #$_validationNbr \t" . RESET CYAN $origCmd
\r
691 . (($status == 0) ? GREEN " Success" : RED " Failure") . RESET;
\r
693 $_log->log ("Test #$_testNbr validation #$_validationNbr\t$origCmd " . (($status == 0) ? "Success" : "Failure"));
\r
698 sub runValidations (@) {
\r
699 my @validations = @_;
\r
701 my $validationErrs = 0;
\r
703 # Make Validation log directory
\r
704 my $validationDir = LOGBASE . "/" . $_east->getSaveTo . "/Validations";
\r
706 eval { mkpath $validationDir };
\r
708 error "Unable to create Validation directory - $validationDir\n$@", 1 if $@;
\r
710 chmod 0775, $validationDir;
\r
712 my $viewPath = "$ENV{MNT_DIR}/snapshot_views/$_east->{userdir}/$_east->{view}";
\r
713 my $vobPath = "vobs/simdev";
\r
715 foreach (@validations) {
\r
716 my @tokens = split;
\r
717 my $outfile = $tokens[0] . ".log";
\r
719 $validationErrs += runValidation $_, "$validationDir/$outfile";
\r
722 $_stats{Failed} += $validationErrs;
\r
724 return $validationErrs;
\r
727 sub runTestFile ($) {
\r
730 my $testName = fileparse $file, ".test";
\r
732 my $testID = $_rantestdb->startTest ($testName);
\r
734 my %fileopts = GetConfig ($file);
\r
736 # GetConfig leaves keys %fileopts as case sensitive but we want them
\r
737 # case insentive so fix that here.
\r
738 foreach (keys (%fileopts)) {
\r
741 # Make "view" an alias for "eastview" but only if there is no
\r
742 # eastview already defined
\r
743 if ($key eq "view") {
\r
744 if (!$fileopts{eastview}) {
\r
745 $fileopts{eastview} = delete $fileopts{view};
\r
746 $_ = $key = "eastview";
\r
750 # Set into %_opts only if that key doesn't exist already. This
\r
751 # allows command line options to override options specified in the
\r
752 # file. The exception to this is the exec array. This gets
\r
753 # replaced in suite runs.
\r
754 if ($key eq "exec" || !$_opts{$key}) {
\r
755 $_opts{$key} = $fileopts{$_};
\r
759 my $testStartTime = time;
\r
761 $_east->setSaveTo ("$testName/$_opts{type}$_opts{unit}/" . YMDHMS ($testStartTime));
\r
763 eval { mkpath LOGBASE . "/" . $_east->getSaveTo };
\r
765 error "Unable to create log directory\n$@", 1 if $@;
\r
767 chmod 0775, LOGBASE . "/" . $_east->getSaveTo;
\r
770 $_log = new Logger (
\r
772 path => LOGBASE . "/" . $_east->getSaveTo,
\r
776 $_log->log ("$FindBin::Script Version " . VERSION_NBR . "\nUsing view: $_opts{eastview}");
\r
779 verbose BOLD CYAN "Using view: " . RESET $_opts{eastview};
\r
781 announceTestrun $testName;
\r
785 my $testFailures = 0;
\r
789 # Set testTimer if specified
\r
790 if ($_opts{testtimeout}) {
\r
791 $SIG{ALRM} = \&testTimeout;
\r
792 alarm $_opts{testtimeout};
\r
795 ($_east->{runID}, $errMsg) = $_rantestdb->startTestrun (UnixDatetime2SQLDatetime localtime $testStartTime);
\r
797 return ($_east->{runID}, $errMsg) if $_east->{runID} == 0;
\r
799 $_validationNbr = 0;
\r
801 if (ref $_opts{exec} eq "ARRAY") {
\r
802 foreach (@{$_opts{exec}}) {
\r
805 $_opts{class} = shift @tokens;
\r
806 $_opts{test} = join " ", @tokens;
\r
810 $result = executeTestStep;
\r
812 if ($result == -1) {
\r
816 $testFailures += $result;
\r
820 if ($_opts{exec}) {
\r
821 @tokens = split /\s+/, $_opts{exec};
\r
823 $_opts{class} = shift @tokens;
\r
824 $_opts{test} = join " ", @tokens;
\r
828 $result = executeTestStep;
\r
830 if ($result == -1) {
\r
833 $testFailures += $result;
\r
838 my $execType = $_opts{rfr} ? "Run for Record"
\r
839 : $_opts{regression} ? "Regression" : "Normal";
\r
841 return 1 if $result == -1;
\r
843 # Disconnect from EAST
\r
844 $_east->disconnect;
\r
846 # Assign 'Failed' and 'Timedout' 0 if they are not initialized
\r
847 $_stats{Failed} ||= 0;
\r
848 $_stats{Timedout} ||= 0;
\r
850 my $testErrors = $_stats{Failed} + $_stats{Timedout};
\r
852 # Collect log files and check them in based on checkin_on_error option
\r
853 $_east->collectLogFiles($testErrors, $_opts{checkin_on_error});
\r
855 if ($testFailures == 0 and $_opts{val}) {
\r
856 my @validations = ref $_opts{val} eq "ARRAY"
\r
860 $testFailures += runValidations @validations;
\r
864 verbose BOLD YELLOW . "Test #$_testNbr\t" . RESET CYAN $testName
\r
865 . (($testFailures == 0) ? GREEN " Success" : RED " Failure") . RESET;
\r
867 $_log->log ("Test #$_testNbr\t$testName " . (($testFailures == 0) ? "Success" : "Failure"));
\r
869 my ($_runID, $dbErrMsg) = $_rantestdb->endTestrun (
\r
870 runID => $_east->{runID},
\r
871 suiteID => $_east->{suiteID} ? $_east->{suiteID} : 0,
\r
872 name => fileparse ($file, ".test"),
\r
873 execType => $execType,
\r
874 start => UnixDatetime2SQLDatetime (scalar (localtime ($testStartTime))),
\r
875 result => $testFailures == 0 ? "Success" : "Failure",
\r
876 unit => "$_east->{unitType}$_east->{unitNbr}",
\r
877 rantest_version => VERSION_NBR,
\r
878 east_version => $ENV{EAST_REL},
\r
879 ran_version => $_east->{ran_version},
\r
880 tm500_version => $_east->{tm500_version},
\r
881 nms_version => $_east->{nms_version},
\r
882 eastlogs => LOGBASE . "/" . $_east->getSaveTo,
\r
885 error $dbErrMsg if $_runID == 0;
\r
887 return $testFailures;
\r
893 return if $ENV{PATH} =~ /$view/;
\r
897 if ($view =~ /(\S+)_SIM/) {
\r
900 error "Unable to find userdir", 1;
\r
904 "$ENV{MNT_DIR}/snapshot_views/$userdir/$view/vobs/simdev/sbin",
\r
905 "$ENV{MNT_DIR}/snapshot_views/$userdir/$view/vobs/simdev/bin",
\r
906 "$ENV{MNT_DIR}/snapshot_views/$userdir/$view/vobs/gdtools/rantest_auto/bin",
\r
909 $ENV{PATH} = join (":", @paths) . ":" . $ENV{PATH};
\r
912 sub runSuiteFile ($) {
\r
915 error "View must be specified when running in suite mode", 1 unless $_opts{eastview};
\r
917 setPath $_opts{eastview};
\r
921 if ($_opts{eastview} =~ /(\S+)_SIM/) {
\r
924 error "Unable to find userdir", 1;
\r
927 unless (open FILE, $file) {
\r
928 error "Unable to open file $file - $!";
\r
932 my @lines = <FILE>;
\r
939 my $suiteStartTime = time;
\r
940 my $suiteFailures = 0;
\r
941 my $suiteName = fileparse ($file, ".suite");
\r
943 $_log = new Logger (
\r
944 name => $suiteName,
\r
949 $_log->log ("$FindBin::Script Version " . VERSION_NBR);
\r
951 ($_east->{suiteID}) = $_rantestdb->startSuiterun ($suiteName);
\r
953 verbose BOLD MAGENTA "Suite\t" . RESET GREEN $suiteName . RESET;
\r
955 $_log->log ("Suite\t$suiteName");
\r
961 my @components = split;
\r
964 my $viewPath = "$ENV{MNT_DIR}/snapshot_views/$userdir/$_opts{eastview}/vobs/simdev/test/";
\r
965 my $testFile = "$viewPath/" . shift @components;
\r
967 unless (-e $testFile) {
\r
968 error "Unable to find test file $testFile (Line: $i)";
\r
972 unless (/\.test/) {
\r
973 error "Not a .test file: $testFile (Line: $i)";
\r
977 # Get test options. It seems GetOptions doesn't support taking
\r
978 # input from anything but @ARGV so we'll have to save a copy and
\r
980 my @savedOptions = @ARGV;
\r
986 my $status = GetOptions (
\r
998 ) || usage "Invalid parameter";
\r
1001 @ARGV = @savedOptions;
\r
1003 # Restore the original command line options:
\r
1004 %_opts = %_cmdline_opts;
\r
1006 # Merge in %suiteOptions: Set into %_opts only if that key doesn't
\r
1007 # exist already. This allows command line options to override
\r
1008 # options specified on the .test line in the .suite file
\r
1009 foreach (keys %suiteOptions) {
\r
1010 $_opts{$_} = $suiteOptions{$_} unless $_opts{$_};
\r
1013 $suiteFailures += runTestFile $testFile;
\r
1015 # Need to disconnect $_east to shut down the previous run
\r
1016 my $savedSuiteID = $_east->{suiteID};
\r
1018 $_east->disconnect;
\r
1020 # Collect logfiles
\r
1021 $_east->collectLogFiles;
\r
1023 if ($suiteFailures == 0 and $_opts{val}) {
\r
1024 my @validations = ref $_opts{val} eq "ARRAY"
\r
1028 $suiteFailures += runValidations @validations;
\r
1031 $_east = new Nethawk::East;
\r
1033 $_east->{suiteID} = $savedSuiteID;
\r
1038 # Log suite results
\r
1039 verbose BOLD MAGENTA "Suite\t" . RESET GREEN $suiteName
\r
1040 . (($suiteFailures == 0) ? GREEN " Success" : RED " Failure") . RESET;
\r
1042 $_log->log ("Suite\t$suiteName" . ($suiteFailures == 0) ? "Success" : "Failure");
\r
1046 ($_east->{suiteID}, $errMsg) = $_rantestdb->endSuiterun (
\r
1047 name => fileparse ($file, ".suite"),
\r
1048 start => UnixDatetime2SQLDatetime (scalar (localtime ($suiteStartTime))),
\r
1049 result => $suiteFailures ? "Failure" : "Success",
\r
1052 error $errMsg if $_east->{suiteID} != 0;
\r
1054 return $suiteFailures;
\r
1060 unless (-e $file) {
\r
1061 error "File $file does not exist";
\r
1065 $_term->AddHistory ("source $file")
\r
1066 unless $_debugging or !-t STDIN;
\r
1068 $SIG{INT} = \&interrupted;
\r
1070 # Determine file type
\r
1071 if ($file =~ /\.test$/) {
\r
1072 runTestFile $file;
\r
1073 } elsif ($file =~ /\.suite$/) {
\r
1074 return runSuiteFile $file
\r
1076 error "File $file is not a .suite or .test file", 1;
\r
1081 $SIG{QUIT} = \&saveHistory;
\r
1083 # Set a more friendly umask
\r
1088 verbose => sub { set_verbose },
\r
1089 debug => sub { set_debug },
\r
1090 usage => sub { usage; exit 0 },
\r
1101 "checkin_on_error",
\r
1105 ) || usage "Invalid parameter";
\r
1107 # Special case elock command
\r
1108 if (scalar @ARGV > 0 and $ARGV[0] =~ /elock/i) {
\r
1113 usage "Extraneous parameters: " . join " ", @ARGV if scalar @ARGV > 0;
\r
1115 # Check for mutually exclusive options
\r
1116 if ($_opts{file}) {
\r
1117 my $suffix = $ENV{RANTEST_FILE} ? "\nNote: The environment variable RANTEST_FILE is set" : "";
\r
1119 if ($_opts{test}) {
\r
1120 $suffix .= $ENV{RANTEST_TEST} ? "\nNote: The environment variable RANTEST_TEST is set" : "";
\r
1121 } elsif ($_opts{class}) {
\r
1122 $suffix .= $ENV{RANTEST_CLASS} ? "\nNote: The environment variable RANTEST_CLASS is set" : "";
\r
1125 usage "<test> and <file> are mutually exclusive$suffix" if $_opts{test};
\r
1126 usage "<class> and <file> are mutually exclusive$suffix" if $_opts{class};
\r
1129 if ($_opts{eastview}) {
\r
1130 my $suffix = $ENV{RANTEST_VIEW} ? "\nNote: The environment variable RANTEST_VIEW is set" : "";
\r
1131 $suffix .= $ENV{RANTEST_EASTVIEW} ? "\nNote: The environment variable RANTEST_EASTVIEW is set" : "";
\r
1133 usage "<eastview> and <view> are mutually exclusive$suffix" if $_opts{view};
\r
1136 usage "-rfr and -regression are mutually exclusive" if $_opts{rfr} && $_opts{regression};
\r
1138 # Make "view" an alias for "eastview" but only if there is no eastview
\r
1140 $_opts{eastview} = delete $_opts{view} if $_opts{view} && !$_opts{eastview};
\r
1142 # Check for required parameters
\r
1143 usage "-view or -eastview specified but no view given"
\r
1144 if defined $_opts{view} and $_opts{view} eq "";
\r
1145 usage "-tm500view specified but no view given"
\r
1146 if defined $_opts{tm500view} and $_opts{tm500view} eq "";
\r
1147 usage "-nmsview specified but no view given"
\r
1148 if defined $_opts{nmsview} and $_opts{nmsview} eq "";
\r
1149 usage "-type specified but no type given"
\r
1150 if defined $_opts{type} and $_opts{type} eq "";
\r
1151 usage "-class specified but no class given"
\r
1152 if defined $_opts{class} and $_opts{class} eq "";
\r
1153 usage "-unit specified but no unit # given"
\r
1154 if defined $_opts{unit} and $_opts{unit} eq "";
\r
1155 usage "-test specified but no test given"
\r
1156 if defined $_opts{test} and $_opts{test} eq "";
\r
1157 usage "-file specified but no file given"
\r
1158 if defined $_opts{file} and $_opts{file} eq "";
\r
1159 usage "-rfr specified but no testcase ID given"
\r
1160 if defined $_opts{rfr} and $_opts{rfr} eq "";
\r
1162 # Save these original command line options. If we are in suite mode
\r
1163 # then we must allow the individual .test options override these
\r
1164 # original command line options. If -rfr is on then we are by default
\r
1166 %_cmdline_opts = %_opts;
\r
1168 set_verbose if $_opts{rfr};
\r
1170 # Instantiate a new East object
\r
1171 $_east = new Nethawk::East;
\r
1173 # Set testcase ID into East object
\r
1174 $_east->setTestCaseID ($_opts{rfr});
\r
1176 $_debugging = get_debug;
\r
1178 # If we are debugging (and thus STDIN gets confused between the debugger's
\r
1179 # STDIN and rantest's STDIN) or if we don't have a tty (-t - we would not
\r
1180 # have a tty if run from say cron(1m), then do not perform these actions
\r
1182 unless ($_debugging or !-t STDIN) {
\r
1183 $_term = new Term::ReadLine $FindBin::Script;
\r
1185 $_term->{AUTORESET} = 1;
\r
1187 # Restore previous history, if any
\r
1188 $_term->ReadHistory (HISTORY_FILE);
\r
1191 # Announce ourselves
\r
1192 verbose DESC . RESET;
\r
1194 # Open Rantest Database
\r
1195 $_rantestdb = new RantestDB ("pswit", "!qaz2w3e");
\r
1197 if ($_opts{test}) {
\r
1198 $SIG{INT} = \&interrupted;
\r
1202 # Separate off options
\r
1203 my $testName = $_opts{test};
\r
1205 if ($_opts{test} =~ /(\S+)\s+\-.*$/) {
\r
1209 $testName = fileparse ($testName, "\.profile");
\r
1211 $_east->setSaveTo ("$testName/$_opts{type}$_opts{unit}/" . YMDHMS);
\r
1213 eval { mkpath LOGBASE . "/" . $_east->getSaveTo };
\r
1215 return (1, $@) if $@;
\r
1217 chmod 0775, LOGBASE . "/" . $_east->getSaveTo;
\r
1219 $_log = new Logger (
\r
1220 name => $testName,
\r
1221 path => LOGBASE . "/" . $_east->getSaveTo,
\r
1225 $_log->log ("$FindBin::Script Version " . VERSION_NBR . "\nUsing view: $_opts{eastview}");
\r
1229 $_term->AddHistory ("$_opts{class} $_opts{test}") unless $_debugging && -t STDIN;
\r
1231 # Disconnect from EAST
\r
1232 $_east->disconnect;
\r
1234 # Collect logfiles
\r
1235 $_east->collectLogFiles;
\r
1236 } elsif ($_opts{file}) {
\r
1237 runFile $_opts{file};
\r
1239 $_east->setSaveTo ("rantest/" . YMDHMS);
\r
1241 eval { mkpath LOGBASE . "/" . $_east->getSaveTo };
\r
1243 return (1, $@) if $@;
\r
1245 chmod 0777, LOGBASE . "/" . $_east->getSaveTo;
\r
1247 $_log = new Logger (
\r
1248 path => LOGBASE . "/" . $_east->getSaveTo,
\r
1252 display DESC if !get_verbose;
\r
1254 if ($_opts{eastview}) {
\r
1255 $_log->log ("$FindBin::Script Version " . VERSION_NBR . "\nUsing view: $_opts{eastview}");
\r
1257 $_log->log ("$FindBin::Script Version " . VERSION_NBR);
\r
1265 unless ($_debugging) {
\r
1266 $cmd = $_term->readline (PROMPT . RESET);
\r
1268 display_nolf PROMPT . RESET;
\r
1273 # Handle Control-d
\r
1274 unless (defined $cmd) {
\r
1282 next if $cmd eq "";
\r
1284 if ($cmd =~ /exit|quit/i) {
\r
1285 $_term->remove_history ($_term->where_history);
\r
1290 if ($cmd =~ /^elock/i) {
\r
1291 if ($cmd =~ /^elock\s+(\w+)/i) {
\r
1300 my @tokens = split /\s+/, $cmd;
\r
1302 $_opts{class} = shift @tokens;
\r
1303 $_opts{test} = join " ", @tokens;
\r
1305 $cmd = lc $_opts{class};
\r
1307 if ($cmd eq "help") {
\r
1309 $_term->remove_history ($_term->where_history) unless $_debugging;
\r
1311 } elsif ($cmd eq "usage") {
\r
1313 $_term->remove_history ($_term->where_history) unless $_debugging;
\r
1315 } elsif ($cmd eq "version") {
\r
1317 $_term->remove_history ($_term->where_history) unless $_debugging;
\r
1319 } elsif ($cmd eq "source") {
\r
1320 runFile $tokens[0];
\r
1321 } elsif ($cmd eq "set") {
\r
1322 if ($_opts{test} =~ /\s*(\w+)\s*=\s*(.+)/) {
\r
1323 my $optionName = $1;
\r
1326 # Remove quotes, if any. Note no check for balancing.
\r
1327 $value =~ s/[\"\']//g;
\r
1330 $_opts{$optionName} = $value;
\r
1332 } elsif ($cmd eq "get") {
\r
1333 if ($_opts{$tokens[0]}) {
\r
1334 display "$tokens[0] = $_opts{$tokens[0]}";
\r
1336 display "$tokens[0] is not set";
\r
1340 $_opts{class} = lc $_opts{class};
\r
1342 if ( $_opts{class} eq "manual" ) {
\r
1343 $_opts{test} = " ";
\r
1350 # Disconnect from EAST
\r
1351 $_east->disconnect;
\r
1353 # Assign 'Failed' and 'Timedout' 0 if they are not initialized
\r
1354 $_stats{Failed} ||= 0;
\r
1355 $_stats{Timedout} ||= 0;
\r
1357 my $testErrors = $_stats{Failed} + $_stats{Timedout};
\r
1359 # Collect log files and check them in based on checkin_on_error option
\r
1360 $_east->collectLogFiles($testErrors, $_opts{checkin_on_error});
\r
1367 # The combination of Failed and Timedout represents our exit
\r
1368 # status. If either or both of them is defined then they will be
\r
1369 # non-zero and thus we exit with a non-zero status. Only if both are
\r
1370 # undefined, and thus set to 0 by the code below, will we exit 0.
\r
1371 $_stats{Failed} = 0 unless $_stats{Failed};
\r
1372 $_stats{Timedout} = 0 unless $_stats{Timedout};
\r
1374 # Now exit with the correct status
\r
1375 exit ($_stats{Failed} + $_stats{Timedout});
\r