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   707 use strict;
  28         59  
  28         687  
3 28     28   136 use warnings;
  28         50  
  28         759  
4              
5 28     28   137 use Carp qw/croak/;
  28         49  
  28         1642  
6 28     28   149 use Scalar::Util qw/reftype/;
  28         60  
  28         1273  
7 28     28   178 use Test::Stream::Sync;
  28         68  
  28         792  
8 28     28   152 use Test::Stream::Util qw/CAN_SET_SUB_NAME set_sub_name update_mask/;
  28         65  
  28         183  
9              
10             use overload(
11             'fallback' => 1,
12             '&{}' => sub {
13 31     31   300 my $self = shift;
14 31         258 my @caller = caller(0);
15 31         257 update_mask($caller[1], $caller[2], '*', {restart => 1, stop => 1, 3 => 'CONTINUE'});
16 31     31   152 my $out = sub { $self->iterate(@_) };
  31         155  
17 31         257 set_sub_name(__PACKAGE__ . '::iterator', $out)
18             if CAN_SET_SUB_NAME;
19 31         123 return $out;
20             },
21 28     28   167 );
  28         53  
  28         340  
22              
23 28     28   2341 use Test::Stream::Workflow qw/push_workflow_vars pop_workflow_vars/;
  28         56  
  28         192  
24 28     28   17983 use Test::Stream::Plugin::Subtest qw/subtest_buffered/;
  28         81  
  28         261  
25 28     28   169 use Test::Stream::Util qw/try set_sub_name CAN_SET_SUB_NAME/;
  28         52  
  28         186  
