File Coverage

blib/lib/Tapper/TestSuite/AutoTest.pm
Criterion Covered Total %
statement 40 235 17.0
branch 0 64 0.0
condition 0 34 0.0
subroutine 14 27 51.8
pod n/a
total 54 360 15.0


line stmt bran cond sub pod time code
1             package Tapper::TestSuite::AutoTest;
2             # git description: v4.1.1-1-gdd3439b
3              
4             BEGIN {
5 1     1   23411 $Tapper::TestSuite::AutoTest::AUTHORITY = 'cpan:TAPPER';
6             }
7             {
8             $Tapper::TestSuite::AutoTest::VERSION = '4.1.2';
9             }
10             # ABSTRACT: Tapper - Complete OS testing in a box via autotest
11              
12 1     1   9 use warnings;
  1         1  
  1         26  
13 1     1   5 use strict;
  1         8  
  1         32  
14 1     1   22 use 5.010;
  1         3  
  1         36  
15              
16 1     1   5 use Cwd;
  1         1  
  1         71  
17 1     1   123199 use Moose;
  1         814087  
  1         11  
18 1     1   10376 use Getopt::Long qw/GetOptions/;
  1         13684  
  1         8  
19 1     1   8327 use Sys::Hostname qw/hostname/;
  1         1524  
  1         79  
20 1     1   930 use YAML::Syck;
  1         3370  
  1         99  
21 1     1   5086 use Archive::Tar;
  1         389944  
  1         92  
22 1     1   1662 use IO::Socket::INET;
  1         26450  
  1         13  
23 1     1   4120 use File::Slurp qw/slurp/;
  1         37983  
  1         131  
24 1     1   1195 use File::Spec::Functions 'tmpdir';
  1         1155  
  1         89  
25 1     1   9 use Digest::MD5 'md5_hex';
  1         2  
  1         4873  
