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   706 use strict;
  28         53  
  28         676  
3 28     28   129 use warnings;
  28         49  
  28         721  
4              
5 28     28   141 use Carp qw/croak/;
  28         53  
  28         1616  
6 28     28   143 use Scalar::Util qw/reftype/;
  28         60  
  28         1300  
7 28     28   151 use Test::Stream::Sync;
  28         48  
  28         803  
8 28     28   138 use Test::Stream::Util qw/CAN_SET_SUB_NAME set_sub_name update_mask/;
  28         64  
  28         175  
9              
10             use overload(
11             'fallback' => 1,
12             '&{}' => sub {
13 31     31   270 my $self = shift;
14 31         233 my @caller = caller(0);
15 31         215 update_mask($caller[1], $caller[2], '*', {restart => 1, stop => 1, 3 => 'CONTINUE'});
16 31     31   134 my $out = sub { $self->iterate(@_) };
  31         99  
17 31         230 set_sub_name(__PACKAGE__ . '::iterator', $out)
18             if CAN_SET_SUB_NAME;
19 31         110 return $out;
20             },
21 28     28   175 );
  28         51  
  28         331  
22              
23 28     28   2382 use Test::Stream::Workflow qw/push_workflow_vars pop_workflow_vars/;
  28         59  
  28         197  
24 28     28   17353 use Test::Stream::Plugin::Subtest qw/subtest_buffered/;
  28         72  
  28         269  
25 28     28   220 use Test::Stream::Util qw/try set_sub_name CAN_SET_SUB_NAME/;
  28         55  
  28         186  