26              
27             use Test::Stream::HashBase(
28 28         192 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   149 );
  28         59  
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 563 my $self = shift;
47              
48             croak "Attribute 'unit' is required"
49 316 100       2008 unless $self->{+UNIT};
50              
51 315   100     864 $self->{+ARGS} ||= [];
52              
53 315         832 $self->reset;
54             }
55              
56             sub finished {
57 672     672 1 991 my $self = shift;
58 672 100       1894 return 1 if $self->{+EXCEPTION};
59 671 100       1829 return 1 if $self->{+STAGE} >= STAGE_COMPLETE();
60              
61 668         1894 return 0;
62             }
63              
64             sub subtest {
65 312     312 1 469 my $self = shift;
66 312 100       1037 return 0 if $self->{+NO_FINAL};
67 204 100       634 return 0 if $self->{+NO_SUBTEST};
68 203         601 return 1;
69             }
70              
71             sub reset {
72 345     345 1 637 my $self = shift;
73              
74 345         879 $self->{+STAGE} = STAGE_BUILDUP();
75 345         695 $self->{+_BUILDUP_IDX} = 0;
76 345         989 $self->{+_TEARDOWN_IDX} = 0;
77 345         647 $self->{+FAILED} = 0;
78 345         640 $self->{+EVENTS} = 0;
79 345         573 $self->{+PENDING} = 0;
80 345         1071 $self->{+EXCEPTION} = undef;
81             }
82              
83             sub _have_primary {
84 326     326   495 my $self = shift;
85              
86 326         1350 my $primary = $self->{+UNIT}->primary;
87              
88             # Make sure we have primary, and that it is a ref
89 326 100       1564 return 0 unless $primary;
90 323 100       830 return 0 unless ref $primary;
91              
92             # code ref is fine
93 322         871 my $type = reftype($primary);
94 322 100       1355 return 1 if $type eq 'CODE';
95              
96             # array ref is fine if it is populated
97 44 100       154 return 0 unless $type eq 'ARRAY';
98 43         291 return @$primary;
99             }
100              
101             sub should_run {
102 327     327 1 488 my $self = shift;
103 327 100       1492 return 1 unless defined $ENV{TS_WORKFLOW};
104 3 100       18 return 1 if $self->{+NO_FINAL};
105 2 100       13 return 1 if $self->{+UNIT}->contains($ENV{TS_WORKFLOW});
106 1         12 return 0;
107             }
108              
109             sub run {
110 325     325 1 534 my $self = shift;
111              
112 325 100       833 return if $self->finished;
113 324 100       855 return unless $self->should_run;
114              
115 323         675 my $unit = $self->{+UNIT};
116 323         1115 my $ctx = $unit->context;
117              
118             # Skip?
119 323 100       1213 if ($ctx->debug->skip) {
120 3         24 $self->{+STAGE} = STAGE_COMPLETE();
121 3         15 $ctx->ok(1, $self->{+UNIT}->name);
122 3         13 return;
123             }
124              
125             # Make sure we have something to do!
126 320 100       2608 unless ($self->_have_primary) {
127 2 100       21 return if $self->{+UNIT}->is_root;
128 1         4 $self->{+STAGE} = STAGE_COMPLETE();
129 1         7 $ctx->ok(0, $self->{+UNIT}->name, ['No primary actions defined! Nothing to do!']);
130 1         5 return;
131             }
132              
133 318         459 my $vars;
134 318 100       1530 $vars = push_workflow_vars({}) unless $self->{+NO_FINAL};
135              
136 318 100       854 if ($self->subtest) {
137             $ctx->do_in_context(
138             \&subtest_buffered,
139             $self->{+UNIT}->name,
140             sub {
141 205     175   718 $self->iterate();
142             $ctx->ok(0, $unit->name, ["No events were generated"])
143 204 100       925 unless $self->{+EVENTS};
144             }
145 205         1013 );
146             }
147             else {
148 113         360 $self->iterate();
149              
150             $ctx->ok(0, $unit->name, ["No events were generated"])
151 112 100 66     451 unless $self->{+EVENTS} || $self->{+NO_FINAL};
152              
153             $ctx->ok(!$self->{+FAILED}, $unit->name)
154 112 100 100     761 if $self->{+FAILED} || !$self->{+NO_FINAL};
155             }
156              
157 316 100       2187 pop_workflow_vars($vars) if $vars;
158              
159             # In case something is holding a reference to vars itself.
160 316         592 %$vars = ();
161 316         494 $vars = undef;
162              
163 316         1242 return;
164             }
165              
166             sub iterate {
167 344     344 1 640 my $self = shift;
168              
169 344 100       1068 $self->{+PENDING}-- if $self->{+PENDING};
170              
171 344 100       819 return if $self->finished;
172              
173             my ($ok, $err) = try {
174 343 100   314   1806 $self->_run_buildups if $self->{+STAGE} == STAGE_BUILDUP();
175 342 100       1487 $self->_run_primaries if $self->{+STAGE} == STAGE_PRIMARY();
176 338 100       1924 $self->_run_teardowns if $self->{+STAGE} == STAGE_TEARDOWN();
177 343         2245 };
178              
179 341 100       1853 unless ($ok) {
180 3         7 $self->{+FAILED}++;
181 3         8 $self->{+EXCEPTION} = $err;
182 3         14 $self->unit->context->send_event('Exception', error => $err);
183             }
184              
185 341         716 return;
186             }
187              
188             sub _run_buildups {
189 345     345   561 my $self = shift;
190              
191 345         1455 my $buildups = $self->{+UNIT}->buildup;
192              
193             # No Buildups
194 345 100       1721 unless ($buildups) {
195 248 50       853 $self->{+STAGE} = STAGE_PRIMARY() if $self->{+STAGE} == STAGE_BUILDUP();
196 248         486 return;
197             }
198              
199 97         344 while ($self->{+_BUILDUP_IDX} < @$buildups) {
200 77         214 my $bunit = $buildups->[$self->{+_BUILDUP_IDX}++];
201 77 100       294 if ($bunit->wrap) {
202 35         194 $self->{+PENDING}++;
203 35         210 $self->runner->run(unit => $bunit, no_final => 1, args => [$self]);
204 35 100       246 if ($self->{+PENDING}) {
205 3         7 $self->{+PENDING}--;
206 3         15 my $ctx = $bunit->context;
207 3         12 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         276 $self->runner->run(unit => $bunit, no_final => 1, args => $self->{+ARGS});
213             }
214             }
215              
216 97 100       375 $self->{+STAGE} = STAGE_PRIMARY() if $self->{+STAGE} == STAGE_BUILDUP();
217             }
218              
219             sub _listener {
220 318     318   548 my $self = shift;
221              
222             return sub {
223 1285     1285   1962 my ($hub, $e) = @_;
224 1285         2481 $self->{+EVENTS}++;
225 1285 100       3634 $self->{+FAILED}++ if $e->causes_fail;
226 318 100       1882 } unless $self->{+NO_FINAL};
227              
228 109         403 my $ctx = $self->{+UNIT}->context;
229 109         411 my $trace = $ctx->debug->trace;
230 109 100       473 $trace = "wrapped $trace" if $self->{+UNIT}->wrap;
231              
232             return sub {
233 490     490   846 my ($hub, $e) = @_;
234 490         1176 $self->{+EVENTS}++;
235 490 100       1746 return unless $e->causes_fail;
236 14         27 $self->{+FAILED}++;
237 14 100       89 return unless $e->can('diag');
238 11 50       39 $e->set_diag([]) unless $e->diag;
239 11         46 push @{$e->diag} => $trace;
  11         27  
240 109         1196 };
241             }
242              
243             sub _run_primary {
244 316     316   1990 my $self = shift;
245 316         566 my $unit = $self->{+UNIT};
246 316         1019 my $primary = $unit->primary;
247              
248 316         2120 my $hub = Test::Stream::Sync->stack->top;
249 316 50       1224 my $l = $hub->listen($self->_listener) if $hub->is_local;
250              
251 316 100       1293 if(reftype($primary) eq 'ARRAY') {
252 46         277 $self->runner->run(unit => $_, args => $self->{+ARGS}) for @$primary
253             }
254             else {
255 28     28   245 BEGIN { update_mask(__FILE__, __LINE__ + 1, '*', {stop => 1, hide => 1}) }
256 270         449 $primary->(@{$self->{+ARGS}});
  270         1190  
257             }
258              
259 312 50       2843 $hub->unlisten($l) if $l;
260             }
261              
262             sub _run_primaries {
263 312     312   475 my $self = shift;
264              
265             # Make sure this does not run again
266 312 50       1047 $self->{+STAGE} = STAGE_TEARDOWN() if $self->{+STAGE} < STAGE_TEARDOWN();
267              
268 312   100     1215 my $modifiers = $self->{+UNIT}->modify || return $self->_run_primary();
269              
270 6         42 for my $mod (@$modifiers) {
271             my $primary = sub {
272 10     10   18 $mod->primary->(@{$self->{+ARGS}});
  10         49  
273 10         75 $self->_run_primary();
274 10         66 };
275              
276 10         53 my $name = $mod->name;
277 10         109 set_sub_name($name, $primary) if CAN_SET_SUB_NAME;
278              
279 10         136 my $temp = Test::Stream::Workflow::Unit->new(
280             %$mod,
281             primary => $primary,
282             );
283 10         60 $self->runner->run(unit => $temp, args => $self->{+ARGS});
284             }
285             }
286              
287             sub _run_teardowns {
288 340     340   557 my $self = shift;
289              
290 340         1487 my $teardowns = $self->{+UNIT}->teardown;
291 340 100       1707 unless ($teardowns) {
292 275         557 $self->{+STAGE} = STAGE_COMPLETE();
293 275         767 return;
294             }
295              
296 65         218 while($self->{+_TEARDOWN_IDX} < @$teardowns) {
297 45         135 my $tunit = $teardowns->[$self->{+_TEARDOWN_IDX}++];
298             # Popping a wrap
299 45 100       181 return if $tunit->wrap;
300              
301 12         74 $self->runner->run(unit => $tunit, no_final => 1, args => $self->{+ARGS});
302             }
303              
304 32         117 $self->{+STAGE} = STAGE_COMPLETE();
305             }
306              
307             1;
308              
309             __END__