File Coverage

blib/lib/Test2/API/Instance.pm
Criterion Covered Total %
statement 249 261 95.4
branch 96 122 78.6
condition 36 58 62.0
subroutine 36 37 97.3
pod 15 17 88.2
total 432 495 87.2


line stmt bran cond sub pod time code
1             package Test2::API::Instance;
2 62     62   1037 use strict;
  57         58  
  57         1288  
3 57     57   157 use warnings;
  57         63  
  57         2675  
4              
5             our $VERSION = '0.000044';
6              
7             our @CARP_NOT = qw/Test2::API Test2::API::Instance Test2::IPC::Driver Test2::Formatter/;
8 57     57   216 use Carp qw/confess carp/;
  57         63  
  57         3065  
9 57     57   202 use Scalar::Util qw/reftype/;
  57         65  
  57         3341  
10              
11 57     57   8123 use Test2::Util qw/get_tid USE_THREADS CAN_FORK pkg_to_file try/;
  57         75  
  57         2657  
12              
13 57     57   18294 use Test2::Util::Trace();
  57         91  
  57         808  
14 57     57   18380 use Test2::API::Stack();
  57         92  
  57         1640  
15              
16 57         224 use Test2::Util::HashBase qw{
17             pid tid
18             no_wait
19             finalized loaded
20             ipc stack formatter
21             contexts
22              
23             ipc_shm_size
24             ipc_shm_last
25             ipc_shm_id
26             ipc_polling
27             ipc_drivers
28             formatters
29              
30             exit_callbacks
31             post_load_callbacks
32             context_acquire_callbacks
33             context_init_callbacks
34             context_release_callbacks
35 57     57   240 };
  57         68  
