File Coverage

blib/lib/Dist/Joseki/Command/smoke.pm
Criterion Covered Total %
statement 42 136 30.8
branch 0 36 0.0
condition 0 24 0.0
subroutine 14 24 58.3
pod 0 9 0.0
total 56 229 24.4


\D+$!s;
line stmt bran cond sub pod time code
1             package Dist::Joseki::Command::smoke;
2 1     1   5 use strict;
  1         1  
  1         34  
3 1     1   4 use warnings;
  1         2  
  1         31  
4 1     1   8 use Cwd 'abs_path';
  1         2  
  1         53  
5 1     1   6 use Config 'myconfig';
  1         5  
  1         94  
6 1     1   711 use Dist::Joseki;
  1         31403  
  1         9  
7 1     1   718 use Dist::Joseki::Find;
  1         578  
  1         9  
8 1     1   25 use File::Basename;
  1         1  
  1         84  
9 1     1   5 use File::Spec;
  1         4  
  1         10  
10 1     1   21 use File::Find;
  1         2  
  1         44  
11 1     1   1649 use Template;
  1         33788  
  1         9  
12 1     1   1103 use Test::TAP::HTMLMatrix;
  1         150819  
  1         10  
13 1     1   30 use Test::TAP::Model::Visual;
  1         2  
  1         7  
14 1     1   968 use YAML qw/LoadFile DumpFile/;
  1         8201  
  1         74  
15             our $VERSION = '0.01';
16 1     1   10 use base 'Dist::Joseki::Cmd::Multiplexable';
  1         2  
  1         855  
