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