26              
27             use Test::Stream::HashBase(
28 28         200 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   218 );
  28         57  
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 316     316 0 506 my $self = shift;
47              
48             croak "Attribute 'unit' is required"
49 316 100       1953 unless $self->{+UNIT};
50              
51 315   100     840 $self->{+ARGS} ||= [];
52              
53 315         803 $self->reset;
54             }
55              
56             sub finished {
57 672     672 1 937 my $self = shift;
58 672 100       1808 return 1 if $self->{+EXCEPTION};
59 671 100       1757 return 1 if $self->{+STAGE} >= STAGE_COMPLETE();
60              
61 668         1775 return 0;
62             }
63              
64             sub subtest {
65 312     312 1 466 my $self = shift;
66 312 100       1011 return 0 if $self->{+NO_FINAL};
67 204 100       547 return 0 if $self->{+NO_SUBTEST};
68 203         529 return 1;
69             }
70              
71             sub reset {
72 345     345 1 626 my $self = shift;
73              
74 345         809 $self->{+STAGE} = STAGE_BUILDUP();
75 345         604 $self->{+_BUILDUP_IDX} = 0;
76 345         921 $self->{+_TEARDOWN_IDX} = 0;
77 345         673 $self->{+FAILED} = 0;
78 345         583 $self->{+EVENTS} = 0;
79 345         599 $self->{+PENDING} = 0;
80 345         1054 $self->{+EXCEPTION} = undef;
81             }
82              
83             sub _have_primary {
84 326     326   462 my $self = shift;
85              
86 326         1234 my $primary = $self->{+UNIT}->primary;
87              
88             # Make sure we have primary, and that it is a ref
89 326 100       1383 return 0 unless $primary;
90 323 100       775 return 0 unless ref $primary;
91              
92             # code ref is fine
93 322         863 my $type = reftype($primary);
94 322 100       1224 return 1 if $type eq 'CODE';
95              
96             # array ref is fine if it is populated
97 44 100       145 return 0 unless $type eq 'ARRAY';
98 43         265 return @$primary;
99             }
100              
101             sub should_run {
102 327     327 1 434 my $self = shift;
103 327 100       1509 return 1 unless defined $ENV{TS_WORKFLOW};
104 3 100       13 return 1 if $self->{+NO_FINAL};
105 2 100       11 return 1 if $self->{+UNIT}->contains($ENV{TS_WORKFLOW});
106 1         11 return 0;
107             }
108              
109             sub run {
110 325     325 1 508 my $self = shift;
111              
112 325 100       797 return if $self->finished;
113 324 100       790 return unless $self->should_run;
114              
115 323         612 my $unit = $self->{+UNIT};
116 323         971 my $ctx = $unit->context;
117              
118             # Skip?
119 323 100       1167 if ($ctx->debug->skip) {
120 3         25 $self->{+STAGE} = STAGE_COMPLETE();
121 3         12 $ctx->ok(1, $self->{+UNIT}->name);
122 3         13 return;
123             }
124              
125             # Make sure we have something to do!
126 320 100       2505 unless ($self->_have_primary) {
127 2 100       18 return if $self->{+UNIT}->is_root;
128 1         3 $self->{+STAGE} = STAGE_COMPLETE();
129 1         5 $ctx->ok(0, $self->{+UNIT}->name, ['No primary actions defined! Nothing to do!']);
130 1         4 return;
131             }
132              
133 318         456 my $vars;
134 318 100       1470 $vars = push_workflow_vars({}) unless $self->{+NO_FINAL};
135              
136 318 100       796 if ($self->subtest) {
137             $ctx->do_in_context(
138             \&subtest_buffered,
139             $self->{+UNIT}->name,
140             sub {
141 205     175   647 $self->iterate();
142             $ctx->ok(0, $unit->name, ["No events were generated"])
143 204 100       886 unless $self->{+EVENTS};
144             }
145 205         893 );
146             }
147             else {
148 113         346 $self->iterate();
149              
150             $ctx->ok(0, $unit->name, ["No events were generated"])
151 112 100 66     436 unless $self->{+EVENTS} || $self->{+NO_FINAL};
152              
153             $ctx->ok(!$self->{+FAILED}, $unit->name)
154 112 100 100     770 if $self->{+FAILED} || !$self->{+NO_FINAL};
155             }
156              
157 316 100       2078 pop_workflow_vars($vars) if $vars;
158              
159             # In case something is holding a reference to vars itself.
160 316         542 %$vars = ();
161 316         474 $vars = undef;
162              
163 316         1153 return;
164             }
165              
166             sub iterate {
167 344     344 1 633 my $self = shift;
168              
169 344 100       997 $self->{+PENDING}-- if $self->{+PENDING};
170              
171 344 100       790 return if $self->finished;
172              
173             my ($ok, $err) = try {
174 343 100   314   1696 $self->_run_buildups if $self->{+STAGE} == STAGE_BUILDUP();
175 342 100       1433 $self->_run_primaries if $self->{+STAGE} == STAGE_PRIMARY();
176 338 100       1808 $self->_run_teardowns if $self->{+STAGE} == STAGE_TEARDOWN();
177 343         2017 };
178              
179 341 100       1922 unless ($ok) {
180 3         8 $self->{+FAILED}++;
181 3         6 $self->{+EXCEPTION} = $err;
182 3         15 $self->unit->context->send_event('Exception', error => $err);
183             }
184              
185 341         696 return;
186             }
187              
188             sub _run_buildups {
189 345     345   545 my $self = shift;
190              
191 345         1460 my $buildups = $self->{+UNIT}->buildup;
192              
193             # No Buildups
194 345 100       1666 unless ($buildups) {
195 248 50       819 $self->{+STAGE} = STAGE_PRIMARY() if $self->{+STAGE} == STAGE_BUILDUP();
196 248         510 return;
197             }
198              
199 97         309 while ($self->{+_BUILDUP_IDX} < @$buildups) {
200 77         207 my $bunit = $buildups->[$self->{+_BUILDUP_IDX}++];
201 77 100       287 if ($bunit->wrap) {
202 35         165 $self->{+PENDING}++;
203 35         111 $self->runner->run(unit => $bunit, no_final => 1, args => [$self]);
204 35 100       236 if ($self->{+PENDING}) {
205 3         5 $self->{+PENDING}--;
206 3         14 my $ctx = $bunit->context;
207 3         15 my $trace = $ctx->debug->trace;
208 3         26 $ctx->ok(0, $bunit->name, ["Inner sub was never called $trace"]);
209             }
210             }
211             else {
212 42         256 $self->runner->run(unit => $bunit, no_final => 1, args => $self->{+ARGS});
213             }
214             }
215              
216 97 100       361 $self->{+STAGE} = STAGE_PRIMARY() if $self->{+STAGE} == STAGE_BUILDUP();
217             }
218              
219             sub _listener {
220 318     318   499 my $self = shift;
221              
222             return sub {
223 1285     1285   2035 my ($hub, $e) = @_;
224 1285         2393 $self->{+EVENTS}++;
225 1285 100       3580 $self->{+FAILED}++ if $e->causes_fail;
226 318 100       1884 } unless $self->{+NO_FINAL};
227              
228 109         379 my $ctx = $self->{+UNIT}->context;
229 109         394 my $trace = $ctx->debug->trace;
230 109 100       434 $trace = "wrapped $trace" if $self->{+UNIT}->wrap;
231              
232             return sub {
233 490     490   839 my ($hub, $e) = @_;
234 490         1050 $self->{+EVENTS}++;
235 490 100       1519 return unless $e->causes_fail;
236 14         28 $self->{+FAILED}++;
237 14 100       98 return unless $e->can('diag');
238 11 50       35 $e->set_diag([]) unless $e->diag;
239 11         47 push @{$e->diag} => $trace;
  11         28  
240 109         1048 };
241             }
242              
243             sub _run_primary {
244 316     316   1827 my $self = shift;
245 316         545 my $unit = $self->{+UNIT};
246 316         937 my $primary = $unit->primary;
247              
248 316         1974 my $hub = Test::Stream::Sync->stack->top;
249 316 50       1156 my $l = $hub->listen($self->_listener) if $hub->is_local;
250              
251 316 100       1245 if(reftype($primary) eq 'ARRAY') {
252 46         249 $self->runner->run(unit => $_, args => $self->{+ARGS}) for @$primary
253             }
254             else {
255 28     28   237 BEGIN { update_mask(__FILE__, __LINE__ + 1, '*', {stop => 1, hide => 1}) }
256 270         421 $primary->(@{$self->{+ARGS}});
  270         1136  
257             }
258              
259 312 50       2706 $hub->unlisten($l) if $l;
260             }
261              
262             sub _run_primaries {
263 312     312   456 my $self = shift;
264              
265             # Make sure this does not run again
266 312 50       985 $self->{+STAGE} = STAGE_TEARDOWN() if $self->{+STAGE} < STAGE_TEARDOWN();
267              
268 312   100     1109 my $modifiers = $self->{+UNIT}->modify || return $self->_run_primary();
269              
270 6         34 for my $mod (@$modifiers) {
271             my $primary = sub {
272 10     10   15 $mod->primary->(@{$self->{+ARGS}});
  10         44  
273 10         67 $self->_run_primary();
274 10         44 };
275              
276 10         50 my $name = $mod->name;
277 10         125 set_sub_name($name, $primary) if CAN_SET_SUB_NAME;
278              
279 10         109 my $temp = Test::Stream::Workflow::Unit->new(
280             %$mod,
281             primary => $primary,
282             );
283 10         47 $self->runner->run(unit => $temp, args => $self->{+ARGS});
284             }
285             }
286              
287             sub _run_teardowns {
288 340     340   539 my $self = shift;
289              
290 340         1425 my $teardowns = $self->{+UNIT}->teardown;
291 340 100       1614 unless ($teardowns) {
292 275         523 $self->{+STAGE} = STAGE_COMPLETE();
293 275         771 return;
294             }
295              
296 65         206 while($self->{+_TEARDOWN_IDX} < @$teardowns) {
297 45         121 my $tunit = $teardowns->[$self->{+_TEARDOWN_IDX}++];
298             # Popping a wrap
299 45 100       148 return if $tunit->wrap;
300              
301 12         73 $self->runner->run(unit => $tunit, no_final => 1, args => $self->{+ARGS});
302             }
303              
304 32         119 $self->{+STAGE} = STAGE_COMPLETE();
305             }
306              
307             1;
308              
309             __END__