17             __PACKAGE__->mk_hash_accessors(qw(dist_errors));
18              
19             sub options {
20 0     0 0   my ($self, $app, $cmd_config) = @_;
21             return (
22 0   0       $self->SUPER::options($app, $cmd_config),
23             [ 'cover|c', 'also run coverage tests', ],
24             [ 'resume|r', 'skip tests if there is a smoke.html already', ],
25             [ 'summary|s=s',
26             'location of summary file',
27             { default => $cmd_config->{summary} || sprintf('%s/smoke.html',
28             (Dist::Joseki::Find->new->projroot)[0]),
29             },
30             ],
31             );
32             }
33              
34             sub run_smoke_tests {
35 0     0 0   my $self = shift;
36 0           my $smoke_html_filename = 'smoke.html';
37 0           my $smoke_yaml_filename = 'smoke.yaml';
38 0 0         if (-e 'BUILD.SKIP') {
39 0           warn "Skipping build because of BUILD.SKIP\n";
40 0           return;
41             }
42 0 0 0       if ($self->opt_has_value('resume') && -e $smoke_html_filename) {
43 0           warn "Skipping tests because --resume is given and smoke.html exists\n";
44 0           return;
45             }
46 0           my $dist = Dist::Joseki->get_dist_type;
47 0           $dist->ACTION_default;
48              
49             # Run smoke tests. Assumes that 'make' has already been run.
50 0 0         my $meta = LoadFile('META.yml') or die "can't load META.yml\n";
51 0           my $distname = $meta->{name};
52 0           local $ENV{HARNESS_VERBOSE} = 1;
53 0           my $model = Test::TAP::Model::Visual->new_with_tests(glob("t/*.t"));
54 0 0         open my $fh, '>', $smoke_html_filename
55             or die "can't open $smoke_html_filename for writing: $!\n";
56 0           my $v = Test::TAP::HTMLMatrix->new($model, $distname);
57 0           $v->has_inline_css(1);
58 0           print $fh "$v";
59 0 0         close $fh or die "can't close $smoke_html_filename: $!\n";
60              
61             # force scalar context so localtime() outputs readable string
62 0           my $start_time = localtime($model->{meat}{start_time});
63 0           my $end_time = localtime($model->{meat}{end_time});
64 0           my %summary = (
65             distname => $distname,
66             start_time => $start_time,
67             end_time => $end_time,
68             );
69 0           for (
70             qw(percentage seen todo skipped passed
71             failed unexpectedly_succeeded ratio)
72             ) {
73 0           my $method = "total_$_";
74 0           $summary{$_} = $model->$method;
75             }
76 0           DumpFile($smoke_yaml_filename, \%summary);
77              
78             # Don't distclean so the generated test files (t/embedded) remain: They
79             # are referenced from smoke.html pages.
80             }
81              
82             sub run_coverage_tests {
83 0     0 0   my $self = shift;
84 0 0         return unless $self->opt_has_value('cover');
85 0 0         if (-e 'BUILD.SKIP') {
86 0           warn "Skipping coverage tests because of BUILD.SKIP\n";
87 0           return;
88             }
89 0 0         if (-e 'COVER.SKIP') {
90 0           warn "Skipping coverage tests because of COVER.SKIP\n";
91 0           return;
92             }
93              
94             # Run coverage tests. Assumes that 'make' has already been run.
95 0           $self->safe_system('cover -delete');
96 0           $self->safe_system(
97             'HARNESS_PERL_SWITCHES=-MDevel::Cover=-ignore,^inc/ make test');
98 0           $self->safe_system('cover');
99             }
100              
101             sub create_summary {
102 0     0 0   my $self = shift;
103 0           my $summary_dir = abs_path(dirname($self->opt('summary')));
104 0           my @smoke;
105             find(
106             sub {
107 0 0 0 0     return unless -f && $_ eq 'smoke.yaml';
108 0 0         return if -e 'BUILD.SKIP';
109 0           my $summary = LoadFile($_);
110 0 0         unless ($summary->{distname}) {
111 0           warn "$File::Find::name defines no distname\n";
112 0           return;
113             }
114              
115             # assume the summary_dir path is above all of the @basedir paths
116 0           (my $rel_dir = $File::Find::dir) =~ s!^$summary_dir/!!;
117 0           $summary->{link} = "$rel_dir/smoke.html";
118 0           my $tee = 'smoketee.txt';
119 0 0         if (-e $tee) {
120 0           $summary->{rawlink} = "$rel_dir/$tee";
121 0           my $raw = do { local (@ARGV, $/) = $tee; <> };
  0            
  0            
122 0 0 0       $summary->{rawalert}++
      0        
      0        
      0        
      0        
123             if $raw =~ /Use of uninitialized value/
124             || $raw =~ / at .* line \d+/
125             || $raw =~ /Failed test /
126             || $raw =~ /Looks like you failed/
127             || $raw =~
128             /Looks like you planned \d+ tests but ran \d+ extra/
129             || $raw =~ /No tests run!/;
130             }
131 0           my $coverage_html = "$File::Find::dir/cover_db/coverage.html";
132 0 0         if (-e $coverage_html) {
133 0           $summary->{coverage_link} = "$rel_dir/cover_db/coverage.html";
134 0 0         open my $fh, '<', $coverage_html
135             or die "can't open $coverage_html: $!\n";
136 0           my $html = do { local $/; <$fh> };
  0            
  0            
137 0 0         close $fh or die "can't close $coverage_html: $!\n";
138              
139             # crude but effective
140 0           ($summary->{coverage_total}) =
141             $html =~ m!">(\d+\.\d+)
142             }
143 0 0         $summary->{coverage_total} = sprintf "%.2f",
144             defined $summary->{coverage_total}
145             ? $summary->{coverage_total}
146             : 0;
147 0           push @smoke => $summary;
148             },
149 0           Dist::Joseki::Find->new->projroot
150             );
151 0           @smoke =
152 0           map { $_->[0] }
153 0           sort { $a->[1] cmp $b->[1] }
154 0           map { [ $_, $_->{distname} ] } @smoke;
155 0           my $template = $self->get_template;
156 0           my $tt = Template->new;
157 0 0         $tt->process(
158             \$template,
159             { smoke => \@smoke,
160             errors => scalar($self->dist_errors),
161             config => myconfig(),
162             },
163             $self->opt('summary')
164             ) || die $tt->error;
165             }
166              
167             sub run {
168 0     0 0   my $self = shift;
169 0           $self->SUPER::run(@_);
170 0           $self->create_summary;
171             }
172              
173             sub run_single {
174 0     0 0   my $self = shift;
175 0           $self->SUPER::run_single(@_);
176 0           $self->assert_is_dist_base_dir;
177 0           $self->run_smoke_tests;
178 0           $self->run_coverage_tests;
179              
180             # create summary here as well as in run() so if we're iterating over all
181             # dists we can watch the summary grow
182 0           $self->create_summary;
183             }
184              
185             sub handle_dist_error {
186 0     0 0   my ($self, $dist, $error) = @_;
187              
188             # we maintain a hash of lists, so get a reference and manipulate it
189             # directly
190 0           my $dist_errors = $self->dist_errors;
191 0           push @{ $dist_errors->{$dist} } => $error;
  0            
192             }
193             sub get_template {
194 0     0 0   <<'EOTEMPLATE' }
195            
196             "http://www.w3.org/TR/REC-html40/strict.dtd">
197            
198            
199             Smoke Test Result Summary
200              
201            
202            
250              
251            
252            
253            

