File Coverage

blib/lib/App/TestOnTap/Harness.pm
Criterion Covered Total %
statement 107 108 99.0
branch 12 20 60.0
condition 4 5 80.0
subroutine 18 18 100.0
pod 3 3 100.0
total 144 154 93.5


line stmt bran cond sub pod time code
1             package App::TestOnTap::Harness;
2              
3 19     19   151 use strict;
  19         42  
  19         657  
4 19     19   110 use warnings;
  19         56  
  19         1313  
5              
6             our $VERSION = '1.001';
7             my $version = $VERSION;
8             $VERSION = eval $VERSION;
9              
10 19     19   153 use base qw(TAP::Harness);
  19         64  
  19         10864  
11              
12 19     19   120217 use App::TestOnTap::Scheduler;
  19         54  
  19         598  
13 19     19   8749 use App::TestOnTap::Dispenser;
  19         52  
  19         663  
14 19     19   125 use App::TestOnTap::Util qw(slashify runprocess $IS_PACKED);
  19         46  
  19         2085  
15              
16 19     19   8974 use TAP::Formatter::Console;
  19         66453  
  19         577  
17 19     19   8028 use TAP::Formatter::File;
  19         54052  
  19         603  
18              
19 19     19   155 use List::Util qw(max);
  19         48  
  19         19941  