36              
37             # Wrap around the getters that should call _finalize.
38             BEGIN {
39 57     57   112 for my $finalizer (IPC, FORMATTER) {
40 114         2210 my $orig = __PACKAGE__->can($finalizer);
41             my $new = sub {
42 207     207   308 my $self = shift;
43 207 100       658 $self->_finalize unless $self->{+FINALIZED};
44 201         580 $self->$orig;
45 114         272 };
46              
47 57     57   302 no strict 'refs';
  57         73  
  57         1507  
48 57     57   179 no warnings 'redefine';
  57         856  
  57         5665  
49 114         101 *{$finalizer} = $new;
  114         126557  
50             }
51             }
52              
53             sub import {
54 78     78   108 my $class = shift;
55 78 100       611 return unless @_;
56 57         74 my ($ref) = @_;
57 57         162 $$ref = $class->new;
58             }
59              
60 62     62 0 118 sub init { $_[0]->reset }
61              
62             sub reset {
63 154     154 1 1106 my $self = shift;
64              
65 154         837 $self->{+PID} = $$;
66 154         167 $self->{+TID} = get_tid();
67 154         195 $self->{+CONTEXTS} = {};
68              
69 154         211 $self->{+IPC_DRIVERS} = [];
70 154         181 $self->{+IPC_POLLING} = undef;
71              
72 154         524 $self->{+FORMATTERS} = [];
73 154         191 $self->{+FORMATTER} = undef;
74              
75 154         185 $self->{+FINALIZED} = undef;
76 154         185 $self->{+IPC} = undef;
77              
78 154         179 $self->{+NO_WAIT} = 0;
79 154         129 $self->{+LOADED} = 0;
80              
81 154         153 $self->{+EXIT_CALLBACKS} = [];
82 154         153 $self->{+POST_LOAD_CALLBACKS} = [];
83 154         152 $self->{+CONTEXT_ACQUIRE_CALLBACKS} = [];
84 154         167 $self->{+CONTEXT_INIT_CALLBACKS} = [];
85 154         293 $self->{+CONTEXT_RELEASE_CALLBACKS} = [];
86              
87 154         785 $self->{+STACK} = Test2::API::Stack->new;
88             }
89              
90             sub _finalize {
91 94     94   261 my $self = shift;
92 94         130 my ($caller) = @_;
93 94   50     1133 $caller ||= [caller(1)];
94              
95 94         190 $self->{+FINALIZED} = $caller;
96              
97 94 100       307 unless ($self->{+FORMATTER}) {
98 89         130 my ($formatter, $source);
99 89 100       239 if ($ENV{T2_FORMATTER}) {
    100          
100 15         10 $source = "set by the 'T2_FORMATTER' environment variable";
101              
102 15 50       75 if ($ENV{T2_FORMATTER} =~ m/^(\+)?(.*)$/) {
103 15 100       55 $formatter = $1 ? $2 : "Test2::Formatter::$2"
104             }
105             else {
106 0         0 $formatter = '';
107             }
108             }
109 74         335 elsif (@{$self->{+FORMATTERS}}) {
110 1         1 ($formatter) = @{$self->{+FORMATTERS}};
  1         2  
111 1         1 $source = "Most recently added";
112             }
113             else {
114 73         136 $formatter = 'Test2::Formatter::TAP';
115 73         117 $source = 'default formatter';
116             }
117              
118 89 100 66     1005 unless (ref($formatter) || $formatter->can('write')) {
119 60         234 my $file = pkg_to_file($formatter);
120 60     60   325 my ($ok, $err) = try { require $file };
  60         25354  
121 60 100       296 unless ($ok) {
122 5         20 my $line = "* COULD NOT LOAD FORMATTER '$formatter' ($source) *";
123 5         10 my $border = '*' x length($line);
124 5         30 die "\n\n $border\n $line\n $border\n\n$err";
125             }
126             }
127              
128 84         211 $self->{+FORMATTER} = $formatter;
129             }
130              
131             # Turn on IPC if threads are on, drivers are reigstered, or the Test2::IPC
132             # module is loaded.
133 89 100 100     295 return unless USE_THREADS || $INC{'Test2/IPC.pm'} || @{$self->{+IPC_DRIVERS}};
  39         210  
134              
135             # Turn on polling by default, people expect it.
136 53         166 $self->enable_ipc_polling;
137              
138 53 100       48 unless (@{$self->{+IPC_DRIVERS}}) {
  53         151  
139 50     50   275 my ($ok, $error) = try { require Test2::IPC::Driver::Files };
  50         9259  
140 50 50       192 die $error unless $ok;
141 50         56 push @{$self->{+IPC_DRIVERS}} => 'Test2::IPC::Driver::Files';
  50         133  
142             }
143              
144 53         79 for my $driver (@{$self->{+IPC_DRIVERS}}) {
  53         110  
145 53 100 66     595 next unless $driver->can('is_viable') && $driver->is_viable;
146 52 50       241 $self->{+IPC} = $driver->new or next;
147 52 50       148 $self->ipc_enable_shm if $self->{+IPC}->use_shm;
148 52         87 return;
149             }
150              
151 1         8 die "IPC has been requested, but no viable drivers were found. Aborting...\n";
152             }
153              
154 11 100   11 1 154 sub formatter_set { $_[0]->{+FORMATTER} ? 1 : 0 }
155              
156             sub add_formatter {
157 1     1 1 1 my $self = shift;
158 1         2 my ($formatter) = @_;
159 1         1 unshift @{$self->{+FORMATTERS}} => $formatter;
  1         2  
160              
161 1 50       23 return unless $self->{+FINALIZED};
162              
163             # Why is the @CARP_NOT entry not enough?
164 0         0 local %Carp::Internal = %Carp::Internal;
165 0         0 $Carp::Internal{'Test2::Formatter'} = 1;
166              
167 0         0 carp "Formatter $formatter loaded too late to be used as the global formatter";
168             }
169              
170             sub add_context_acquire_callback {
171 3     3 0 4 my $self = shift;
172 3         5 my ($code) = @_;
173              
174 3   50     11 my $rtype = reftype($code) || "";
175              
176 3 50 33     17 confess "Context-acquire callbacks must be coderefs"
177             unless $code && $rtype eq 'CODE';
178              
179 3         4 push @{$self->{+CONTEXT_ACQUIRE_CALLBACKS}} => $code;
  3         6  
180             }
181              
182             sub add_context_init_callback {
183 57     57 1 71 my $self = shift;
184 57         59 my ($code) = @_;
185              
186 57   50     362 my $rtype = reftype($code) || "";
187              
188 57 50 33     296 confess "Context-init callbacks must be coderefs"
189             unless $code && $rtype eq 'CODE';
190              
191 57         55 push @{$self->{+CONTEXT_INIT_CALLBACKS}} => $code;
  57         139  
192             }
193              
194             sub add_context_release_callback {
195 4     4 1 5 my $self = shift;
196 4         5 my ($code) = @_;
197              
198 4   50     19 my $rtype = reftype($code) || "";
199              
200 4 50 33     19 confess "Context-release callbacks must be coderefs"
201             unless $code && $rtype eq 'CODE';
202              
203 4         4 push @{$self->{+CONTEXT_RELEASE_CALLBACKS}} => $code;
  4         13  
204             }
205              
206             sub add_post_load_callback {
207 18     18 1 68 my $self = shift;
208 18         21 my ($code) = @_;
209              
210 18   50     58 my $rtype = reftype($code) || "";
211              
212 18 100 66     907 confess "Post-load callbacks must be coderefs"
213             unless $code && $rtype eq 'CODE';
214              
215 13         13 push @{$self->{+POST_LOAD_CALLBACKS}} => $code;
  13         29  
216 13 100       41 $code->() if $self->{+LOADED};
217             }
218              
219             sub load {
220 67     67 1 116 my $self = shift;
221 67 100       210 unless ($self->{+LOADED}) {
222             # This is for https://github.com/Test-More/test-more/issues/16
223             # and https://rt.perl.org/Public/Bug/Display.html?id=127774
224             # END blocks run in reverse order. This insures the END block is loaded
225             # as late as possible. It will not solve all cases, but it helps.
226 55 50   55   8027 eval "END { Test2::API::test2_set_is_end() }; 1" or die $@;
  62         3632  
227              
228 62         246 $self->{+LOADED} = 1;
229 62         109 $_->() for @{$self->{+POST_LOAD_CALLBACKS}};
  62         329  
230             }
231 67         156 return $self->{+LOADED};
232             }
233              
234             sub add_exit_callback {
235 18     18 1 69 my $self = shift;
236 18         23 my ($code) = @_;
237 18   50     54 my $rtype = reftype($code) || "";
238              
239 18 100 66     486 confess "End callbacks must be coderefs"
240             unless $code && $rtype eq 'CODE';
241              
242 13         18 push @{$self->{+EXIT_CALLBACKS}} => $code;
  13         26  
243             }
244              
245             sub add_ipc_driver {
246 5     5 1 19 my $self = shift;
247 5         6 my ($driver) = @_;
248 5         6 unshift @{$self->{+IPC_DRIVERS}} => $driver;
  5         15  
249              
250 5 100       33 return unless $self->{+FINALIZED};
251              
252             # Why is the @CARP_NOT entry not enough?
253 2         10 local %Carp::Internal = %Carp::Internal;
254 2         5 $Carp::Internal{'Test2::IPC::Driver'} = 1;
255              
256 2         468 carp "IPC driver $driver loaded too late to be used as the global ipc driver";
257             }
258              
259             sub enable_ipc_polling {
260 56     56 1 70 my $self = shift;
261              
262             $self->add_context_init_callback(
263             # This is called every time a context is created, it needs to be fast.
264             # $_[0] is a context object
265             sub {
266 601 100   601   1094 return unless $self->{+IPC_POLLING};
267 599 100       991 return $_[0]->{hub}->cull unless $self->{+IPC_SHM_ID};
268              
269 589         490 my $val;
270             {
271 589 50       728 shmread($self->{+IPC_SHM_ID}, $val, 0, $self->{+IPC_SHM_SIZE}) or return;
  589         9830  
272              
273 589 100       2768 return if $val eq $self->{+IPC_SHM_LAST};
274 8         26 $self->{+IPC_SHM_LAST} = $val;
275             }
276              
277 8         49 $_[0]->{hub}->cull;
278             }
279 56 100       197 ) unless defined $self->ipc_polling;
280              
281 56         170 $self->set_ipc_polling(1);
282             }
283              
284             sub ipc_enable_shm {
285 52     52 1 80 my $self = shift;
286              
287 52 100       169 return 1 if defined $self->{+IPC_SHM_ID};
288              
289             my ($ok, $err) = try {
290 27     27   9313 require IPC::SysV;
291              
292 27         17457 my $ipc_key = IPC::SysV::IPC_PRIVATE();
293 27 50       561 my $shm_size = $self->{+IPC}->can('shm_size') ? $self->{+IPC}->shm_size : 64;
294 27 100       644 my $shm_id = shmget($ipc_key, $shm_size, 0666) or die;
295              
296 23         66 my $initial = 'a' x $shm_size;
297 23 50       833 shmwrite($shm_id, $initial, 0, $shm_size) or die;
298              
299 23         67 $self->{+IPC_SHM_SIZE} = $shm_size;
300 23         43 $self->{+IPC_SHM_ID} = $shm_id;
301 23         84 $self->{+IPC_SHM_LAST} = $initial;
302 27         169 };
303              
304 27         141 return $ok;
305             }
306              
307             sub get_ipc_pending {
308 0     0 1 0 my $self = shift;
309 0 0       0 return -1 unless defined $self->{+IPC_SHM_ID};
310 0         0 my $val;
311 0 0       0 shmread($self->{+IPC_SHM_ID}, $val, 0, $self->{+IPC_SHM_SIZE}) or return -1;
312 0 0       0 return 0 if $val eq $self->{+IPC_SHM_LAST};
313 0         0 $self->{+IPC_SHM_LAST} = $val;
314 0         0 return 1;
315             }
316              
317             sub set_ipc_pending {
318 33     33 1 65 my $self = shift;
319              
320 33 100       127 return undef unless defined $self->{+IPC_SHM_ID};
321              
322 20         58 my ($val) = @_;
323              
324 20 50       40 confess "value is required for set_ipc_pending"
325             unless $val;
326              
327 20         389 shmwrite($self->{+IPC_SHM_ID}, $val, 0, $self->{+IPC_SHM_SIZE});
328             }
329              
330             sub disable_ipc_polling {
331 3     3 1 7 my $self = shift;
332 3 100       13 return unless defined $self->{+IPC_POLLING};
333 2         4 $self->{+IPC_POLLING} = 0;
334             }
335              
336             sub _ipc_wait {
337 23     23   2970 my $fail = 0;
338              
339 23         70 while (CAN_FORK) {
340 37         16136741 my $pid = CORE::wait();
341 37         152 my $err = $?;
342 37 100       189 last if $pid == -1;
343 14 100       74 next unless $err;
344 6         17 $fail++;
345 6         18 $err = $err >> 8;
346 6         238 warn "Process $pid did not exit cleanly (status: $err)\n";
347             }
348              
349 23         35 if (USE_THREADS) {
350             for my $t (threads->list()) {
351             $t->join;
352             # In older threads we cannot check if a thread had an error unless
353             # we control it and its return.
354             my $err = $t->can('error') ? $t->error : undef;
355             next unless $err;
356             my $tid = $t->tid();
357             $fail++;
358             chomp($err);
359             warn "Thread $tid did not end cleanly: $err\n";
360             }
361             }
362              
363 23 100       130 return 0 unless $fail;
364 6         42 return 255;
365             }
366              
367             sub set_exit {
368 88     88 1 3982 my $self = shift;
369              
370 88         172 my $exit = $?;
371 88         253 my $new_exit = $exit;
372              
373             # if ($INC{'Test/Builder.pm'} && $Test::Builder::VERSION ne $Test2::API::VERSION) {
374             # print STDERR <<" EOT";
375             #
376             #********************************************************************************
377             #* *
378             #* Test::Builder -- Test2::API version mismatch detected *
379             #* *
380             #********************************************************************************
381             # Test2::API Version: $Test2::API::VERSION
382             #Test::Builder Version: $Test::Builder::VERSION
383             #
384             #This is not a supported configuration, you will have problems.
385             #
386             # EOT
387             # }
388              
389 88         120 for my $ctx (values %{$self->{+CONTEXTS}}) {
  88         336  
390 5 100       16 next unless $ctx;
391              
392 1 50 33     7 next if $ctx->_aborted && ${$ctx->_aborted};
  0         0  
393              
394             # Only worry about contexts in this PID
395 1   50     4 my $trace = $ctx->trace || next;
396 1 50       6 next unless $trace->pid == $$;
397              
398             # Do not worry about contexts that have no hub
399 1   50     6 my $hub = $ctx->hub || next;
400              
401             # Do not worry if the state came to a sudden end.
402 1 50       5 next if $hub->bailed_out;
403 1 50       5 next if defined $hub->skip_reason;
404              
405             # now we worry
406 1         6 $trace->alert("context object was never released! This means a testing tool is behaving very badly");
407              
408 1         4 $exit = 255;
409 1         2 $new_exit = 255;
410             }
411              
412 88 100 100     712 if ($self->{+PID} != $$ or $self->{+TID} != get_tid()) {
413 13         24 $? = $exit;
414 13         6 return;
415             }
416              
417 75 50       428 my @hubs = $self->{+STACK} ? $self->{+STACK}->all : ();
418              
419 75 100 66     467 if (@hubs and $self->{+IPC} and !$self->{+NO_WAIT}) {
      66        
420 16         51 local $?;
421 16         41 my %seen;
422 16         39 for my $hub (reverse @hubs) {
423 16 50       93 my $ipc = $hub->ipc or next;
424 16 50       370 next if $seen{$ipc}++;
425 16         83 $ipc->waiting();
426             }
427              
428 16         42 my $ipc_exit = _ipc_wait();
429 16   100     115 $new_exit ||= $ipc_exit;
430             }
431              
432             # None of this is necessary if we never got a root hub
433 75 100       224 if(my $root = shift @hubs) {
434 66         484 my $trace = Test2::Util::Trace->new(
435             frame => [__PACKAGE__, __FILE__, 0, __PACKAGE__ . '::END'],
436             detail => __PACKAGE__ . ' END Block finalization',
437             );
438 66         283 my $ctx = Test2::API::Context->new(
439             trace => $trace,
440             hub => $root,
441             );
442              
443 66 100       181 if (@hubs) {
444 6         24 $ctx->diag("Test ended with extra hubs on the stack!");
445 6         6 $new_exit = 255;
446             }
447              
448 66 100       276 unless ($root->no_ending) {
449 63         160 local $?;
450 63 100       204 $root->finalize($trace) unless $root->ended;
451 63         76 $_->($ctx, $exit, \$new_exit) for @{$self->{+EXIT_CALLBACKS}};
  63         215  
452 63   100     447 $new_exit ||= $root->failed;
453             }
454             }
455              
456 75 100       208 $new_exit = 255 if $new_exit > 255;
457              
458 75 100       163 if ($new_exit) {
459 19         2179 require Test2::API::Breakage;
460 19         87 my @warn = Test2::API::Breakage->report();
461              
462 19 100       41 if (@warn) {
463 3         12 print STDERR "\nYou have loaded versions of test modules known to have problems with Test2.\nThis could explain some test failures.\n";
464 3         12 print STDERR "$_\n" for @warn;
465 3         6 print STDERR "\n";
466             }
467             }
468              
469 75         71 $? = $new_exit;
470             }
471              
472             1;
473              
474             __END__