Smoke Test Result Summary

254              
255            
256            
257             Distribution
258             raw
259             coverage
260             tests
261             ok
262             fail
263             todo
264             skip
265             unexp.
success
266             total
267             time
268            
269              
270             [% FOR dist = smoke;
271             IF dist.ratio == 0;
272             tdclass = "allfail";
273             ELSIF dist.ratio == 1;
274             tdclass = "allpass";
275             ELSE;
276             tdclass = "partial";
277             END;
278             %]
279            
280            
281             [% dist.distname %]
282            
283              
284              
285              
286             [% IF dist.rawlink %]
287              
288             [%
289             IF dist.rawalert;
290             rawtdclass = "allfail";
291             rawtext = "warn";
292             ELSE;
293             rawtdclass = "allpass";
294             rawtext = "ok";
295             END;
296             %]
297              
298            
299             [% rawtext %]
300            
301             [% ELSE %]
302             MISSING
303             [% END %]
304              
305              
306              
307             [%
308             IF dist.coverage_total + 0 == 0;
309             covertdclass = "allfail";
310             ELSIF dist.coverage_total + 0 == 100;
311             covertdclass = "allpass";
312             ELSE;
313             covertdclass = "partial";
314             END;
315             %]
316              
317            
318             [% IF dist.coverage_link %]
319            
320             [% END %]
321             [% dist.coverage_total %]%
322             [% IF dist.coverage_link %]
323            
324             [% END %]
325            
326              
327             [% dist.seen %]
328             [% dist.passed %]
329             [% dist.failed %]
330             [% dist.todo %]
331             [% dist.skipped %]
332             [% dist.unexpectedly_succeeded %]
333             [% dist.percentage %]
334             [% dist.end_time %]
335            
336             [% END %]
337            
338              
339             [% IF errors.size > 0 %]
340            

Errors

341              
342            

There were problems.

343              
344             [% FOREACH dist IN errors.keys.sort %]
345            

[% dist %]

346              
347            
348             [% FOREACH error IN errors.$dist %]
349            
  • [% error %]
  • 350             [% END %]
    351            
    352             [% END %]
    353             [% END %]
    354              
    355            

    Config

    356              
    357            
     
    358            
    359             [% config %]
    360            
    361            
    362              
    363            
    364            
    365             EOTEMPLATE
    366              
    367             sub hook_in_dist_loop_begin {
    368 0     0 0   my ($self, $dist) = @_;
    369 0           $self->SUPER::hook_in_dist_loop_begin($dist);
    370 0           $self->print_header($dist);
    371             }
    372             1;
    373             __END__