26              
27             with 'MooseX::Log::Log4perl';
28              
29              
30             sub makedir
31             {
32 0     0     my ($self, $dir) = @_;
33 0 0         return 0 if -d $dir;
34 0 0 0       if (-e $dir and not -d $dir) {
35 0           unlink $dir;
36             }
37 0 0         system("mkdir","-p",$dir) == 0 or return "Can't create $dir:$!";
38 0           return 0;
39             }
40              
41              
42             sub log_and_system {
43 0     0     my ($self, @args) = @_;
44 0           $self->log->debug(join(" ", @args));
45 0           system(@args);
46             }
47              
48              
49             sub log_and_system_shell {
50 0     0     my ($self, @args) = @_;
51 0           $self->log->debug(join(" ", @args));
52 0           system(join(" ", @args));
53             }
54              
55              
56             sub copy_client
57             {
58 0     0     my($self, $downloaddir, $target) = @_;
59 0           my ($error, $output);
60 0           `which rsync`;
61 0 0         if ( $? == 0) {
62 0           ($error, $output) = $self->log_and_system_shell("rsync",
63             "-a",
64             "$downloaddir/*autotest*/",
65             "$target/");
66             } else {
67 0 0         die "Target dir '$target' does not exist\n" if not -d $target;
68 0           ($error, $output) = $self->log_and_system_shell("cp","-r","$downloaddir/*autotest*/*","$target/");
69             }
70 0 0         die $output if $error;
71 0           return;
72             }
73              
74              
75              
76             sub install
77             {
78 0     0     my ($self, $args) = @_;
79 0           my $error;
80             my $output;
81              
82 0           my $tmp = tmpdir;
83 0           my $source = $args->{source};
84 0   0       my $user = $ENV{USER} || 'unknown';
85 0           my $checksum = substr(md5_hex($source), 0,7);
86 0   0       my $target = $args->{target} || "$tmp/tapper-testsuite-autotest-client-$user-$checksum";
87 0           my $downloaddir = "$tmp/tapper-testsuite-autotest-mirror-$user-$checksum";
88              
89 0           $self->makedir($target);
90 0           $self->makedir($downloaddir);
91              
92 0           my $downloadfile;
93 0 0         if (! -d "$target/tests") {
94 0 0         if ($source =~ m,^(http|ftp)://, ) {
    0          
95 0           $downloadfile = "$downloaddir/autotest-download-$checksum.tgz";
96 0 0         if (! -e $downloadfile) {
97 0           $self->log->debug( "Download autotest from $source to $downloadfile");
98 0           ($error, $output) = $self->log_and_system('wget', "--no-check-certificate",
99             $source, "-O", $downloadfile);
100 0 0         die $output if $error;
101             }
102             } elsif ($source =~ m,^file://,) {
103 0           $downloadfile = $source;
104 0           $downloadfile =~ s,^file://,,;
105             } else {
106 0           $downloadfile = $source;
107             }
108 0           $self->log->debug( "Unpack autotest from file $downloadfile to subdir $downloaddir");
109 0           ($error, $output) = $self->log_and_system("tar",
110             "-xzf", $downloadfile,
111             "-C", $downloaddir);
112 0 0         die $output if $error;
113 0           $self->copy_client($downloaddir, $target);
114 0 0         die $output if $error;
115             }
116 0           $args->{target} = $target;
117 0           return $args;
118             }
119              
120              
121              
122             sub report_away
123             {
124 0     0     my ($self, $args) = @_;
125 0           my $result_dir = $args->{result_dir};
126 0           my $gzipped_content = slurp("$result_dir/tap.tar.gz");
127              
128 0           my $sock = IO::Socket::INET->new(PeerAddr => $args->{report_server},
129             PeerPort => $args->{report_port},
130             Proto => 'tcp');
131 0   0       $self->log->debug("Report to ".($args->{report_server} // "report_server=UNDEF").":".($args->{report_port} // "report_port=UNDEF"));
      0        
132 0 0         unless ($sock) {
133 0           $self->log->error( "Result TAP in $result_dir/tap.tar.gz can not be sent to Tapper server.");
134 0   0       die "Can't open connection to ", ($args->{report_server} // "report_server=UNDEF"), ":", ($args->{report_port} // "report_port=UNDEF"), ":$!"
      0        
135             }
136              
137 0           my $report_id = <$sock>;
138 0           ($report_id) = $report_id =~ /(\d+)$/;
139 0           $sock->print($gzipped_content);
140 0           $sock->close();
141 0           $self->log->debug( "Report $report_id (http://".$args->{report_server}."/tapper/reports/id/$report_id)");
142 0           return $report_id;
143             }
144              
145              
146             sub upload_files
147             {
148 0     0     my ($self, $report_id, $test, $args) = @_;
149              
150 0           my $host = $args->{reportserver};
151 0           my $port = $args->{reportport};
152 0           my $result_dir = $args->{result_dir};
153              
154             # Currently no upload for these (personal taste, privacy, too big):
155             #
156             # sysinfo/installed_packages
157             #
158 0           my @files = ();
159 0           push @files, (qw( status
160             control
161             sysinfo/cmdline
162             sysinfo/cpuinfo
163             sysinfo/df
164             sysinfo/dmesg.gz
165             sysinfo/gcc_--version
166             sysinfo/hostname
167             sysinfo/interrupts
168             sysinfo/ld_--version
169             sysinfo/lspci_-vvn
170             sysinfo/meminfo
171             sysinfo/modules
172             sysinfo/mount
173             sysinfo/partitions
174             sysinfo/proc_mounts
175             sysinfo/slabinfo
176             sysinfo/uname
177             sysinfo/uptime
178             sysinfo/version
179             ));
180 0           my @iterations = map { chomp; $_ } `cd $result_dir ; find $test/sysinfo -name 'iteration.*'`;
  0            
  0            
181 0           foreach my $iteration (@iterations) {
182 0           push @files, map { "$iteration/$_" } (qw( interrupts.before
  0            
183             interrupts.after
184             meminfo.before
185             meminfo.after
186             schedstat.before
187             schedstat.after
188             slabinfo.before
189             slabinfo.after
190             ));
191             }
192 0           foreach my $shortfile (@files) {
193 0           my $file = "$result_dir/$shortfile";
194 0 0         next unless -e $file;
195              
196             # upload uncompressed dmesg for easier inline reading
197 0 0         if ($file =~ m/dmesg.gz$/) {
198 0 0         system("gunzip $file") or do {
199 0           $file =~ s/\.gz$//;
200 0           $shortfile =~ s/\.gz$//;
201             }
202             }
203              
204 0           my $cmdline = "#! upload $report_id $shortfile plain\n";
205 0           my $content = slurp($file);
206 0           my $sock = IO::Socket::INET->new(PeerAddr => $args->{report_server},
207             PeerPort => $args->{report_api_port},
208             Proto => 'tcp');
209 0   0       $self->log->debug("Upload '$shortfile' to ".($args->{report_server} // "report_server=UNDEF").":".($args->{report_api_port} // "report_api_port=UNDEF"));
      0        
210 0 0         unless ($sock) {
211 0           $self->log->error( "Result file '$file' can not be sent to Tapper server.");
212 0   0       die "Can't open connection to ", ($args->{report_server} // "report_server=UNDEF"), ":", ($args->{report_api_port} // "report_api_port=UNDEF"), ":$!"
      0        
213             }
214 0           $sock->print($cmdline);
215 0           $sock->print($content);
216 0           $sock->close();
217             }
218 0           return;
219             }
220              
221              
222             sub get_machine_name
223             {
224 0     0     my $etc_tapper = "/etc/tapper";
225              
226 0           my $hostname = hostname();
227 0           $hostname =~ s/\..*$//; # no FQDN
228             # combined machine name in Tapper automation guest environment
229 0 0         if ($ENV{TAPPER_HOSTNAME}) {
    0          
230 0           $hostname = "$ENV{TAPPER_HOSTNAME}:$hostname"
231             } elsif ( -r $etc_tapper ) {
232 0           my @tapper_config = ();
233 0           my $TAPPERCFG;
234 0 0         open $TAPPERCFG, "<", $etc_tapper and do {
235 0           local $/;
236 0           @tapper_config = <$TAPPERCFG>;
237 0           close $TAPPERCFG;
238             };
239 0           my ($machinename) =
240             map {
241 0           my $m = $_ ; $m =~ s/^[^:]*:// ; $m
  0            
  0            
242             }
243             grep {
244 0           /hostname:/
245             } @tapper_config;
246 0           $hostname = "${machinename}:$hostname";
247             }
248 0           return $hostname;
249             }
250              
251              
252             sub send_results
253             {
254 0     0     my ($self, $test, $args) = @_;
255 0           my $report;
256              
257 0           my $tar = Archive::Tar->new;
258 0           $args->{result_dir} = $args->{target}."/client/results/default";
259 0           my $result_dir = $args->{result_dir};
260 0           my $hostname = get_machine_name;
261 0           my $testrun_id = $args->{testrun_id};
262 0           my $report_group = $args->{report_group};
263              
264 0           my $report_meta = "Version 13
265             1..1
266             # Tapper-Suite-Name: Autotest-$test
267             # Tapper-Machine-Name: $hostname
268             # Tapper-Suite-Version: ".$Tapper::TestSuite::AutoTest::VERSION."
269             ok 1 - Tapper metainfo
270             ";
271 0 0         $report_meta .= $testrun_id ? "# Tapper-Reportgroup-Testrun: $testrun_id\n" : '';
272 0 0         $report_meta .= $report_group ? "# Tapper-Reportgroup-Arbitrary: $report_group\n" : '';
273 0           $report_meta .= $self->autotest_meta($test, $args);
274              
275 0           my $meta;
276 0           eval { $meta = YAML::Syck::LoadFile("$result_dir/meta.yml") };
  0            
277 0 0         if ($@) {
278 0           $meta = {};
279 0           $report_meta .= "# Error loading $result_dir/meta.yml: $@\n";
280 0           $report_meta .= "# Files in $result_dir\n";
281 0           $report_meta .= $_ foreach map { "# ".$_ } `find $result_dir`;
  0            
282             }
283 0           push @{$meta->{file_order}}, 'tapper-suite-meta.tap';
  0            
284 0           $tar->read("$result_dir/tap.tar.gz");
285 0           $tar->replace_content( 'meta.yml', YAML::Syck::Dump($meta) );
286 0           $tar->add_data('tapper-suite-meta.tap',$report_meta);
287 0           $tar->write("$result_dir/tap.tar.gz", COMPRESS_GZIP);
288              
289 0           my $report_id = $self->report_away($args);
290 0 0         $self->upload_files($report_id, $test, $args) if $args->{uploadfiles};
291 0           return $args;
292             }
293              
294              
295             sub autotest_meta
296             {
297 0     0     my ($self, $test, $args) = @_;
298              
299 0           my $result_dir = $args->{result_dir};
300 0           my $meta = '';
301              
302             # --- generic entries ---
303 0           my %metamapping = ( "uname" => "uname",
304             "flags" => "cmdline",
305             "machine-name" => "hostname",
306             );
307 0           foreach my $header (keys %metamapping) {
308 0           my $file = "$result_dir/sysinfo/".$metamapping{$header};
309 0 0         next unless -e $file;
310 0           my ($value) = slurp($file);
311 0           chomp $value;
312 0           $meta .= "# Tapper-$header: $value\n";
313             }
314              
315             # --- cpu info ---
316 0           my $cpuinfofile = "$result_dir/sysinfo/cpuinfo";
317 0 0         if (-e $cpuinfofile) {
318 0           my @lines = slurp($cpuinfofile);
319 0           my $is_arm_cpu = grep { /Processor.*:.*ARM/ } @lines;
  0            
320 0 0         my $entry = $is_arm_cpu ? "Processor" : "model name";
321 0           my @cpuinfo = map { chomp ; s/^$entry.*: *//; $_ } grep { /$entry.*:/ } @lines;
  0            
  0            
  0            
  0            
322 0 0         $meta .= "# Tapper-cpuinfo: ".@cpuinfo." cores [".$cpuinfo[0]."]\n" if @cpuinfo;
323             }
324 0           return $meta;
325             }
326              
327              
328             sub print_help
329             {
330 0     0     my ($self) = @_;
331 0           say "$0 --test=s@ [ --directory=s ] [--remote-name]";
332 0           say "\t--test|t\t\tName of a subtest, REQUIRED, may be given multple times";
333 0           say "\t--directory|d\t\tDirectory to copy autotest to";
334 0           say "\t--source_url|s\t\tURL to get autotest from";
335 0           say "\t--remote-name|O\t\tPrint out the name of result files";
336 0           say "\t--help|h\t\tPrint this help text and exit";
337              
338              
339 0           exit;
340             }
341              
342              
343             sub parse_args
344             {
345 0     0     my ($self) = @_;
346 0           my @tests;
347 0           my ($dir, $remote_name, $help, $source, $uploadfiles);
348              
349 0           $uploadfiles = 1;
350 0           GetOptions ("test|t=s" => \@tests,
351             "directory|d=s" => \$dir,
352             "remote-name|O" => \$remote_name,
353             "source_url|s=s" => \$source,
354             "help|h" => \$help,
355             "uploadfiles!" => \$uploadfiles,
356             );
357 0 0         $self->print_help() if $help;
358 0 0         if (not @tests) {
359 0           print "Please name at least one subtest you want to run (--test=...).\n\n.";
360 0           $self->print_help();
361             }
362              
363 0   0       my $args = {subtests => \@tests,
      0        
      0        
      0        
      0        
364             target => $dir,
365             source => $source || 'http://github.com/autotest/autotest/tarball/0.14.3',
366             report_server => $ENV{TAPPER_REPORT_SERVER},
367             report_api_port => $ENV{TAPPER_REPORT_API_PORT} || '7358',
368             report_port => $ENV{TAPPER_REPORT_PORT} || '7357',
369             testrun_id => $ENV{TAPPER_TESTRUN} || '',
370             report_group => $ENV{TAPPER_REPORT_GROUP} || '',
371             remote_name => $remote_name,
372             uploadfiles => $uploadfiles,
373             };
374              
375 0           return $args;
376              
377             }
378              
379              
380              
381             sub run
382             {
383 0     0     my ($self, $args) = @_;
384 0           my $target = $args->{target};
385 0           my $autotest = "./autotest-local";
386              
387 0           my $olddir = cwd();
388 0 0         foreach my $test (@{$args->{subtests} || [] }) {
  0            
389 0           $self->log->debug("chdir $target/client");
390 0           chdir "$target/client";
391 0           $self->log_and_system($autotest, "run", "--tap", $test);
392 0           $self->send_results($test, $args);
393             }
394 0           chdir $olddir;
395 0           return $args;
396             }
397              
398             1; # End of Tapper::TestSuite::AutoTest
399              
400             __END__
401             =pod
402              
403             =encoding utf-8
404              
405             =head1 NAME
406              
407             Tapper::TestSuite::AutoTest - Tapper - Complete OS testing in a box via autotest
408              
409             =head1 SYNOPSIS
410              
411             You most likely want to run the frontend cmdline tool like this
412              
413             =over 4
414              
415             =item * Run an autotest subtest and report results to Tapper:
416              
417             $ tapper-testsuite-autotest -t hackbench
418              
419             =item * Run multiple autotest subtests and report results to Tapper:
420              
421             $ tapper-testsuite-autotest -t hackbench -t hwclock
422              
423             =back
424              
425             =head1 DESCRIPTION
426              
427             This module wraps autotest to make its (sub) tests available for Tapper.
428              
429             The commandline tool simply calls the single steps like this:
430              
431             use Tapper::TestSuite::AutoTest;
432              
433             my $wrapper = Tapper::TestSuite::AutoTest->new();
434             my $args = $wrapper->parse_args();
435             $args = $wrapper->install($args);
436             $args = $wrapper->run($args);
437              
438             The reporting evaluates several environment variables:
439              
440             TAPPER_REPORT_SERVER
441             TAPPER_REPORT_API_PORT
442             TAPPER_REPORT_PORT
443             TAPPER_TESTRUN
444             TAPPER_REPORT_GROUP
445              
446             with some sensible defaults. They are automatically provided when
447             using Tapper automation.
448              
449             In case you run it manually the most important variable is
450             C<TAPPER_REPORT_SERVER> pointing to your central Tapper server.
451              
452             See the Tapper manual for more details.
453              
454             =head1 FUNCTIONS
455              
456             =head2 makedir
457              
458             Checks whether a given directory exists and creates it if not.
459              
460             @param string - directory to create
461              
462             @return success - 0
463             @return error - error string
464              
465             =head2 $self->log_and_system(@args)
466              
467             Log and do a multi arg C<system()>.
468              
469             =head2 $self->log_and_system_shell(@args)
470              
471             Log and do a single arg C<system()>.
472              
473             =head2 copy_client
474              
475             Move the client to where it belongs.
476              
477             @param string - download directory
478             @param string - target directory
479              
480             @return die() in case of error
481              
482             =head2 install
483              
484             Install the autotest framework from a given source into a given target
485              
486             @param hash ref - args
487              
488             @return hash ref - args
489              
490             =head2 report_away
491              
492             Send the actual report to reports receiver framework.
493              
494             @param hash ref - args
495              
496             @return success - int - report id
497             @return error - die()
498              
499             =head2 upload_files
500              
501             Upload the stats file to reports framework.
502              
503             @param int - report id
504             @param hash ref - args
505              
506             =head2 get_machine_name
507              
508             Return hostname for metainfo in typical Tapper notation, i.e., just
509             the hostname (without FQDN) in host context or C<host:guest> (colon
510             separated) in guest context.
511              
512             =head2 send_results
513              
514             Send the test results to Tapper.
515              
516             @param hash ref - args
517              
518             @return hash ref - args
519              
520             =head2 autotest_meta
521              
522             Add meta information from files generated by autotest.
523              
524             @param hash ref - args
525              
526             @return string - Tapper TAP metainfo headers
527              
528             =head2 print_help
529              
530             Print help and die.
531              
532             =head2 parse_args
533              
534             Parse command line arguments and Tapper ENV variables.
535              
536             @return hash ref - args
537              
538             =head2 run
539              
540             Run the requested autotest test(s), collect their results and report
541             them.
542              
543             @param hash ref - args
544              
545             @return hash ref - args
546              
547             =head1 AUTHOR
548              
549             AMD OSRC Tapper Team <tapper@amd64.org>
550              
551             =head1 COPYRIGHT AND LICENSE
552              
553             This software is Copyright (c) 2012 by Advanced Micro Devices, Inc..
554              
555             This is free software, licensed under:
556              
557             The (two-clause) FreeBSD License
558              
559             =cut
560