File Coverage

blib/lib/Test/Stream/Workflow/Task.pm
Criterion Covered Total %
statement 179 179 100.0
branch 87 92 94.5
condition 9 10 90.0
subroutine 32 32 100.0
pod 6 7 85.7
total 313 320 97.8


line stmt bran cond sub pod time code
1             package Test::Stream::Workflow::Task;
2 28     28   453 use strict;
  28         32  
  28         657  
3 28     28   82 use warnings;
  28         25  
  28         569  
4              
5 28     28   86 use Carp qw/croak/;
  28         29  
  28         1389  
6 28     28   99 use Scalar::Util qw/reftype/;
  28         30  
  28         1013  
7 28     28   102 use Test::Stream::Sync();
  28         32  
  28         442  
8 28     28   121 use Test::Stream::Util qw/CAN_SET_SUB_NAME set_sub_name update_mask/;
  28         34  
  28         142  
9              
10             use overload(
11             'fallback' => 1,
12             '&{}' => sub {
13 31     31   182 my $self = shift;
14 31         171 my @caller = caller(0);
15 31         132 update_mask($caller[1], $caller[2], '*', {restart => 1, pause => 1, 3 => 'CONTINUE'});
16 31     31   91 my $out = sub { $self->iterate(@_) };
  31         65  
17 31         151 set_sub_name(__PACKAGE__ . '::iterator', $out)
18             if CAN_SET_SUB_NAME;
19 31         73 return $out;
20             },
21 28     28   123 );
  28         35  
  28         239  
22              
23 28     28   1808 use Test::Stream::Workflow qw/push_workflow_vars pop_workflow_vars/;
  28         32  
  28         166  
24 28     28   10520 use Test::Stream::Plugin::Subtest qw/subtest_buffered/;
  28         51  
  28         196  
25 28     28   121 use Test::Stream::Util qw/try set_sub_name CAN_SET_SUB_NAME/;
  28         32  
  28         130  
26              
27             use Test::Stream::HashBase(
28 28         141 accessors => [
29             qw{
30             unit args runner
31             no_final no_subtest
32             stage
33             _buildup_idx _teardown_idx
34             exception
35             failed events pending
36             }
37             ]
38 28     28   113 );
  28         33  
