Removed /usr/local from CDPATH
[clearscm.git] / rantest / rantest
1 #!/usr/bin/perl\r
2 ##############################################################################\r
3 #\r
4 # Name:         rantest\r
5 #\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
16 #\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
20 #\r
21 #               b2_l3_rnc_irt_001.test:\r
22 #               ----------------------\r
23 #               view:   p6258c_SIMCQ00000100_intview\r
24 #               type:   rnc\r
25 #               unit:   4\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
30 #\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
37 #\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
42 #\r
43 #               This would be run as so:\r
44 #\r
45 #               $ rantest -file b2_l3_rnc_irt_001.test\r
46 #\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
52 #\r
53 #               nightly.suite:\r
54 #               --------------\r
55 #               # RNC IRT tests\r
56 #               b2_l3_rnc_irt_007.test -unit 4\r
57 #               b2_l3_rnc_irt_014.test\r
58 #\r
59 #               # RNC SCH tests\r
60 #               b2_l3_rnc_sch_001.test -view official_view\r
61 #               b2_l3_rnc_sch_003a.test\r
62 #\r
63 # Author:       Andrew@ClearSCM.com\r
64 #\r
65 # Copyright (c) 2008, 2009 General Dynamics\r
66 #\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
69 #\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
75 # 5230.25.\r
76 #\r
77 ##############################################################################\r
78 use strict;\r
79 use warnings;\r
80 \r
81 use File::Basename;\r
82 use File::Glob ':glob';\r
83 use File::Path;\r
84 use FindBin;\r
85 use Getopt::Long;\r
86 use Net::Domain qw (hostname);\r
87 use Term::ANSIColor qw (:constants);\r
88 use Term::ReadLine;\r
89 use Term::ReadLine::Gnu;\r
90 \r
91 # Use the SDE Tools libraries. Sorry for this long path. I didn't come\r
92 # up with it!\r
93 #use lib "/cleartrig/ent/SNSD/muos/ccadm_tools/vobs/ranccadm/scripts/lib";\r
94 use lib "$FindBin::Bin/../lib";\r
95 \r
96 use DateUtils;\r
97 use Display;\r
98 use Utils;\r
99 use GetConfig;\r
100 use Logger;\r
101 \r
102 error "$FindBin::Script only runs on seast1", 1\r
103   unless hostname eq "seast1";\r
104 \r
105 use lib "$FindBin::Bin/../lib";\r
106 \r
107 use GD::RantestDB;\r
108 use GD::Nethawk::East;\r
109 \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
115                          . RESET        ": "\r
116                          . BOLD CYAN    "RAN T"\r
117                          . RESET        "ool for "\r
118                          . BOLD CYAN    "E"\r
119                          . RESET        "xecution of "\r
120                          . BOLD CYAN    "S"\r
121                          . RESET        "ystem "\r
122                          . BOLD CYAN    "T"\r
123                          . RESET        "ests";\r
124 \r
125 use constant HISTORY_FILE => "$ENV{HOME}/.rantest_hist";\r
126 use constant LOGBASE      => "$ENV{MNT_DIR}/testlogs";\r
127 \r
128 ############################################################################\r
129 # Globals\r
130 ############################################################################\r
131 my $_east;\r
132 my $_connected          = 0;\r
133 my $_debugging;\r
134 my $_log;\r
135 my $_term;\r
136 my $_rantestdb;\r
137 my $_testNbr            = 0;\r
138 my $_validationNbr      = 0;\r
139 \r
140 my %_stats;\r
141 \r
142 my %_executionResults;\r
143 \r
144 my (%_opts, %_cmdline_opts);\r
145 \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
161 \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
164 \r
165 sub usage (;$) {\r
166   my ($msg) = @_;\r
167 \r
168   my $usage = "ERROR: $msg\n\n" if $msg;\r
169 \r
170   $usage .= <<END;\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
175   [-[no]s|ecure]\r
176 \r
177 Where:\r
178 \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
184                      test\r
185   -nm|sview <tag>    NMS view to set into the environment for\r
186                      test\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
189 \r
190       Load           LoadTCRunner\r
191       Pool           RegressionLoadRunner\r
192       TC             RegressionRunner\r
193       TS             RegressionTSRunner\r
194       Manual         Manual test\r
195 \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
202                      results under\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
205                      results.\r
206   -feature <feature> If specified then FEATURE will be set into the\r
207                      environment on the blade before calling\r
208                      start_east_auto.\r
209   -[no]s|ecure       Indicates whether or not to secure the node before\r
210                      attempting to connect to it. (Default: secure).\r
211 \r
212 NOTE: Set ANSI_COLORS_DISABLED to turn off colors\r
213 \r
214 If you specify -file you cannot specify -test nor -class. -class'es are\r
215 read from -file.\r
216 \r
217 Additionally, options above can be specified in the environment by\r
218 preceeding the environment variable with \"RANTEST_\". For example,\r
219 \r
220   \$ export RANTEST_TYPE=rbs\r
221   \$ export RANTEST_UNIT=2\r
222   \$ rantest\r
223 \r
224 Also such options can be specified in the -file:\r
225 \r
226   unit: 5\r
227   executionlevel: 2\r
228   ts ts1.profile -timeout -1 -pause 5\r
229   ts ts2.profile -displaylevel 3\r
230   ts ts3.profile -activecalls 10\r
231 \r
232 Options after test profile name are passed directory to EAST's command\r
233 line. The exceptions are -timeout and -pause:\r
234 \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
241 \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
246                         time to start.\r
247 \r
248   -name <name>          Names a test. Used in conditional execution.\r
249 \r
250   -if (<name> <status>) Run this test if the named test returned <status>\r
251                         where <status> is one of\r
252 \r
253                           . Success\r
254                           . Failure\r
255                           . In Progress\r
256                           . Timed out\r
257                           . Failed to execute\r
258                           . Rendezvous\r
259                           . Failed to rendezvous\r
260 \r
261 Note: Required options not supplied will be prompted for.\r
262 END\r
263 \r
264   my $pager = $ENV{PAGER} ? $ENV{PAGER} : "more";\r
265 \r
266   system "echo \"$usage\" | $pager";\r
267 \r
268   exit 1 if $msg;\r
269 } # usage\r
270 \r
271 sub help () {\r
272   display DESC . RESET;\r
273   display <<END;\r
274 \r
275 Valid commands are:\r
276 \r
277 help:                   This display\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
285 \r
286 Running tests:\r
287 \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
292 manual\r
293 \r
294 Note: ReadLine is supported thus you can edit previous commands.\r
295 Try the up arrow!\r
296 END\r
297 } # Help\r
298 \r
299 sub getParm ($) {\r
300   my ($prompt) = @_;\r
301 \r
302   my $value;\r
303 \r
304   while (!$value or $value eq "") {\r
305     display_nolf BOLD YELLOW . "$FindBin::Script needs the following parameter - $prompt" . RESET;\r
306 \r
307     $value = <STDIN>;\r
308 \r
309     chomp $value;\r
310   } # while\r
311 \r
312   return $value;\r
313 } # getParm\r
314 \r
315 sub eLock (;$) {\r
316   my ($unit) = @_;\r
317 \r
318   my ($status, @locks) = Execute "ls $ENV{MNT_DIR}/$ENV{EAST_REL}/DUT/*/desktop.lock 2> /dev/null";\r
319 \r
320   $status >>= 8;\r
321 \r
322   foreach (@locks) {\r
323     my $unit_found;\r
324 \r
325     if (/.*DUT\/(\w+)\/desktop/) {\r
326       $unit_found = $1;\r
327 \r
328       next if $unit && $unit_found !~ /$unit/i;\r
329     } # if\r
330 \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
336 \r
337     display BOLD CYAN   "$fields[5]\t"\r
338           . RESET       "locked since "\r
339           . BOLD YELLOW localtime ((stat $_)[9])\r
340           . RESET       " by "\r
341           . MAGENTA     $name\r
342           . RESET       " ("\r
343           . GREEN       $userid\r
344           . RESET       ")";\r
345   } # foreach\r
346 } # eLock\r
347 \r
348 sub displaySummary () {\r
349   my $msg = "Summary:";\r
350 \r
351   foreach (sort keys %_stats) {\r
352     $msg .= " $_stats{$_} $_";\r
353   } # foreach\r
354 \r
355   $_log->msg ($msg) if $_log;\r
356 } # displaySummary\r
357 \r
358 sub announceTestrun ($) {\r
359   my ($testname) = @_;\r
360 \r
361   my $user = $ENV{USER}         ? $ENV{USER}\r
362            : $ENV{LOGNAME}      ? $ENV{LOGNAME}\r
363            : "Unknown";\r
364   my $timestamp = YMDHMS;\r
365 \r
366   $_testNbr++;\r
367 \r
368   verbose BOLD YELLOW   "Test #" . $_testNbr . "\t"\r
369         . RESET CYAN    $testname\r
370         . RESET         " run on $timestamp by "\r
371         . YELLOW        $user\r
372         . RESET         " on "\r
373         . MAGENTA       $_opts{type}\r
374         . RESET         " unit "\r
375         . CYAN          $_opts{unit}\r
376         . RESET;\r
377 \r
378   $_log->log ("Test #$_testNbr $testname run on: $timestamp by $user on $_opts{type} unit $_opts{unit}");\r
379 } # announceTestrun\r
380 \r
381 sub saveHistory {\r
382   $_term->WriteHistory (HISTORY_FILE) if $_term;\r
383 } # saveHistory\r
384 \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
392 \r
393     # Connect to it\r
394     my $msg = $_east->connect (\r
395       $_opts{eastview},\r
396       $_opts{type},\r
397       $_opts{unit},\r
398       $_opts{tm500view},\r
399       $_opts{nmsview},\r
400       $_opts{feature},\r
401       $_opts{secure}\r
402     );\r
403 \r
404     if ($msg) {\r
405       $_log->err ("Unable to connect to EAST\n$msg");\r
406       verbose RED "Skipping renaming test steps" . RESET;\r
407       $_stats{Failed}++;\r
408       return -1;\r
409     } else {\r
410       $_connected = 1;\r
411     } # if\r
412   } # if\r
413 \r
414   my ($status, $msg) = Nethawk::East::validTestType ($_opts{class});\r
415 \r
416   if ($status != 0) {\r
417     $_log->err ($msg);\r
418     return $status;\r
419   } # if\r
420 \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
425       return 1;\r
426     } # unless\r
427   } # if\r
428 \r
429   $_east->setCollectLogFiles (1);\r
430 \r
431   verbose_nolf $_stats{Run} . ": " . CYAN "$_opts{class}\t" . BOLD YELLOW $_opts{test} . RESET;\r
432 \r
433   my $testStepResult;\r
434 \r
435   my $startTime = time;\r
436   my $stepName  = "Unknown";\r
437 \r
438   if ($_opts{test} =~ /(.*)\.profile/) {\r
439     $stepName = $1;\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
446 \r
447     $_east->setRantvlStartTime (time);\r
448   } # if\r
449 \r
450   my ($stepID, $errMsg) = $_rantestdb->startSteprun ($stepName);\r
451 \r
452   ($status, $testStepResult) = $_east->exec (\%_opts, \%_executionResults);\r
453 \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
461   } # if\r
462 \r
463   my $endTime = time;\r
464 \r
465   if ($status == 0) {\r
466     if ($testStepResult eq "Success") {\r
467       verbose GREEN " $testStepResult" . RESET;\r
468       $_stats{Passed}++;\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
476     } else {\r
477       verbose RED " $testStepResult" . RESET;\r
478       $status = 1;\r
479       $_stats{Failed}++;\r
480     } # if\r
481   } else {\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
487       $status = 1;\r
488       $_stats{Timedout}++;\r
489     } else {\r
490       verbose RED " $testStepResult" . RESET;\r
491       $status = 1;\r
492       $_stats{Failed}++;\r
493     } # if\r
494   } # if\r
495 \r
496   # Log test step result\r
497   $_log->log ("$_stats{Run}: $_opts{class}\t$_opts{test} $testStepResult");\r
498 \r
499   my ($dbErrNbr, $dbErrMsg) = $_rantestdb->endSteprun (\r
500     runID       => $_east->{runID},\r
501     stepID      => $stepID,\r
502     start       => UnixDatetime2SQLDatetime (scalar (localtime ($startTime))),\r
503     end         => UnixDatetime2SQLDatetime (scalar (localtime ($endTime))),\r
504     result      => $testStepResult,\r
505   );\r
506 \r
507   error $dbErrMsg if $dbErrNbr != 0;\r
508 \r
509   return $status;\r
510 } # executeTestStep\r
511 \r
512 sub testTimeout {\r
513   error "Test timed out ($_opts{testtimeout}) seconds passed)";\r
514 \r
515   $_east->disconnect;\r
516 \r
517   # Collect logfiles\r
518   $_east->collectLogFiles;\r
519 } # testTimeout\r
520 \r
521 sub interrupted {\r
522   use Term::ReadKey;\r
523 \r
524   display BLUE "\nInterrupted" . RESET;\r
525 \r
526   displaySummary;\r
527 \r
528   display_nolf\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
533 \r
534   ReadMode ("cbreak");\r
535   my $answer = ReadKey (0);\r
536   ReadMode ("normal");\r
537 \r
538   if ($answer eq "\n") {\r
539     display "c";\r
540   } else {\r
541     display $answer;\r
542   } # if\r
543 \r
544   $answer = lc $answer;\r
545 \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
551     saveHistory;\r
552     exit;\r
553   } # if\r
554 } # interrupted\r
555 \r
556 sub interpolate ($) {\r
557   my ($str) = @_;\r
558 \r
559   # Perform psuedo variable interpolation. The following psuedo\r
560   # variables are supported:\r
561   #\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
565 \r
566   # msgdefs:      Absolute path to msgdefs\r
567   my $msgdefs   = "$simdev/msgdefs";\r
568 \r
569   # validation:  Absolute path to validation\r
570   my $validation        = "$simdev/validation";\r
571 \r
572   # logpath:      Absolute path into the "testlogs" area where\r
573   #               logfiles are written\r
574   my $logpath   = LOGBASE . "/" . $_east->getSaveTo;\r
575 \r
576   while ($str =~ /\$/) {\r
577     my ($var, $slice);\r
578 \r
579     if ($str =~ /\$(\w+)/) {    \r
580       # Regular $var\r
581       $var      = $1;\r
582     } elsif ($str =~ /\$(\[.+?\])\[(.+?)\]/) {\r
583       # A $[fileset][slice] reference\r
584       $var      = $1;\r
585       $slice    = $2;\r
586     } elsif ($str =~ /\$(\[.+?\])/) {   \r
587       # A $[fileset] reference\r
588       $var      = $1;\r
589     } # if\r
590 \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
600       my $fileset = $1;\r
601 \r
602       my @fileset = glob $fileset;\r
603       my $list;\r
604 \r
605       if (defined $slice) {\r
606         $fileset = quotemeta $fileset;\r
607 \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
615           #\r
616           # Adjust bounds\r
617           $2 = $#fileset if $2 > $#fileset;\r
618 \r
619           no warnings;\r
620           $list = join ",", @fileset[$1..$2];\r
621           use warnings;\r
622         } else {\r
623           # Not a slice really but an array reference\r
624           $list = "$fileset[$slice]";\r
625         } # if\r
626 \r
627         $str =~ s/\$\[$fileset\]\[$slice\]/$list/;\r
628       } else {\r
629         $list = join ",", @fileset;\r
630         $str =~ s/\$\[$fileset\]/$list/;\r
631       } # if\r
632 \r
633       if (defined $slice) {\r
634         $str =~ s/\$\[$fileset\]\[$slice\]//;\r
635       } else {\r
636         $str =~ s/\$\[$fileset\]//;\r
637       } # if\r
638     } else {\r
639       error "Unknown variable ($var) encountered in val line:\n$str", 1;\r
640     } # if\r
641   } # while\r
642 \r
643   return $str;\r
644 } # interpolate\r
645 \r
646 sub runValidation ($$) {\r
647   my ($cmd, $logfile) = @_;\r
648 \r
649   my $origCmd = $cmd;\r
650 \r
651   my ($stepID, $errMsg);\r
652 \r
653   ($stepID, $errMsg) = $_rantestdb->startSteprun ($origCmd);\r
654 \r
655   if ($stepID == 0) {\r
656     error "Unable to startSteprun\n$errMsg";\r
657     return 1;\r
658   } # if\r
659 \r
660   my $startTime = time;\r
661 \r
662   $cmd = interpolate ($cmd);\r
663 \r
664   my ($status, @lines) = Execute ("$cmd >> $logfile 2>&1");\r
665 \r
666   $status >>= 8;\r
667 \r
668   my $endTime = time;\r
669 \r
670   my ($dbErrNbr, $dbErrMsg) = $_rantestdb->endSteprun (\r
671     runID       => $_east->{runID},\r
672     stepID      => $stepID,\r
673     start       => UnixDatetime2SQLDatetime (scalar (localtime ($startTime))),\r
674     end         => UnixDatetime2SQLDatetime (scalar (localtime ($endTime))),\r
675     result      => $status ? "Failure" : "Success",\r
676   );\r
677 \r
678   error $dbErrMsg if $dbErrNbr != 0;\r
679 \r
680   # Output lines to stdout\r
681   if (-e $logfile) {\r
682     verbose "$_\n" foreach (ReadFile $logfile);\r
683   } else {\r
684     verbose "Unable to read $logfile";\r
685     $status++;\r
686   } # if\r
687 \r
688   $_validationNbr++;\r
689 \r
690   verbose BOLD YELLOW . "Test #$_testNbr validation #$_validationNbr \t" . RESET CYAN $origCmd\r
691     . (($status == 0) ? GREEN " Success" : RED " Failure") . RESET;\r
692 \r
693   $_log->log ("Test #$_testNbr validation #$_validationNbr\t$origCmd " . (($status == 0) ? "Success" : "Failure"));\r
694 \r
695   return $status;\r
696 } # runValidation\r
697 \r
698 sub runValidations (@) {\r
699   my @validations = @_;\r
700 \r
701   my $validationErrs = 0;\r
702 \r
703   # Make Validation log directory\r
704   my $validationDir = LOGBASE . "/" . $_east->getSaveTo . "/Validations";\r
705 \r
706   eval { mkpath $validationDir };\r
707 \r
708   error "Unable to create Validation directory - $validationDir\n$@", 1 if $@;\r
709 \r
710   chmod 0775, $validationDir;\r
711 \r
712   my $viewPath  = "$ENV{MNT_DIR}/snapshot_views/$_east->{userdir}/$_east->{view}";\r
713   my $vobPath   = "vobs/simdev";\r
714 \r
715   foreach (@validations) {\r
716     my @tokens  = split;\r
717     my $outfile = $tokens[0] . ".log";\r
718 \r
719     $validationErrs += runValidation $_, "$validationDir/$outfile";\r
720   } # foreach\r
721 \r
722   $_stats{Failed} += $validationErrs;\r
723 \r
724   return $validationErrs;\r
725 } # runValidations\r
726 \r
727 sub runTestFile ($) {\r
728   my ($file) = @_;\r
729 \r
730   my $testName = fileparse $file, ".test";\r
731 \r
732   my $testID = $_rantestdb->startTest ($testName);\r
733 \r
734   my %fileopts = GetConfig ($file);\r
735 \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
739     my $key = lc $_;\r
740 \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
747       } # if\r
748     } # if\r
749 \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
756     } # if\r
757   } # foreach\r
758 \r
759   my $testStartTime = time;\r
760 \r
761   $_east->setSaveTo ("$testName/$_opts{type}$_opts{unit}/" . YMDHMS ($testStartTime));\r
762 \r
763   eval { mkpath LOGBASE . "/" . $_east->getSaveTo };\r
764 \r
765   error "Unable to create log directory\n$@", 1 if $@;\r
766 \r
767   chmod 0775, LOGBASE . "/" . $_east->getSaveTo;\r
768 \r
769   unless ($_log) {\r
770     $_log = new Logger (\r
771       name      => $testName,\r
772       path      => LOGBASE . "/" . $_east->getSaveTo,\r
773       append    => "yes",\r
774     );\r
775 \r
776     $_log->log ("$FindBin::Script Version " . VERSION_NBR . "\nUsing view: $_opts{eastview}");\r
777   } # unless\r
778 \r
779   verbose BOLD CYAN "Using view: " . RESET $_opts{eastview};\r
780 \r
781   announceTestrun $testName;\r
782 \r
783   my @tokens;\r
784 \r
785   my $testFailures      = 0;\r
786   my $result            = 0;\r
787   my $errMsg;\r
788 \r
789   # Set testTimer if specified\r
790   if ($_opts{testtimeout}) {\r
791     $SIG{ALRM} = \&testTimeout;\r
792     alarm $_opts{testtimeout};\r
793   } # if\r
794 \r
795   ($_east->{runID}, $errMsg) = $_rantestdb->startTestrun (UnixDatetime2SQLDatetime localtime $testStartTime);\r
796 \r
797   return ($_east->{runID}, $errMsg) if $_east->{runID} == 0;\r
798 \r
799   $_validationNbr = 0;\r
800 \r
801   if (ref $_opts{exec} eq "ARRAY") {\r
802     foreach (@{$_opts{exec}}) {\r
803       @tokens = split;\r
804 \r
805       $_opts{class} = shift @tokens;\r
806       $_opts{test}  = join " ", @tokens;\r
807 \r
808       $_stats{Run}++;\r
809 \r
810       $result = executeTestStep;\r
811 \r
812       if ($result == -1) {\r
813         $testFailures++;\r
814         last;\r
815       } else {\r
816         $testFailures += $result;\r
817       } # if\r
818     } # foreach\r
819   } else {\r
820     if ($_opts{exec}) {\r
821       @tokens = split /\s+/, $_opts{exec};\r
822 \r
823       $_opts{class} = shift @tokens;\r
824       $_opts{test}  = join " ", @tokens;\r
825 \r
826       $_stats{Run}++;\r
827 \r
828       $result = executeTestStep;\r
829 \r
830       if ($result == -1) {\r
831         $testFailures++;\r
832       } else {\r
833         $testFailures += $result;\r
834       } # if\r
835     } # if\r
836   } # if\r
837 \r
838   my $execType = $_opts{rfr}            ? "Run for Record"\r
839                : $_opts{regression}     ? "Regression" : "Normal";\r
840 \r
841   return 1 if $result == -1;\r
842 \r
843   # Disconnect from EAST\r
844   $_east->disconnect;\r
845 \r
846   # Assign 'Failed' and 'Timedout' 0 if they are not initialized\r
847   $_stats{Failed}   ||= 0;\r
848   $_stats{Timedout} ||= 0;\r
849 \r
850   my $testErrors = $_stats{Failed} + $_stats{Timedout};\r
851 \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
854 \r
855   if ($testFailures == 0 and $_opts{val}) {\r
856     my @validations = ref $_opts{val} eq "ARRAY"\r
857                     ? @{$_opts{val}}\r
858                     : ($_opts{val});\r
859 \r
860     $testFailures += runValidations @validations;\r
861   } # if\r
862 \r
863   # Log test results\r
864   verbose BOLD YELLOW . "Test #$_testNbr\t" . RESET CYAN $testName\r
865     . (($testFailures == 0) ? GREEN " Success" : RED " Failure") . RESET;\r
866 \r
867   $_log->log ("Test #$_testNbr\t$testName " . (($testFailures == 0) ? "Success" : "Failure"));\r
868 \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
883   );\r
884 \r
885   error $dbErrMsg if $_runID == 0;\r
886 \r
887   return $testFailures;\r
888 } # runTestFile\r
889 \r
890 sub setPath ($) {\r
891   my ($view) = @_;\r
892 \r
893   return if $ENV{PATH} =~ /$view/;\r
894 \r
895   my $userdir;\r
896 \r
897   if ($view =~ /(\S+)_SIM/) {\r
898     $userdir = $1;\r
899   } else {\r
900     error "Unable to find userdir", 1;\r
901   } # if\r
902 \r
903   my @paths = (\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
907   );\r
908 \r
909   $ENV{PATH} = join (":", @paths) . ":" . $ENV{PATH};\r
910 } # setPath\r
911 \r
912 sub runSuiteFile ($) {\r
913   my ($file) = @_;\r
914 \r
915   error "View must be specified when running in suite mode", 1 unless $_opts{eastview};\r
916 \r
917   setPath $_opts{eastview};\r
918 \r
919   my $userdir;\r
920 \r
921   if ($_opts{eastview} =~ /(\S+)_SIM/) {\r
922     $userdir = $1;\r
923   } else {\r
924     error "Unable to find userdir", 1;\r
925   } # if\r
926 \r
927   unless (open FILE, $file) {\r
928     error "Unable to open file $file - $!";\r
929     return 1\r
930   } # unless\r
931 \r
932   my @lines = <FILE>;\r
933 \r
934   chomp @lines;\r
935 \r
936   close FILE;\r
937 \r
938   my $i                 = 0;\r
939   my $suiteStartTime    = time;\r
940   my $suiteFailures     = 0;\r
941   my $suiteName         = fileparse ($file, ".suite");\r
942 \r
943   $_log = new Logger (\r
944     name        => $suiteName,\r
945     path        => LOGBASE,\r
946     append      => "yes",\r
947   );\r
948 \r
949   $_log->log ("$FindBin::Script Version " . VERSION_NBR);\r
950 \r
951   ($_east->{suiteID}) = $_rantestdb->startSuiterun ($suiteName);\r
952 \r
953   verbose BOLD MAGENTA "Suite\t" . RESET GREEN $suiteName . RESET;\r
954 \r
955   $_log->log ("Suite\t$suiteName");\r
956 \r
957   foreach (@lines) {\r
958     $i++;\r
959     next if /(^#|^$)/;\r
960 \r
961     my @components = split;\r
962 \r
963 \r
964     my $viewPath = "$ENV{MNT_DIR}/snapshot_views/$userdir/$_opts{eastview}/vobs/simdev/test/";\r
965     my $testFile = "$viewPath/" . shift @components;\r
966 \r
967     unless (-e $testFile) {\r
968       error "Unable to find test file $testFile (Line: $i)";\r
969       next;\r
970     } # unless\r
971 \r
972     unless (/\.test/) {\r
973       error "Not a .test file: $testFile (Line: $i)";\r
974       next;\r
975     } # unless\r
976 \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
979     # restore it.\r
980     my @savedOptions = @ARGV;\r
981 \r
982     @ARGV = split;\r
983 \r
984     my %suiteOptions;\r
985 \r
986     my $status = GetOptions (\r
987       \%suiteOptions,\r
988       "eastview=s",\r
989       "tm500view=s",\r
990       "nmsview=s",\r
991       "type=s",\r
992       "class=s",\r
993       "unit=s",\r
994       "test=s",\r
995       "file=s",\r
996       "rfr=s",\r
997       "regression",\r
998     ) || usage "Invalid parameter";\r
999 \r
1000     # Restore @ARGV\r
1001     @ARGV = @savedOptions;\r
1002 \r
1003     # Restore the original command line options:\r
1004     %_opts = %_cmdline_opts;\r
1005 \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
1011     } # foreach\r
1012 \r
1013     $suiteFailures += runTestFile $testFile;\r
1014 \r
1015     # Need to disconnect $_east to shut down the previous run\r
1016     my $savedSuiteID = $_east->{suiteID};\r
1017 \r
1018     $_east->disconnect;\r
1019 \r
1020     # Collect logfiles\r
1021     $_east->collectLogFiles;\r
1022 \r
1023     if ($suiteFailures == 0 and $_opts{val}) {\r
1024       my @validations = ref $_opts{val} eq "ARRAY"\r
1025                       ? @{$_opts{val}}\r
1026                       : ($_opts{val});\r
1027 \r
1028       $suiteFailures += runValidations @validations;\r
1029     } # if\r
1030 \r
1031     $_east = new Nethawk::East;\r
1032 \r
1033     $_east->{suiteID} = $savedSuiteID;\r
1034 \r
1035     $_connected = 0;\r
1036   } # foreach\r
1037 \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
1041 \r
1042   $_log->log ("Suite\t$suiteName" . ($suiteFailures == 0) ? "Success" : "Failure");\r
1043 \r
1044   my $errMsg;\r
1045 \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
1050   );\r
1051 \r
1052   error $errMsg if $_east->{suiteID} != 0;\r
1053 \r
1054   return $suiteFailures;\r
1055 } # runSuiteFile\r
1056 \r
1057 sub runFile ($) {\r
1058   my ($file) = @_;\r
1059 \r
1060   unless (-e $file) {\r
1061     error "File $file does not exist";\r
1062     return;\r
1063   } # if\r
1064 \r
1065   $_term->AddHistory ("source $file")\r
1066     unless $_debugging or !-t STDIN;\r
1067 \r
1068   $SIG{INT} = \&interrupted;\r
1069 \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
1075   } else {\r
1076     error "File $file is not a .suite or .test file", 1;\r
1077   } # if\r
1078 } # runFile\r
1079 \r
1080 $SIG{TERM}      =\r
1081 $SIG{QUIT}      = \&saveHistory;\r
1082 \r
1083 # Set a more friendly umask\r
1084 umask 002;\r
1085 \r
1086 GetOptions (\r
1087   \%_opts,\r
1088   verbose       => sub { set_verbose },\r
1089   debug         => sub { set_debug },\r
1090   usage         => sub { usage; exit 0 },\r
1091   "eastview:s",\r
1092   "view:s",\r
1093   "tm500view:s",\r
1094   "nmsview:s",\r
1095   "type:s",\r
1096   "class:s",\r
1097   "unit:s",\r
1098   "test:s",\r
1099   "file:s",\r
1100   "rfr:s",\r
1101   "checkin_on_error",\r
1102   "feature:s",\r
1103   "secure!",\r
1104   "regression",\r
1105 ) || usage "Invalid parameter";\r
1106 \r
1107 # Special case elock command\r
1108 if (scalar @ARGV > 0 and $ARGV[0] =~ /elock/i) {\r
1109   eLock ($ARGV[1]);\r
1110   exit;\r
1111 } # if\r
1112 \r
1113 usage "Extraneous parameters: " . join " ", @ARGV if scalar @ARGV > 0;\r
1114 \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
1118 \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
1123   } # if\r
1124 \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
1127 } # if\r
1128 \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
1132 \r
1133   usage "<eastview> and <view> are mutually exclusive$suffix" if $_opts{view};\r
1134 } # if\r
1135 \r
1136 usage "-rfr and -regression are mutually exclusive" if $_opts{rfr} && $_opts{regression};\r
1137 \r
1138 # Make "view" an alias for "eastview" but only if there is no eastview\r
1139 # already defined\r
1140 $_opts{eastview} = delete $_opts{view} if $_opts{view} && !$_opts{eastview};\r
1141 \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
1161 \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
1165 # verbose\r
1166 %_cmdline_opts = %_opts;\r
1167 \r
1168 set_verbose if $_opts{rfr};\r
1169 \r
1170 # Instantiate a new East object\r
1171 $_east = new Nethawk::East;\r
1172 \r
1173 # Set testcase ID into East object\r
1174 $_east->setTestCaseID ($_opts{rfr});\r
1175 \r
1176 $_debugging = get_debug;\r
1177 \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
1181 # on $_term.\r
1182 unless ($_debugging or !-t STDIN) {\r
1183   $_term = new Term::ReadLine $FindBin::Script;\r
1184 \r
1185   $_term->{AUTORESET} = 1;\r
1186 \r
1187   # Restore previous history, if any\r
1188   $_term->ReadHistory (HISTORY_FILE);\r
1189 } # unless\r
1190 \r
1191 # Announce ourselves\r
1192 verbose DESC . RESET;\r
1193 \r
1194 # Open Rantest Database\r
1195 $_rantestdb = new RantestDB ("pswit", "!qaz2w3e");\r
1196 \r
1197 if ($_opts{test}) {\r
1198   $SIG{INT} = \&interrupted;\r
1199 \r
1200   $_stats{Run}++;\r
1201 \r
1202   # Separate off options\r
1203   my $testName = $_opts{test};\r
1204 \r
1205   if ($_opts{test} =~ /(\S+)\s+\-.*$/) {\r
1206     $testName = $1;\r
1207  } # if\r
1208 \r
1209   $testName = fileparse ($testName, "\.profile");\r
1210 \r
1211   $_east->setSaveTo ("$testName/$_opts{type}$_opts{unit}/" . YMDHMS);\r
1212 \r
1213   eval { mkpath LOGBASE . "/" . $_east->getSaveTo };\r
1214 \r
1215   return (1, $@) if $@;\r
1216 \r
1217   chmod 0775, LOGBASE . "/" . $_east->getSaveTo;\r
1218 \r
1219   $_log = new Logger (\r
1220     name        => $testName,\r
1221     path        => LOGBASE . "/" . $_east->getSaveTo,\r
1222     append      => "yes",\r
1223   );\r
1224 \r
1225   $_log->log ("$FindBin::Script Version " . VERSION_NBR . "\nUsing view: $_opts{eastview}");\r
1226 \r
1227   executeTestStep;\r
1228 \r
1229   $_term->AddHistory ("$_opts{class} $_opts{test}") unless $_debugging && -t STDIN;\r
1230 \r
1231   # Disconnect from EAST\r
1232   $_east->disconnect;\r
1233 \r
1234   # Collect logfiles\r
1235   $_east->collectLogFiles;\r
1236 } elsif ($_opts{file}) {\r
1237   runFile $_opts{file};\r
1238 } else {\r
1239   $_east->setSaveTo ("rantest/" . YMDHMS);\r
1240 \r
1241   eval { mkpath LOGBASE . "/" . $_east->getSaveTo };\r
1242 \r
1243   return (1, $@) if $@;\r
1244 \r
1245   chmod 0777, LOGBASE . "/" . $_east->getSaveTo;\r
1246 \r
1247   $_log = new Logger (\r
1248     path        => LOGBASE . "/" . $_east->getSaveTo,\r
1249     append      => "yes"\r
1250   );\r
1251 \r
1252   display DESC if !get_verbose;\r
1253 \r
1254   if ($_opts{eastview}) {\r
1255     $_log->log ("$FindBin::Script Version " . VERSION_NBR . "\nUsing view: $_opts{eastview}");\r
1256   } else {\r
1257     $_log->log ("$FindBin::Script Version " . VERSION_NBR);\r
1258   } # if\r
1259 \r
1260   set_verbose;\r
1261 \r
1262   while () {\r
1263     my $cmd;\r
1264 \r
1265     unless ($_debugging) {\r
1266       $cmd = $_term->readline (PROMPT . RESET);\r
1267     } else {\r
1268       display_nolf PROMPT . RESET;\r
1269 \r
1270       $cmd = <STDIN>;\r
1271     } # if\r
1272 \r
1273     # Handle Control-d\r
1274     unless (defined $cmd) {\r
1275       display "";\r
1276       saveHistory;\r
1277       exit 0;\r
1278     } # if\r
1279 \r
1280     chomp $cmd;\r
1281 \r
1282     next if $cmd eq "";\r
1283 \r
1284     if ($cmd =~ /exit|quit/i) {\r
1285       $_term->remove_history ($_term->where_history);\r
1286       saveHistory;\r
1287       exit 0;\r
1288     } # if\r
1289 \r
1290     if ($cmd =~ /^elock/i) {\r
1291       if ($cmd =~ /^elock\s+(\w+)/i) {\r
1292         eLock $1;\r
1293       } else {\r
1294         eLock;\r
1295       } # if\r
1296 \r
1297       next;\r
1298     } # if\r
1299 \r
1300     my @tokens = split /\s+/, $cmd;\r
1301 \r
1302     $_opts{class}       = shift @tokens;\r
1303     $_opts{test}        = join " ", @tokens;\r
1304 \r
1305     $cmd = lc $_opts{class};\r
1306 \r
1307     if ($cmd eq "help") {\r
1308       help;\r
1309       $_term->remove_history ($_term->where_history) unless $_debugging;\r
1310       next;\r
1311     } elsif ($cmd eq "usage") {\r
1312       usage;\r
1313       $_term->remove_history ($_term->where_history) unless $_debugging;\r
1314       next;\r
1315     } elsif ($cmd eq "version") {\r
1316       display DESC;\r
1317       $_term->remove_history ($_term->where_history) unless $_debugging;\r
1318       next;\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
1324         my $value       = $2;\r
1325 \r
1326         # Remove quotes, if any. Note no check for balancing.\r
1327         $value =~ s/[\"\']//g;\r
1328 \r
1329         # Set option\r
1330         $_opts{$optionName} = $value;\r
1331       } # if\r
1332     } elsif ($cmd eq "get") {\r
1333       if ($_opts{$tokens[0]}) {\r
1334         display "$tokens[0] = $_opts{$tokens[0]}";\r
1335       } else {\r
1336         display "$tokens[0] is not set";\r
1337       } # if\r
1338     } else {\r
1339       $_stats{Run}++;\r
1340       $_opts{class} = lc $_opts{class};\r
1341 \r
1342       if ( $_opts{class} eq "manual" ) {\r
1343         $_opts{test} = " ";\r
1344       } # if\r
1345 \r
1346       executeTestStep;\r
1347     } # if\r
1348   } # while\r
1349 \r
1350   # Disconnect from EAST\r
1351   $_east->disconnect;\r
1352 \r
1353   # Assign 'Failed' and 'Timedout' 0 if they are not initialized\r
1354   $_stats{Failed}   ||= 0;\r
1355   $_stats{Timedout} ||= 0;\r
1356 \r
1357   my $testErrors = $_stats{Failed} + $_stats{Timedout};\r
1358 \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
1361 \r
1362 } # if\r
1363 \r
1364 saveHistory;\r
1365 displaySummary;\r
1366 \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
1373 \r
1374 # Now exit with the correct status\r
1375 exit ($_stats{Failed} + $_stats{Timedout});\r