20              
21             sub new
22             {
23 27     27 1 74 my $class = shift;
24 27         59 my $args = shift;
25              
26 27         154 my $self = $class->SUPER::new
27             (
28             {
29             formatter => __getFormatter($args),
30             jobs => $args->getJobs(),
31             merge => $args->getMerge(),
32             callbacks => { after_test => $args->getWorkDirManager()->getResultCollector() },
33             'exec' => __getExecMapper($args),
34             scheduler_class => 'App::TestOnTap::Scheduler'
35             }
36             );
37              
38 27         10391 $self->{testontap} = { args => $args, pez => App::TestOnTap::Dispenser->new($args) };
39              
40 26         149 return $self;
41             }
42              
43             sub make_scheduler
44             {
45 26     26 1 125756 my $self = shift;
46            
47 26         354 return $self->{scheduler_class}->new($self->{testontap}->{pez}, @_);
48             }
49              
50             sub runtests
51             {
52 26     26 1 61 my $self = shift;
53            
54 26         69 my $args = $self->{testontap}->{args};
55 26         96 my $sr = $args->getSuiteRoot();
56            
57 26         80 my @pairs;
58 26         194 push(@pairs, [ slashify("$sr/$_"), $_ ]) foreach ($self->{testontap}->{pez}->getAllTests());
59              
60 26         83 my $failed = 0;
61             {
62 26         50 my $wdmgr = $self->{testontap}->{args}->getWorkDirManager();
  26         145  
63              
64 26         58 local %ENV = %{$self->{testontap}->{args}->getPreprocess()->getEnv()};
  26         127  
65 26         215 $ENV{TESTONTAP_SUITE_DIR} = $sr;
66 26         165 $ENV{TESTONTAP_TMP_DIR} = $wdmgr->getTmp();
67 26         141 $ENV{TESTONTAP_SAVE_DIR} = $wdmgr->getSaveSuite();
68            
69 26 100       161 if ($self->{testontap}->{args}->useHarness())
70             {
71             # the normal case is to run with a 'real' harness that parses
72             # TAP, handles parallelization, formatters and all that
73             #
74 25         143 $wdmgr->beginTestRun();
75 25         6535 my $aggregator = $self->SUPER::runtests(@pairs);
76 25         17040 $wdmgr->endTestRun($self->{testontap}->{args}, $aggregator);
77 25   100     339 $failed = $aggregator->failed() || 0;
78             }
79             else
80             {
81             # if the user has requested 'no harness', just run the jobs serially
82             # in the right context, but make no effort to parse their output
83             # in any way - more convenient for debugging (esp. with an execmap
84             # that can start a test in debug mode)
85             #
86 1         5 my $scheduler = $self->make_scheduler(@pairs);
87              
88             # figure out the longest test file name with some extra to produce some
89             # nice delimiters...
90             #
91 1         2 my $longestTestFileName = 0;
92 1         7 $longestTestFileName = max($longestTestFileName, length($_->[0])) foreach (@pairs);
93 1         10 $longestTestFileName += 10;
94 1         4 my $topDelimLine = '#' x $longestTestFileName;
95 1         3 my $bottomDelimLine = '-' x $longestTestFileName;
96              
97 1         7 while (my $job = $scheduler->get_job())
98             {
99 1         4 my $desc = $job->description();
100 1         6 my $filename = $job->filename;
101 1         7 my $cmdline = $self->exec()->($self, $filename);
102 1         5 my $dryrun = $self->{testontap}->{args}->doDryRun();
103 1 50       12 my $parallelizable = ($self->{testontap}->{args}->getConfig()->parallelizable($desc) ? '' : 'not ') . 'parallelizable';
104 1         56 print "$topDelimLine\n";
105 1         16 print "Run test '$desc' ($parallelizable) using:\n";
106 1         21 print " $_\n" foreach (@$cmdline);
107 1         12 print "$bottomDelimLine\n";
108 1 50       5 if ($dryrun)
109             {
110 0         0 print "(dry run only, actual test not executed)\n";
111             }
112             else
113             {
114 1 50       100344 $failed++ if system(@$cmdline) >> 8;
115             }
116 1         67 $job->finish();
117             }
118             }
119            
120             # run postprocessing
121             #
122 26         2193 my $postcmd = $self->{testontap}->{args}->getConfig()->getPostprocessCmd();
123 26 100 66     341 if ($postcmd && @$postcmd)
124             {
125 1         4 my @postproc;
126             my $xit = runprocess
127             (
128             sub
129             {
130 1     1   33 push(@postproc, $_[0]);
131 1         480 print STDERR $_[0]
132             },
133             $sr,
134             (
135             @$postcmd,
136 1         19 @{$self->{testontap}->{args}->getPreprocess()->getArgv()}
  1         12  
137             )
138             );
139 1 50       41 if ($xit)
140             {
141 1         9 $failed++;
142 1         40 warn("WARNING: exit code '$xit' when running postprocess command\n");
143             }
144 1 50       13 $failed++ if $xit;
145              
146 1         37 $args->getWorkDirManager()->recordPostprocess([ @postproc ]);
147             }
148            
149             # drop the special workaround envvar...
150             #
151 26 50       3805 delete $ENV{PERL5LIB} if $IS_PACKED;
152             }
153            
154 26 50       789 return ($failed > 127) ? 127 : $failed;
155             }
156              
157             sub _open_spool
158             {
159 47     47   3761 my $self = shift;
160 47         107 my $testpath = shift;
161              
162 47         228 return $self->{testontap}->{args}->getWorkDirManager()->openTAPHandle($testpath);
163             }
164              
165             sub _close_spool
166             {
167 47     47   24974146 my $self = shift;
168 47         252 my $parser = shift;
169              
170 47         1058 $self->{testontap}->{args}->getWorkDirManager()->closeTAPHandle($parser);
171              
172 47         271 return;
173             }
174              
175             sub __getExecMapper
176             {
177 27     27   97 my $args = shift;
178              
179             return sub
180             {
181 48     48   1760 my $harness = shift;
182 48         128 my $testfile = shift;
183            
184             # trim down the full file name to the test name
185             #
186 48         296 my $srfs = slashify($args->getSuiteRoot(), '/');
187 48         18970 my $testname = slashify($testfile, '/');
188 48         790 $testname =~ s#^\Q$srfs\E/##;
189              
190             # get the commandline corresponding to the test name
191             #
192 48         255 my $cmdline = $args->getConfig()->getExecMapping($testname);
193            
194             # expand it with the full set
195             #
196 48         9683 $cmdline = [ @$cmdline, $testfile, @{$args->getArgv()} ];
  48         368  
197            
198             # make a note of the result for the work area records
199             #
200 48         254 $args->getWorkDirManager()->recordCommandLine($testname, $cmdline);
201            
202 48         243 return $cmdline;
203 27         484 };
204             }
205              
206             sub __getFormatter
207             {
208 27     27   73 my $args = shift;
209              
210 27         164 my $formatterArgs =
211             {
212             jobs => $args->getJobs(),
213             timer => $args->getTimer(),
214             show_count => 1,
215             verbosity => $args->getVerbose(),
216             };
217            
218             return
219 27 50       965 -t \*STDOUT
220             ? TAP::Formatter::Console->new($formatterArgs)
221             : TAP::Formatter::File->new($formatterArgs);
222             }
223              
224             1;