39              
40             sub STAGE_BUILDUP() { 0 }
41             sub STAGE_PRIMARY() { 1 }
42             sub STAGE_TEARDOWN() { 2 }
43             sub STAGE_COMPLETE() { 3 }
44              
45             sub init {
46 317     317 0 291 my $self = shift;
47              
48             croak "Attribute 'unit' is required"
49 317 100       1336 unless $self->{+UNIT};
50              
51 316   100     546 $self->{+ARGS} ||= [];
52              
53 316         496 $self->reset;
54             }
55              
56             sub finished {
57 674     674 1 520 my $self = shift;
58 674 100       1302 return 1 if $self->{+EXCEPTION};
59 673 100       1099 return 1 if $self->{+STAGE} >= STAGE_COMPLETE();
60              
61 670         1147 return 0;
62             }
63              
64             sub subtest {
65 313     313 1 272 my $self = shift;
66 313 100       695 return 0 if $self->{+NO_FINAL};
67 205 100       373 return 0 if $self->{+NO_SUBTEST};
68 204         357 return 1;
69             }
70              
71             sub reset {
72 346     346 1 434 my $self = shift;
73              
74 346         470 $self->{+STAGE} = STAGE_BUILDUP();
75 346         372 $self->{+_BUILDUP_IDX} = 0;
76 346         582 $self->{+_TEARDOWN_IDX} = 0;
77 346         374 $self->{+FAILED} = 0;
78 346         351 $self->{+EVENTS} = 0;
79 346         350 $self->{+PENDING} = 0;
80 346         627 $self->{+EXCEPTION} = undef;
81             }
82              
83             sub _have_primary {
84 327     327   283 my $self = shift;
85              
86 327         851 my $primary = $self->{+UNIT}->primary;
87              
88             # Make sure we have primary, and that it is a ref
89 327 100       894 return 0 unless $primary;
90 324 100       586 return 0 unless ref $primary;
91              
92             # code ref is fine
93 323         608 my $type = reftype($primary);
94 323 100       879 return 1 if $type eq 'CODE';
95              
96             # array ref is fine if it is populated
97 44 100       97 return 0 unless $type eq 'ARRAY';
98 43         139 return @$primary;
99             }
100              
101             sub should_run {
102 328     328 1 330 my $self = shift;
103 328 100       987 return 1 unless defined $ENV{TS_WORKFLOW};
104 3 100       7 return 1 if $self->{+NO_FINAL};
105 2 100       7 return 1 if $self->{+UNIT}->contains($ENV{TS_WORKFLOW});
106 1         6 return 0;
107             }
108              
109             sub run {
110 326     326 1 332 my $self = shift;
111              
112 326 100       483 return if $self->finished;
113 325 100       502 return unless $self->should_run;
114              
115 324         372 my $unit = $self->{+UNIT};
116 324         732 my $ctx = $unit->context;
117              
118             # Skip?
119 324 100       656 if ($ctx->debug->skip) {
120 3         17 $self->{+STAGE} = STAGE_COMPLETE();
121 3         8 $ctx->ok(1, $self->{+UNIT}->name);
122 3         8 return;
123             }
124              
125             # Make sure we have something to do!
126 321 100       1581 unless ($self->_have_primary) {
127 2 100       15 return if $self->{+UNIT}->is_root;
128 1         3 $self->{+STAGE} = STAGE_COMPLETE();
129 1         4 $ctx->ok(0, $self->{+UNIT}->name, ['No primary actions defined! Nothing to do!']);
130 1         3 return;
131             }
132              
133 319         276 my $vars;
134 319 100       948 $vars = push_workflow_vars({}) unless $self->{+NO_FINAL};
135              
136 319 100       487 if ($self->subtest) {
137             $ctx->do_in_context(
138             \&subtest_buffered,
139             $self->{+UNIT}->name,
140             sub {
141 206     176   472 $self->iterate();
142             $ctx->ok(0, $unit->name, ["No events were generated"])
143 205 100       592 unless $self->{+EVENTS};
144             }
145 206         637 );
146             }
147             else {
148 113         228 $self->iterate();
149              
150             $ctx->ok(0, $unit->name, ["No events were generated"])
151 112 100 66     334 unless $self->{+EVENTS} || $self->{+NO_FINAL};
152              
153             $ctx->ok(!$self->{+FAILED}, $unit->name)
154 112 100 100     480 if $self->{+FAILED} || !$self->{+NO_FINAL};
155             }
156              
157 317 100       1402 pop_workflow_vars($vars) if $vars;
158              
159             # In case something is holding a reference to vars itself.
160 317         370 %$vars = ();
161 317         324 $vars = undef;
162              
163 317         807 return;
164             }
165              
166             sub iterate {
167 345     345 1 391 my $self = shift;
168              
169 345 100       775 $self->{+PENDING}-- if $self->{+PENDING};
170              
171 345 100       482 return if $self->finished;
172              
173             my ($ok, $err) = try {
174 344 100   315   1082 $self->_run_buildups if $self->{+STAGE} == STAGE_BUILDUP();
175 343 100       965 $self->_run_primaries if $self->{+STAGE} == STAGE_PRIMARY();
176 339 100       1240 $self->_run_teardowns if $self->{+STAGE} == STAGE_TEARDOWN();
177 344         1637 };
178              
179 342 100       1274 unless ($ok) {
180 3         6 $self->{+FAILED}++;
181 3         4 $self->{+EXCEPTION} = $err;
182 3         11 $self->unit->context->send_event('Exception', error => $err);
183             }
184              
185 342         413 return;
186             }
187              
188             sub _run_buildups {
189 346     346   379 my $self = shift;
190              
191 346         956 my $buildups = $self->{+UNIT}->buildup;
192              
193             # No Buildups
194 346 100       1056 unless ($buildups) {
195 249 50       509 $self->{+STAGE} = STAGE_PRIMARY() if $self->{+STAGE} == STAGE_BUILDUP();
196 249         305 return;
197             }
198              
199 97         214 while ($self->{+_BUILDUP_IDX} < @$buildups) {
200 77         124 my $bunit = $buildups->[$self->{+_BUILDUP_IDX}++];
201 77 100       168 if ($bunit->wrap) {
202 35         100 $self->{+PENDING}++;
203 35         72 $self->runner->run(unit => $bunit, no_final => 1, args => [$self]);
204 35 100       157 if ($self->{+PENDING}) {
205 3         6 $self->{+PENDING}--;
206 3         10 my $ctx = $bunit->context;
207 3         10 my $trace = $ctx->debug->trace;
208 3         22 $ctx->ok(0, $bunit->name, ["Inner sub was never called $trace"]);
209             }
210             }
211             else {
212 42         161 $self->runner->run(unit => $bunit, no_final => 1, args => $self->{+ARGS});
213             }
214             }
215              
216 97 100       241 $self->{+STAGE} = STAGE_PRIMARY() if $self->{+STAGE} == STAGE_BUILDUP();
217             }
218              
219             sub _listener {
220 319     319   317 my $self = shift;
221              
222             return sub {
223 1294     1294   1201 my ($hub, $e) = @_;
224 1294         1622 $self->{+EVENTS}++;
225 1294 100       2360 $self->{+FAILED}++ if $e->causes_fail;
226 319 100       1321 } unless $self->{+NO_FINAL};
227              
228 109         257 my $ctx = $self->{+UNIT}->context;
229 109         240 my $trace = $ctx->debug->trace;
230 109 100       281 $trace = "wrapped $trace" if $self->{+UNIT}->wrap;
231              
232             return sub {
233 491     491   470 my ($hub, $e) = @_;
234 491         791 $self->{+EVENTS}++;
235 491 100       1048 return unless $e->causes_fail;
236 14         20 $self->{+FAILED}++;
237 14 100       63 return unless $e->can('diag');
238 11 50       23 $e->set_diag([]) unless $e->diag;
239 11         27 push @{$e->diag} => $trace;
  11         20  
240 109         791 };
241             }
242              
243             sub _run_primary {
244 317     317   1147 my $self = shift;
245 317         297 my $unit = $self->{+UNIT};
246 317         607 my $primary = $unit->primary;
247              
248 317         1327 my $hub = Test::Stream::Sync->stack->top;
249 317 50       798 my $l = $hub->listen($self->_listener) if $hub->is_local;
250              
251 317 100       888 if(reftype($primary) eq 'ARRAY') {
252 46         161 $self->runner->run(unit => $_, args => $self->{+ARGS}) for @$primary
253             }
254             else {
255 28     28   207 BEGIN { update_mask(__FILE__, __LINE__ + 1, '*', {pause => 1, hide => 1}) }
256 271         228 $primary->(@{$self->{+ARGS}});
  271         821  
257             }
258              
259 313 50       1816 $hub->unlisten($l) if $l;
260             }
261              
262             sub _run_primaries {
263 313     313   294 my $self = shift;
264              
265             # Make sure this does not run again
266 313 50       615 $self->{+STAGE} = STAGE_TEARDOWN() if $self->{+STAGE} < STAGE_TEARDOWN();
267              
268 313   100     674 my $modifiers = $self->{+UNIT}->modify || return $self->_run_primary();
269              
270 6         25 for my $mod (@$modifiers) {
271             my $primary = sub {
272 10     10   13 $mod->primary->(@{$self->{+ARGS}});
  10         31  
273 10         47 $self->_run_primary();
274 10         39 };
275              
276 10         34 my $name = $mod->name;
277 10         64 set_sub_name($name, $primary) if CAN_SET_SUB_NAME;
278              
279 10         80 my $temp = Test::Stream::Workflow::Unit->new(
280             %$mod,
281             primary => $primary,
282             );
283 10         33 $self->runner->run(unit => $temp, args => $self->{+ARGS});
284             }
285             }
286              
287             sub _run_teardowns {
288 341     341   311 my $self = shift;
289              
290 341         927 my $teardowns = $self->{+UNIT}->teardown;
291 341 100       1027 unless ($teardowns) {
292 276         341 $self->{+STAGE} = STAGE_COMPLETE();
293 276         485 return;
294             }
295              
296 65         132 while($self->{+_TEARDOWN_IDX} < @$teardowns) {
297 45         73 my $tunit = $teardowns->[$self->{+_TEARDOWN_IDX}++];
298             # Popping a wrap
299 45 100       92 return if $tunit->wrap;
300              
301 12         48 $self->runner->run(unit => $tunit, no_final => 1, args => $self->{+ARGS});
302             }
303              
304 32         64 $self->{+STAGE} = STAGE_COMPLETE();
305             }
306              
307             1;
308              
309             __END__