#!/usr/bin/env perl # IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html use strict; use warnings; use Getopt::Long; use Data::Dumper; use Term::ANSIColor; use Time::Local; use File::Basename; use File::Path; BEGIN { $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : -d '/opt/xcat' ? '/opt/xcat' : '/usr'; } use lib "$::XCATROOT/lib/perl"; my $rootdir = "$::XCATROOT/share/xcat/tools/autotest"; my $needhelp = 0; my $configinfo = undef; my $configfile = undef; my $casedir = "$rootdir/testcase"; my $bundledir = "$rootdir/bundle"; my $resultdir = "$rootdir/result"; my $bundlelist = undef; my $caselist = undef; my $cmdlist = undef; my $showbundlesorcommands = undef; my $needshow = 0; my $restore = 0; my $ret = 0; my $string1 = undef; my $showbundlefiles = 0; my $showcommandslist = 0; my $stop_to_keep_env = 0; #----------------------------------- =head1 System label usage: In order to make install xCAT to be the first case for automation daily regression, "System" label is used in this xcattest command. xcattest -f /opt/xcat/share/xcat/tools/autotest/default.conf:System -t install_xCAT_on_rhels_sles xcattest -f /opt/xcat/share/xcat/tools/autotest/default.conf:System -t install_xCAT_on_ubuntu System label means only the [System] aspect will be loaded and no other inital action will be done. =cut #----------------------------------- my $initallabel = undef; my $loadsysteminfo = "System"; #Create result directory mkdir $resultdir unless -d $resultdir; # create a log for xcattest my $timestamp = `date +"%Y%m%d%H%M%S"`; open(LOG, ">$resultdir/xcattest.log.$timestamp") or die "Can't open logfile for writing: $!"; if ( !GetOptions("h|?" => \$needhelp, "f=s" => \$configinfo, "b=s" => \$bundlelist, "t=s" => \$caselist, "c=s" => \$cmdlist, "s=s" => \$showbundlesorcommands, "l" => \$needshow, "restore" => \$restore) ) { &usage; exit 1; } if ($needhelp) { &usage; exit 0; } if (&checkoptions) { &usage; exit 1; } #show bundle files under $bundledir with .bundle as file suffix my %bundlefilesinfo = (); if ($showbundlefiles) { &listbundlefiles; exit 0; } #show commands, which is the folder name $casedir, with case* files and test cases if ($showcommandslist) { &listcommands; exit 0; } #load case to $cases # key type #$cases[x](x>0): hash # name string # os:AIX/Linux string # arch:ppc64/x386 string # hcp:hmc/mm/bmc/fsp string # cmd: array # check: array my @cases = (); if ($needshow) { &loadcase; exit 0; } # create a log for run test cases &log_this("xCAT automated test started at " . scalar(localtime())); open(LOG_ERR, ">$resultdir/failedcases.$timestamp") or die "Can't open error logfile for writing: $!"; #read config file log_this("******************************"); log_this("Reading Configure"); log_this("******************************"); #config{object}{type}{name}{attr} #config{table}{name}{entry}{key} #config{script_prev}->[] #config{script_post}->[] #config{var}{varname} my %config = (); $ret = &getConfig; if ($ret != 0) { goto EXIT; } #if not only load System aspects from config file, then init test enviroment if (!defined($initallabel)){ log_this("******************************"); log_this("Initialize xCAT test evironment"); log_this("******************************"); $ret = &init; if ($ret != 0) { goto EXIT; } } my @filespath = (); #loading and check cases log_this("******************************"); log_this("loading test cases"); log_this("******************************"); $ret = &loadcase; if ($ret != 0) { goto EXIT; } #run case log_this("******************************"); log_this("Start to run test cases"); log_this("******************************"); &reordercases if (defined($bundlelist) || defined($caselist)); &runcase; EXIT: log_this("******************************"); log_this("un-initialize xCAT test evironment"); log_this("******************************"); if ($restore) { &uninit; } &log_this("\nxCAT automated test finished at " . scalar(localtime())); &log_this("Please check results in the $resultdir, \nand see $resultdir/failedcases.$timestamp file for failed cases.\nsee $resultdir/performance.report.$timestamp file for time consumption"); close(LOG); close(LOG_ERR); my $reportfile = "$resultdir/performance.report.$timestamp"; my $tmpreport = "$resultdir/xcattest.log.$timestamp"; &getreport($tmpreport, $reportfile); if ($stop_to_keep_env) { exit 1; } else { exit 0; } # end main # # logger # sub log_this { print LOG join("\n", @_), "\n"; my $msg = join("\n", @_); if ($msg =~ /\[Pass\]/) { print color("green"), "$msg\n", color("reset"); } elsif ($msg =~ /\[Failed\]/) { print color("red"), "$msg\n", color("reset"); } else { print "$msg\n"; } } sub log_error { print LOG_ERR join("\n", @_), "\n"; } sub include_file { my $file = shift; my $idir = shift; my @text = (); unless ($file =~ /^\//) { $file = $idir . "/" . $file; } open(INCLUDE, $file) || return "#INCLUDEBAD:cannot open $file#"; while () { chomp($_); s/\s+$//; #remove trailing spaces next if /^\s*$/; #-- skip empty lines push(@text, $_); } close(INCLUDE); return join(",", @text); } sub sort_caserange { my @caserange = @_; my $bundletext = join(',', @caserange); #handle the #INLCUDE# tag recursively my $idir = "$rootdir/bundle"; my $doneincludes = 0; while (not $doneincludes) { $doneincludes = 1; if ($bundletext =~ /#INCLUDE:[^#^\n]+#/) { $doneincludes = 0; $bundletext =~ s/#INCLUDE:([^#^\n]+)#/include_file($1,$idir)/eg; } } @caserange=split(",",$bundletext); my @diff; foreach my $case (@caserange) { unless (grep { $_ eq $case } @diff) { push @diff, $case; } } my %index; my @same = grep($index{$_}++, @caserange); my @error =grep /INCLUDEBAD/, @caserange; return (\@diff, \@same, \@error); } sub getConfig { my $type = undef; #Script_Prev,Script_Post,Table,Object,System,Custom my $sub_type = undef; # The string after $type_ # Script--> # Script_Prev # Script_Post # Table---> # Table_xxxxx # Object--> # Object_xxxx # System----> # Custom----> my $name = undef; my $attr = undef; my $value = undef; my $c = 0; my $cmd = undef; my $mgt_name = undef; if (!open(FILE, "$configfile")) { log_this("Error: can't open xCAT config file: $configfile"); return 1; } #Only load System information if (defined($initallabel) && ($initallabel eq $loadsysteminfo)) { while (my $line = ) { $line = &trim($line); next if (length($line) == 0); #Only read System variable if ($line =~ /\[System\]/) { $type = "Varible"; } if (defined($type) && ($type eq "Varible")) { if ($line =~ /(\w+)\s*=\s*([\w\.\-\+\/:]+)/) { $config{var}{$1} = $2; } } } }else{ #Load all config files information while (my $line = ) { $line = &trim($line); next if (length($line) == 0); #Table name can not contain "_" if ($line =~ /\[\s*(\w+)\_(\w+)\s*\]/) { $type = $1; $sub_type = $2; $name = undef; $c = 0; } elsif ($line =~ /\[\s*System|Custom\s*\]/) { $type = "Varible"; } elsif ($type eq "Table") { ##TABLE BLOCK## if ($line =~ /(\w+)\s*=\s*([\w\.\-]+)/) { $attr = $1; $value = $2; if ($name && ($config{table}{$sub_type}{$name}{__KEY__} ne $attr)) { $config{table}{$sub_type}{$name}{$attr} = $value; } else { $name = $value; $config{table}{$sub_type}{$name}{__KEY__} = $attr; } } } elsif ($type eq "Object") { ##OBJECT BLOCK## if ($line =~ /(\w+)\s*=\s*([:\w\.\-\/]+)/) { $attr = $1; $value = $2; if ($attr eq "Name") { $name = $value; } elsif (!defined($name)) { print "Please give name for Object\n"; close FILE; return 1; } else { $config{object}{$sub_type}{$name}{$attr} = $value; } } } elsif ($type eq "Script") { ##SCRIPT_BLOCK## if ($sub_type eq "Prev") { $config{script_prev}->[$c] = $line; $c = $c + 1; } elsif ($sub_type eq "Post") { $config{script_post}->[$c] = $line; $c = $c + 1; } } elsif ($type eq "Varible") { ##NODE_BLOCK## if ($line =~ /(\w+)\s*=\s*([\w\.\-\+\/:]+)/) { $config{var}{$1} = $2; } } } } if (exists $config{object}) { foreach my $type (keys %{ $config{object} }) { foreach my $name (keys %{ $config{object}{$type} }) { log_this("OBJECT:$name,TYPE:$type"); foreach my $attr (keys %{ $config{object}{$type}{$name} }) { log_this(" $attr = $config{object}{$type}{$name}{$attr};"); } } } } if (exists $config{table}) { foreach my $type (keys %{ $config{table} }) { log_this("TABLE:$type"); foreach my $name (keys %{ $config{table}{$type} }) { log_this(" $config{table}{$type}{$name}{__KEY__} = $name"); foreach my $attr (keys %{ $config{table}{$type}{$name} }) { if ($attr ne '__KEY__') { log_this(" $attr = $config{table}{$type}{$name}{$attr}"); } } log_this("\n"); } } } if (exists $config{script_prev}) { log_this("Script_Prev:"); foreach $cmd (@{ $config{script_prev} }) { log_this(" $cmd"); } } if (exists $config{script_post}) { log_this("Script_Post:"); foreach $cmd (@{ $config{script_post} }) { log_this(" $cmd"); } } if (exists $config{var}) { log_this("Varible:"); foreach my $varname (keys %{ $config{var} }) { log_this(" $varname = $config{var}{$varname}"); } } close FILE; return 0; } sub init { if ($restore) { log_this("******************************"); log_this("Backup current xCAT database"); log_this("******************************"); &runcmd("mkdir -p /tmp/xCATdbbackup"); &runcmd("dumpxCATdb -p /tmp/xCATdbbackup"); if ($::RUNCMD_RC != 0) { &log_this("Fail to backup xCAT database"); &runcmd("rm -rf /tmp/xCATdbbackup"); $restore = 0; return 1; } } my $cmd = undef; foreach $cmd (@{ $config{script_prev} }) { log_this("$cmd"); &runcmd($cmd); if ($::RUNCMD_RC != 0) { &log_this("Fail to run $cmd"); return 1; } } if (exists $config{object}) { foreach my $type (keys %{ $config{object} }) { foreach my $name (keys %{ $config{object}{$type} }) { $cmd = "chdef -t $type -o $name"; foreach my $attr (keys %{ $config{object}{$type}{$name} }) { $cmd = $cmd . " $attr=$config{object}{$type}{$name}{$attr}"; } log_this($cmd); runcmd($cmd); if ($::RUNCMD_RC != 0) { log_this("Fail to run $cmd"); return 1; } } } } if (exists $config{table}) { foreach my $type (keys %{ $config{table} }) { foreach my $name (keys %{ $config{table}{$type} }) { $cmd = "chtab $config{table}{$type}{$name}{__KEY__}=$name"; foreach my $attr (keys %{ $config{table}{$type}{$name} }) { if ($attr ne '__KEY__') { $cmd = $cmd . " $type.$attr=$config{table}{$type}{$name}{$attr}"; } } log_this($cmd); &runcmd($cmd); if ($::RUNCMD_RC != 0) { &log_this("Fail to run $cmd"); return 1; } } } } if (!exists $config{var}{OS}) { my @output = runcmd("uname"); $config{var}{OS} = $output[0]; log_this("Detecting: OS = $config{var}{OS}"); } else { $config{var}{OS} = lc($config{var}{OS}); } if (!exists $config{var}{ARCH}) { if (!exists $config{var}{CN}) { $config{var}{ARCH} = "Unknown"; log_this("Error: No compute node defined, can't get ARCH of compute node"); } else { $config{var}{ARCH} = getnodeattr($config{var}{CN}, "arch"); if ($config{var}{ARCH} =~ /ppc/) { $config{var}{ARCH} = 'ppc'; } elsif ($config{var}{ARCH} =~ /86/) { $config{var}{ARCH} = 'x86'; } log_this("Detecting: ARCH = $config{var}{ARCH}"); } } if (!exists $config{var}{HCP}) { if (!exists $config{var}{CN}) { $config{var}{HCP} = "Unknown"; log_this("Error: No compute node defined, can't get HCP TYPE of compute node"); } else { $config{var}{HCP} = getnodeattr($config{var}{CN}, "mgt"); log_this("Detecting: HCP = $config{var}{HCP}"); } } return 0; } sub uninit { my $cmd = undef; # if(exists $config{object}){ # foreach my $type (keys %{$config{object}}){ # foreach my $name (keys %{$config{object}{$type}}){ # $cmd = "rmdef -t $type -o $name"; # log_this($cmd); # runcmd($cmd); # if($::RUNCMD_RC != 0){ # log_this("Fail to run $cmd"); # return 1; # } # } # } # } # if(exists $config{table}){ # foreach my $type (keys %{$config{table}}){ # foreach my $name (keys %{$config{table}{$type}}){ # $cmd = "chtab -d $config{table}{$type}{$name}{__KEY__}=$name $type"; # log_this($cmd); # runcmd($cmd); # if($::RUNCMD_RC != 0){ # log_this("Fail to run $cmd"); # return 1; # } # } # } # } foreach $cmd (@{ $config{script_post} }) { log_this($cmd); runcmd($cmd); if ($::RUNCMD_RC != 0) { log_this("Error: Fail to run $cmd"); return 1; } } &runcmd("restorexCATdb -p /tmp/xCATdbbackup"); &runcmd("rm -rf /tmp/xCATdbbackup"); return 0; } sub Get_Files_Recursive { my $dir = $_[0]; foreach $dir (@_) { opendir(my $d, $dir); for (; ;) { my $direntry = readdir($d); last unless defined $direntry; next if $direntry =~ m/^\.\w*/; next if $direntry eq '..'; if (-d $dir . "/" . $direntry) { Get_Files_Recursive($dir . "/" . $direntry); } else { my $dirpath = $dir . '/' . $direntry . "\n"; #print $dirpath; #print $dir."\n"; push(@filespath, glob("$dirpath")); } } closedir($d); } } sub loadcase { my @files = (); #if($cmdlist){ # my @cmds = split /,/,$cmdlist; # for my $cmd (@cmds){ # push (@files, glob("$casedir/$cmd/*")); # } #} else { # @files = glob("$casedir/*/*"); #} Get_Files_Recursive("$casedir"); for (my $countfile = 0 ; $countfile < @filespath ; $countfile++) { #TODO:if commands are not right, no action or message now if ($cmdlist) { my @cmds = split /,/, $cmdlist; for (my $countcmd = 0 ; $countcmd < @cmds ; $countcmd++) { if ($filespath[$countfile] =~ m/\/$cmds[$countcmd]\/case/) { push(@files, glob("$filespath[$countfile]")); } } } else { push(@files, glob("$filespath[$countfile]")); } } my $file; my $line; my $i = 0; my $j = -1; my $z = 0; my $skip = 0; my @caserange = (); my @rightcase = (); my @notrightcase = (); my @wrongnamecase= (); my @samecase = (); my @errorcase = (); if ($bundlelist) { my @bundles = split /,/, $bundlelist; foreach my $bundle (@bundles) { if (!open(FILE, "<$bundledir/$bundle")) { log_this("can't open $bundledir/$bundle"); return 1; } while ($line = ) { chomp($line); next if (length($line) == 0); push(@caserange, $line); } close(FILE); my @refs=sort_caserange(@caserange); @caserange=@{$refs[0]}; @samecase=@{$refs[1]}; @errorcase=@{$refs[2]}; } } #TODO:if cases are not existed, no action or message. if ($caselist) { @caserange = split /,/, $caselist; } foreach $file (@files) { if (!open(FILE, "<$file")) { log_this("can't open $file"); return 1; } while ($line = ) { $line = &trim($line); next if (length($line) == 0); #skip comment lines next if ($line =~ /^\s*#/); #TODO: description line is treated as a comment line for now next if ($line =~ /^description\s*:/); if ($line =~ /^start\s*:\s*(.*)/) { my $name =$1; if ($name =~ /[^a-zA-Z0-9_-]/) { $skip = 1; push(@wrongnamecase, $name); next; }else { $skip = 0; if ($caserange[0] && !(grep { /^$name$/ } @caserange)) { $skip = 1; next; } $j = -1; $cases[$i] = {}; $cases[$i]->{name} = $name; $cases[$i]->{filename} = $file; if (!$needshow) { $cases[$i]->{cmd} = []; $cases[$i]->{check} = []; $cases[$i]->{cmdcheck} = []; push(@rightcase, $name); } else { $skip = 1; $i = $i + 1; } } } elsif ($line =~ /^os\s*:\s*(\w[\w\,]+)/) { next if $skip; $string1 = $1; if ($string1 =~ /^rhels\s*/ && -f "/etc/redhat-release") { $cases[$i]->{os} = "rhels"; } elsif ($string1 =~ /^sles\s*/ && -f "/etc/SuSE-release") { $cases[$i]->{os} = "sles"; } elsif ($string1 =~ /^ubuntu\s*/ && -f "/etc/lsb-release") { $cases[$i]->{os} = "ubuntu"; } else { $cases[$i]->{os} = $string1; } chomp($cases[$i]->{os}); chomp($config{var}{OS}); if ($cases[$i]->{os} !~ /$config{var}{OS}/) { if ((($config{var}{OS} =~ /^Linux\s*/i) && ($cases[$i]->{os} =~ /^aix\s*/i)) || (($config{var}{OS} =~ /^aix\s*/i) && ($cases[$i]->{os} !~ /^aix\s*/i)) || (($config{var}{OS} =~ /^rhels\s*/i) && ($cases[$i]->{os} !~ /^Linux\s*/i)) || (($config{var}{OS} =~ /^sles\s*/i) && ($cases[$i]->{os} !~ /^Linux\s*/i)) || (($config{var}{OS} =~ /^ubuntu\s*/i) && ($cases[$i]->{os} !~ /^Linux\s*/i))) { push(@notrightcase, $cases[$i]->{name}); pop(@rightcase); $skip = 1; } } } elsif ($line =~ /^arch\s*:\s*(\w[\w\,]+)/) { next if $skip; $cases[$i]->{arch} = $1; if ($cases[$i]->{arch} !~ /$config{var}{ARCH}/) { push(@notrightcase, $cases[$i]->{name}); pop(@rightcase); $skip = 1; } } elsif ($line =~ /^hcp\s*:\s*(\w[\w\,]+)/) { next if $skip; $cases[$i]->{hcp} = $1; if ($cases[$i]->{hcp} !~ /$config{var}{HCP}/) { push(@notrightcase, $cases[$i]->{name}); pop(@rightcase); $skip = 1; } } elsif ($line =~ /^type\s*:\s*(\w[\w\,-]+)/) { next if $skip; $cases[$i]->{type} = $1; if ($cases[$i]->{type} !~ /$config{var}{TYPE}/) { push(@notrightcase, $cases[$i]->{name}); pop(@rightcase); $skip = 1; } } elsif ($line =~ /^stop\s*:\s*(\w[\w\,]+)/) { next if $skip; $cases[$i]->{stop} = $1; } elsif ($line =~ /^cmd\s*:\s*([\/\$\w].+)/) { next if $skip; $j = $j + 1; $z = 0; $cases[$i]->{cmd}->[$j] = &getvar($1); if ($cases[$i]->{cmd}->[$j] eq '') { close(FILE); return 1; } } elsif ($line =~ /^check\s*:\s*(\w.+)/) { next if $skip; $cases[$i]->{check}->[$j][$z] = &getvar($1); if ($cases[$i]->{check}->[$j][$z] eq '') { close(FILE); return 1; } $z = $z + 1; } elsif ($line =~ /^cmdcheck\s*:\s*(\w.+)/) { next if $skip; $cases[$i]->{cmdcheck}->[$j][$z] = &getvar($1); if ($cases[$i]->{cmdcheck}->[$j][$z] eq '') { close(FILE); return 1; } $z = $z + 1; } elsif ($line =~ /^end/) { next if $skip; $i = $i + 1; } } close(FILE); } if ($needshow) { if (@cases) { foreach my $case (@cases) { log_this("$case->{name}"); } }else { log_this("Error: Please check the case name or command name"); } log_this("Case name not supported:", @wrongnamecase) if (@wrongnamecase); return 0; } if (@rightcase) { log_this("To run:", @rightcase); }else { log_this("Error: No case to run, please check the case name or command name"); } log_this("Not to run:", @notrightcase) if (@notrightcase); log_this("Duplicated case:", @samecase) if (@samecase); log_this("INCLUDEBAD case:", @errorcase) if (@errorcase); log_this("Case name not supported:", @wrongnamecase) if (@wrongnamecase); return 0; } sub getnodeattr { my ($node, $attr) = @_; my @output = runcmd("lsdef -t node -o $node -i $attr"); my $t; if ($::RUNCMD_RC) { # return "Unknown"; foreach $t (1 .. 40) { log_this("Error: could not get node attr $attr "); @output = runcmd("lsdef -t node -o $node -i $attr"); last if ($::RUNCMD_RC == 0); } } if ($::RUNCMD_RC == 0) { foreach my $output1 (@output) { if ($output1 =~ /$attr=(\w.+)/) { log_this("$attr is $1"); return $1; } } } return "Unknown"; } sub gettablevalue { my ($keyname, $key, $colname, $table) = @_; my @output = runcmd("gettab $keyname=$key $table\.$colname"); return $output[0]; } #to remove space and comment sub trim { my $str = shift @_; if ($str) { # $str =~ s/\#/__wellnumber__/g; $str =~ s/^\s+|#.+|\s+$//g; # $str =~ s/__wellnumber__/#/g; } return $str; } sub getvar { my $str = shift @_; while ($str =~ /\$\$(\w+)/) { my $varname = $1; if (exists($config{var}{$varname})) { $str =~ s/\$\$$varname/$config{var}{$varname}/g; } else { log_this("Error: can't get varible $varname"); return ''; } } return $str; } sub getfunc { my $str = shift @_; my $func = undef; my @para = (); my $parameter = undef; my $value = undef; while ($str =~ /__(\w+)\(([\s\,\w\$]*)\)__/) { $func = $1; $parameter = $2; log_this("parameter is $parameter,fun is $func"); @para = split /\s*,\s*/, trim($parameter); if ($func eq "GETNODEATTR") { $value = getnodeattr(@para); log_this("value is $value"); if ($value eq "Unknown") { $value = ''; } } elsif ($func eq "INC") { $value = $para[0] + 1; } elsif ($func eq "GETTABLEVALUE") { $value = gettablevalue(@para); } $str =~ s/__$func\($parameter\)__/$value/g; } return $str; } sub runcase { my @output = (); my $rc = 0; my $j = 0; my $z = 0; my $lvalue = undef; my $rvalue = undef; my $op = undef; my $failed = 0; my $total = 0; my $failnum = 0; foreach my $case (@cases) { my @record = (); $failed = 0; $j = 0; $total = $total + 1; my $now1 = timelocal(localtime()); my $time1 = scalar(localtime()); log_this("------START:$$case{name}::Time:$time1------"); push @record, "------START:$$case{name}::Time:$time1------"; push @record, "FILENAME:$$case{filename}"; foreach my $cmd (@{ $$case{cmd} }) { $cmd = getfunc($cmd); #by my $runstart = timelocal(localtime()); log_this("\nRUN:$cmd"); push(@record, "\nRUN:$cmd"); @output = &runcmd($cmd); $rc = $::RUNCMD_RC; #by my $runstop = timelocal(localtime()); my $diffduration = $runstop - $runstart; log_this("\n[$cmd] Running Time:$diffduration sec"); push(@record, ("\n[$cmd] Running Time:$diffduration sec")); log_this("RETURN: rc = $rc", "OUTPUT:", @output); push(@record, ("RETURN rc = $rc", "OUTPUT:", @output)); foreach my $check (@{ $$case{check}->[$j] }) { if ($failed) { last; } if ($check =~ /rc\s*([=!]+)\s*(\d+)/) { $lvalue = $rc; $op = $1; $rvalue = $2; if ((($op eq '!=') && ($lvalue == $rvalue)) || (($op eq '==') && ($lvalue != $rvalue))) { $failed = 1; } if ($failed) { log_this("CHECK:rc $op $rvalue\t[Failed]"); push(@record, "CHECK:rc $op $rvalue\t[Failed]"); last; } else { log_this("CHECK:rc $op $rvalue\t[Pass]"); push(@record, "CHECK:rc $op $rvalue\t[Pass]"); } } elsif ($check =~ /output\s*([=!~]+)\s*(\S.*)/ && $check !~ /output\s*([=!~])\1/) { $lvalue = join("\n", @output); $op = $1; $rvalue = $2; $rvalue = getfunc($rvalue); if ((($op eq '=~') && ($lvalue !~ /$rvalue/)) || (($op eq '!~') && ($lvalue =~ /$rvalue/)) || (($op eq '==') && ($lvalue ne $rvalue)) || (($op eq '!=') && ($lvalue eq $rvalue))) { $failed = 1; } if ($failed) { log_this("CHECK:output $op $rvalue\t[Failed]"); push(@record, "CHECK:output $op $rvalue\t[Failed]"); last; } else { log_this("CHECK:output $op $rvalue\t[Pass]"); push(@record, "CHECK:output $op $rvalue\t[Pass]"); } } elsif ($check =~ /output\s*~~\s*(\S.*)/) { $op = "~~"; $failed = 1; $rvalue = $1; $rvalue = getfunc($rvalue); my $num; if ($rvalue =~ /(\d+)/) { $num = $1; } $rvalue =~ s/(\d+)//; foreach my $line (@output) { chomp($line); if ($line =~ /$rvalue/) { if ($num =~ /^\d+$/) { my $max = $num * 1.1; my $min = $num * 0.9; $line =~ /.*:.*: (\d+) /; if ($1 < $max && $1 > $min) { $failed = 0; last; } } else { next; } } } if ($failed) { log_this("CHECK:output $op $rvalue $num\t[Failed]"); push(@record, "CHECK:output $op $rvalue\t[Failed]"); last; } else { log_this("CHECK:output $op $rvalue $num\t[Pass]"); push(@record, "CHECK:output $op $rvalue\t[Pass]"); } } } foreach my $cmdcheck (@{ $$case{cmdcheck}->[$j] }) { if ($cmdcheck) { &runcmd($cmdcheck); $rc = $::RUNCMD_RC; if ($rc == 1) { log_this("CMDCHECK:output $cmdcheck\t[Failed]"); push(@record, "CHECK:output $cmdcheck\t[Failed]"); } elsif ($rc == 0) { log_this("CMDCHECK:output $cmdcheck\t[Pass]"); push(@record, "CHECK:output $cmdcheck\t[Pass]"); } } } $j = $j + 1; } my $now2 = timelocal(localtime()); my $time2 = scalar(localtime()); my $diff = $now2 - $now1; if ($failed) { log_this("------END::$$case{name}::Failed::Time:$time2 ::Duration::$diff sec------"); push(@record, "------END::$$case{name}::Failed::Time:$time2 ::Duration::$diff sec------"); } else { log_this("------END::$$case{name}::Passed::Time:$time2 ::Duration::$diff sec------"); push(@record, "------END::$$case{name}::Passed::Time:$time2 ::Duration::$diff sec------"); } if ($failed) { $failnum = $failnum + 1; log_error(@record); if (defined($$case{stop}) && ($$case{stop} =~ /^yes$/)) { $stop_to_keep_env = 1; last; } } } log_this("\n\n"); log_this("------Total: $total , Failed: $failnum------"); } sub runcmd { my ($cmd) = @_; my $rc = 0; $::RUNCMD_RC = 0; my $outref = []; @$outref = `$cmd 2>&1`; if ($?) { $rc = $?; $rc = $rc >> 8; $::RUNCMD_RC = $rc; } chomp(@$outref); return @$outref; } sub usage { log_this("Usage:Run xcat test cases:"); log_this(" xcattest [-?|-h]"); log_this(" xcattest [-f configure file] [-b case bundle files]"); log_this(" xcattest [-f configure file] [-t cases list]"); log_this(" xcattest [-f configure file] [-c cmds list]"); log_this("Show xcat test cases, bundle files, commands lists:"); log_this(" xcattest [-b case bundle files] [-l]"); log_this(" xcattest [-t cases list] [-l]"); log_this(" xcattest [-c cmds list] [-l]"); log_this("Show all bundle files, all commands:"); log_this(" xcattest [-s command|bundle]"); log_this(""); return; } sub listbundlefiles { my @bundlefiles = (); #get all .bundle files from /opt/xcat/share/xcat/tools/autotest/bundle/ opendir(DIR, $bundledir); my @files = readdir(DIR); foreach my $file (@files){ next if (-d $file); if ($file =~ /\.bundle$/){ push(@bundlefiles, $file); } } closedir(DIR); #read all .bundle files, get descriptions for each file. my $skip =0; my $line; foreach my $bundlefile (@bundlefiles) { if (!open(FILE, "<$bundledir/$bundlefile")) { log_this("Error: Can't open bundle file: $bundlefile"); log_this("Use 'xcattest -s bundle' to list out available bundles"); return 1; } $skip = 0; while ($line = ) { $line = &trim($line); next if (length($line) == 0); #description line is treated as a comment line for now if ($line =~ /^description\s*:\s*(.*)/){ if (length($1) != 0) { $bundlefilesinfo{$bundlefile} = $1; $skip=1; last; } } } close(FILE); if (!$skip){ $bundlefilesinfo{$bundlefile} = "No description, add with \"description: details\" in bundle file"; } } &listformatbundleinfo(%bundlefilesinfo); return 0; } sub listformatbundleinfo { my $maxlen = 0; foreach my $filename (keys %bundlefilesinfo) { $maxlen = length($filename) if (length($filename) > $maxlen); } $maxlen += 4; my $desiredwidth = 120; my $screenwidth = (`tput cols` + 0); my $finallen = ($screenwidth > $desiredwidth ? $desiredwidth : $screenwidth); print "bundle files and descriptions:\n"; foreach my $filename (sort { $a cmp $b } keys %bundlefilesinfo ) { my @desc = split(" ", $bundlefilesinfo{$filename}); my $str = ""; my @formatdesc = (); foreach my $word (@desc) { if (length($str) + length($word) > $finallen - $maxlen) { $str =~ s/([^\s]+)\s$/$1/g; push @formatdesc, $str; $str = ""; } $str .= $word . " "; } $str =~ s/([^\s]+)\s$/$1/g; push @formatdesc, $str; print "$filename"; my $space = " " x ($maxlen - length($filename)); print "$space$formatdesc[0]\n"; delete $formatdesc[0]; $space = " " x $maxlen; foreach my $line (@formatdesc) { print "$space$line\n" if (length($line)); } } } sub listcommands { my @files = (); Get_Files_Recursive("$casedir"); for (my $countfile = 0 ; $countfile < @ filespath ; $countfile++) { if ($filespath[$countfile] =~ /testcase\/(.*)\/case/) { log_this("$1"); } } } sub getreport { open(INDOC, ">$_[1]") || die("open STDOUT failed"); print INDOC "Testcase Duration\n"; print INDOC "------------------------------------------------------------------------------\n"; close(INDOC); open(STDOUT, ">>$_[1]") || die("open STDOUT failed"); open FD, "<$_[0]" or die "$?"; while () { if (/Time/) { s/------//g; $_ .= "\n" if /END/; print STDOUT $_; } } close(FD); close(STDOUT); } sub reordercases { my @caserange = (); my $line; if ($bundlelist) { my @bundles = split /,/, $bundlelist; foreach my $bundle (@bundles) { if (!open(FILE, "<$bundledir/$bundle")){ log_this("Error: Can't open bundle file: $bundle"); return 1; } while ($line = ) { chomp($line); next if ((length($line) == 0) || ($line =~ /^description\s*:\s*(.*)/)); push(@caserange, $line); } close(FILE); my @refs=sort_caserange(@caserange); @caserange=@{$refs[0]}; } } if ($caselist) { @caserange = split /,/, $caselist; } my @tmpcases = (); foreach my $case (@caserange) { my $i = 0; my $hit = 0; foreach my $runcase (@cases) { if ($runcase->{name} eq $case) { $hit = 1; last; } $i++; next; } push(@tmpcases, $cases[$i]) if ($hit); } @cases = @tmpcases; } sub checkoptions { #-b,-c,-t,-s should be defined at least one if (!defined($bundlelist) && !defined($caselist) && !defined($cmdlist) && !defined($showbundlesorcommands)) { log_this("Error: please define options correctly, see below usage information:"); return 1; }elsif ((defined($bundlelist) || defined($caselist) || defined($cmdlist)) && (! $needshow) && !defined($configinfo)) { #config file must be defined if the using -c,-b,-t to run test cases log_this("Error: To run test cases, please define the config file with -f option"); log_this(" To show test cases, please use the -l option"); return 1; }elsif (defined($showbundlesorcommands) && (defined($bundlelist) || defined($caselist) || defined($cmdlist))) { #-s can't be used together with -c,-b,-t log_this("Error: -b,-c or -t can't be used together with -s"); return 1; }elsif (defined($showbundlesorcommands) && $needshow) { log_this("Error: -s, -l can't be used together"); return 1; } #check the -s option, the value should be bundle or command if (defined($showbundlesorcommands)) { if (($showbundlesorcommands ne "bundle") && ($showbundlesorcommands ne "command")) { log_this("Error: please use \"bundle\" or \"command\" as the \-s value"); return 1; }elsif ($showbundlesorcommands eq "bundle") { $showbundlefiles = 1; }else { } $showcommandslist= 1; } #get and check config file and System label #this System label means only the [System] variable will be loaded if (defined($configinfo)) { if ($configinfo =~ /(.*):(.*)/) { $configfile = $1; $initallabel = $2; if ($initallabel ne $loadsysteminfo) { log_this("Error: $initallabel is not supported!"); return 1; } }else { $configfile = $configinfo; } if (!(-e $configfile)) { log_this("Error: Can't open config file: $configfile"); return 1; } } #check bundle files if (defined($bundlelist)) { my @bundles = split /,/, $bundlelist; foreach my $bundle (@bundles){ if ("$bundledir/$bundle" !~ /\.bundle$/) { log_this("Error: please input the .bundle file"); log_this("Use 'xcattest -s bundle' to list all bundle files"); return 1; } if (!(-e "$bundledir/$bundle")) { log_this("Error: Can't open bundle file: $bundle"); log_this("Use 'xcattest -s bundle' to list all bundle files"); return 1; } } } return 0; }