xref: /openbsd-src/gnu/usr.bin/perl/cpan/Test-Simple/lib/Test2/API/Instance.pm (revision 5486feefcc8cb79b19e014ab332cc5dfd05b3b33)
15759b3d2Safresh1package Test2::API::Instance;
25759b3d2Safresh1use strict;
35759b3d2Safresh1use warnings;
45759b3d2Safresh1
5*5486feefSafresh1our $VERSION = '1.302199';
65759b3d2Safresh1
75759b3d2Safresh1our @CARP_NOT = qw/Test2::API Test2::API::Instance Test2::IPC::Driver Test2::Formatter/;
85759b3d2Safresh1use Carp qw/confess carp/;
95759b3d2Safresh1use Scalar::Util qw/reftype/;
105759b3d2Safresh1
115759b3d2Safresh1use Test2::Util qw/get_tid USE_THREADS CAN_FORK pkg_to_file try CAN_SIGSYS/;
125759b3d2Safresh1
135759b3d2Safresh1use Test2::EventFacet::Trace();
145759b3d2Safresh1use Test2::API::Stack();
155759b3d2Safresh1
165759b3d2Safresh1use Test2::Util::HashBase qw{
175759b3d2Safresh1    _pid _tid
185759b3d2Safresh1    no_wait
195759b3d2Safresh1    finalized loaded
205759b3d2Safresh1    ipc stack formatter
215759b3d2Safresh1    contexts
225759b3d2Safresh1
235759b3d2Safresh1    add_uuid_via
245759b3d2Safresh1
255759b3d2Safresh1    -preload
265759b3d2Safresh1
275759b3d2Safresh1    ipc_disabled
285759b3d2Safresh1    ipc_polling
295759b3d2Safresh1    ipc_drivers
305759b3d2Safresh1    ipc_timeout
315759b3d2Safresh1    formatters
325759b3d2Safresh1
335759b3d2Safresh1    exit_callbacks
345759b3d2Safresh1    post_load_callbacks
355759b3d2Safresh1    context_acquire_callbacks
365759b3d2Safresh1    context_init_callbacks
375759b3d2Safresh1    context_release_callbacks
385759b3d2Safresh1    pre_subtest_callbacks
39*5486feefSafresh1
40*5486feefSafresh1    trace_stamps
415759b3d2Safresh1};
425759b3d2Safresh1
435759b3d2Safresh1sub DEFAULT_IPC_TIMEOUT() { 30 }
445759b3d2Safresh1
45*5486feefSafresh1sub test2_enable_trace_stamps { $_[0]->{+TRACE_STAMPS} = 1 }
46*5486feefSafresh1sub test2_disable_trace_stamps { $_[0]->{+TRACE_STAMPS} = 0 }
47*5486feefSafresh1sub test2_trace_stamps_enabled { $_[0]->{+TRACE_STAMPS} }
48*5486feefSafresh1
495759b3d2Safresh1sub pid { $_[0]->{+_PID} }
505759b3d2Safresh1sub tid { $_[0]->{+_TID} }
515759b3d2Safresh1
525759b3d2Safresh1# Wrap around the getters that should call _finalize.
535759b3d2Safresh1BEGIN {
545759b3d2Safresh1    for my $finalizer (IPC, FORMATTER) {
555759b3d2Safresh1        my $orig = __PACKAGE__->can($finalizer);
565759b3d2Safresh1        my $new  = sub {
575759b3d2Safresh1            my $self = shift;
585759b3d2Safresh1            $self->_finalize unless $self->{+FINALIZED};
595759b3d2Safresh1            $self->$orig;
605759b3d2Safresh1        };
615759b3d2Safresh1
625759b3d2Safresh1        no strict 'refs';
635759b3d2Safresh1        no warnings 'redefine';
645759b3d2Safresh1        *{$finalizer} = $new;
655759b3d2Safresh1    }
665759b3d2Safresh1}
675759b3d2Safresh1
685759b3d2Safresh1sub has_ipc { !!$_[0]->{+IPC} }
695759b3d2Safresh1
705759b3d2Safresh1sub import {
715759b3d2Safresh1    my $class = shift;
725759b3d2Safresh1    return unless @_;
735759b3d2Safresh1    my ($ref) = @_;
745759b3d2Safresh1    $$ref = $class->new;
755759b3d2Safresh1}
765759b3d2Safresh1
775759b3d2Safresh1sub init { $_[0]->reset }
785759b3d2Safresh1
795759b3d2Safresh1sub start_preload {
805759b3d2Safresh1    my $self = shift;
815759b3d2Safresh1
825759b3d2Safresh1    confess "preload cannot be started, Test2::API has already been initialized"
835759b3d2Safresh1        if $self->{+FINALIZED} || $self->{+LOADED};
845759b3d2Safresh1
855759b3d2Safresh1    return $self->{+PRELOAD} = 1;
865759b3d2Safresh1}
875759b3d2Safresh1
885759b3d2Safresh1sub stop_preload {
895759b3d2Safresh1    my $self = shift;
905759b3d2Safresh1
915759b3d2Safresh1    return 0 unless $self->{+PRELOAD};
925759b3d2Safresh1    $self->{+PRELOAD} = 0;
935759b3d2Safresh1
945759b3d2Safresh1    $self->post_preload_reset();
955759b3d2Safresh1
965759b3d2Safresh1    return 1;
975759b3d2Safresh1}
985759b3d2Safresh1
995759b3d2Safresh1sub post_preload_reset {
1005759b3d2Safresh1    my $self = shift;
1015759b3d2Safresh1
1025759b3d2Safresh1    delete $self->{+_PID};
1035759b3d2Safresh1    delete $self->{+_TID};
1045759b3d2Safresh1
1055759b3d2Safresh1    $self->{+ADD_UUID_VIA} = undef unless exists $self->{+ADD_UUID_VIA};
1065759b3d2Safresh1
1075759b3d2Safresh1    $self->{+CONTEXTS} = {};
1085759b3d2Safresh1
1095759b3d2Safresh1    $self->{+FORMATTERS} = [];
1105759b3d2Safresh1
1115759b3d2Safresh1    $self->{+FINALIZED} = undef;
1125759b3d2Safresh1    $self->{+IPC}       = undef;
1135759b3d2Safresh1    $self->{+IPC_DISABLED} = $ENV{T2_NO_IPC} ? 1 : 0;
1145759b3d2Safresh1
1155759b3d2Safresh1    $self->{+IPC_TIMEOUT} = DEFAULT_IPC_TIMEOUT() unless defined $self->{+IPC_TIMEOUT};
1165759b3d2Safresh1
1175759b3d2Safresh1    $self->{+LOADED} = 0;
1185759b3d2Safresh1
1195759b3d2Safresh1    $self->{+STACK} ||= Test2::API::Stack->new;
1205759b3d2Safresh1}
1215759b3d2Safresh1
1225759b3d2Safresh1sub reset {
1235759b3d2Safresh1    my $self = shift;
1245759b3d2Safresh1
1255759b3d2Safresh1    delete $self->{+_PID};
1265759b3d2Safresh1    delete $self->{+_TID};
1275759b3d2Safresh1
128*5486feefSafresh1    $self->{+TRACE_STAMPS} = $ENV{T2_TRACE_STAMPS} || 0;
129*5486feefSafresh1
1305759b3d2Safresh1    $self->{+ADD_UUID_VIA} = undef;
1315759b3d2Safresh1
1325759b3d2Safresh1    $self->{+CONTEXTS} = {};
1335759b3d2Safresh1
1345759b3d2Safresh1    $self->{+IPC_DRIVERS} = [];
1355759b3d2Safresh1    $self->{+IPC_POLLING} = undef;
1365759b3d2Safresh1
1375759b3d2Safresh1    $self->{+FORMATTERS} = [];
1385759b3d2Safresh1    $self->{+FORMATTER}  = undef;
1395759b3d2Safresh1
1405759b3d2Safresh1    $self->{+FINALIZED}    = undef;
1415759b3d2Safresh1    $self->{+IPC}          = undef;
1425759b3d2Safresh1    $self->{+IPC_DISABLED} = $ENV{T2_NO_IPC} ? 1 : 0;
1435759b3d2Safresh1
1445759b3d2Safresh1    $self->{+IPC_TIMEOUT} = DEFAULT_IPC_TIMEOUT() unless defined $self->{+IPC_TIMEOUT};
1455759b3d2Safresh1
1465759b3d2Safresh1    $self->{+NO_WAIT} = 0;
1475759b3d2Safresh1    $self->{+LOADED}  = 0;
1485759b3d2Safresh1
1495759b3d2Safresh1    $self->{+EXIT_CALLBACKS}            = [];
1505759b3d2Safresh1    $self->{+POST_LOAD_CALLBACKS}       = [];
1515759b3d2Safresh1    $self->{+CONTEXT_ACQUIRE_CALLBACKS} = [];
1525759b3d2Safresh1    $self->{+CONTEXT_INIT_CALLBACKS}    = [];
1535759b3d2Safresh1    $self->{+CONTEXT_RELEASE_CALLBACKS} = [];
1545759b3d2Safresh1    $self->{+PRE_SUBTEST_CALLBACKS}     = [];
1555759b3d2Safresh1
1565759b3d2Safresh1    $self->{+STACK} = Test2::API::Stack->new;
1575759b3d2Safresh1}
1585759b3d2Safresh1
1595759b3d2Safresh1sub _finalize {
1605759b3d2Safresh1    my $self = shift;
1615759b3d2Safresh1    my ($caller) = @_;
1625759b3d2Safresh1    $caller ||= [caller(1)];
1635759b3d2Safresh1
1645759b3d2Safresh1    confess "Attempt to initialize Test2::API during preload"
1655759b3d2Safresh1        if $self->{+PRELOAD};
1665759b3d2Safresh1
1675759b3d2Safresh1    $self->{+FINALIZED} = $caller;
1685759b3d2Safresh1
1695759b3d2Safresh1    $self->{+_PID} = $$        unless defined $self->{+_PID};
1705759b3d2Safresh1    $self->{+_TID} = get_tid() unless defined $self->{+_TID};
1715759b3d2Safresh1
1725759b3d2Safresh1    unless ($self->{+FORMATTER}) {
1735759b3d2Safresh1        my ($formatter, $source);
1745759b3d2Safresh1        if ($ENV{T2_FORMATTER}) {
1755759b3d2Safresh1            $source = "set by the 'T2_FORMATTER' environment variable";
1765759b3d2Safresh1
1775759b3d2Safresh1            if ($ENV{T2_FORMATTER} =~ m/^(\+)?(.*)$/) {
1785759b3d2Safresh1                $formatter = $1 ? $2 : "Test2::Formatter::$2"
1795759b3d2Safresh1            }
1805759b3d2Safresh1            else {
1815759b3d2Safresh1                $formatter = '';
1825759b3d2Safresh1            }
1835759b3d2Safresh1        }
1845759b3d2Safresh1        elsif (@{$self->{+FORMATTERS}}) {
1855759b3d2Safresh1            ($formatter) = @{$self->{+FORMATTERS}};
1865759b3d2Safresh1            $source = "Most recently added";
1875759b3d2Safresh1        }
1885759b3d2Safresh1        else {
1895759b3d2Safresh1            $formatter = 'Test2::Formatter::TAP';
1905759b3d2Safresh1            $source    = 'default formatter';
1915759b3d2Safresh1        }
1925759b3d2Safresh1
1935759b3d2Safresh1        unless (ref($formatter) || $formatter->can('write')) {
1945759b3d2Safresh1            my $file = pkg_to_file($formatter);
1955759b3d2Safresh1            my ($ok, $err) = try { require $file };
1965759b3d2Safresh1            unless ($ok) {
1975759b3d2Safresh1                my $line   = "* COULD NOT LOAD FORMATTER '$formatter' ($source) *";
1985759b3d2Safresh1                my $border = '*' x length($line);
1995759b3d2Safresh1                die "\n\n  $border\n  $line\n  $border\n\n$err";
2005759b3d2Safresh1            }
2015759b3d2Safresh1        }
2025759b3d2Safresh1
2035759b3d2Safresh1        $self->{+FORMATTER} = $formatter;
2045759b3d2Safresh1    }
2055759b3d2Safresh1
2065759b3d2Safresh1    # Turn on IPC if threads are on, drivers are registered, or the Test2::IPC
2075759b3d2Safresh1    # module is loaded.
2085759b3d2Safresh1    return if $self->{+IPC_DISABLED};
2095759b3d2Safresh1    return unless USE_THREADS || $INC{'Test2/IPC.pm'} || @{$self->{+IPC_DRIVERS}};
2105759b3d2Safresh1
2115759b3d2Safresh1    # Turn on polling by default, people expect it.
2125759b3d2Safresh1    $self->enable_ipc_polling;
2135759b3d2Safresh1
2145759b3d2Safresh1    unless (@{$self->{+IPC_DRIVERS}}) {
2155759b3d2Safresh1        my ($ok, $error) = try { require Test2::IPC::Driver::Files };
2165759b3d2Safresh1        die $error unless $ok;
2175759b3d2Safresh1        push @{$self->{+IPC_DRIVERS}} => 'Test2::IPC::Driver::Files';
2185759b3d2Safresh1    }
2195759b3d2Safresh1
2205759b3d2Safresh1    for my $driver (@{$self->{+IPC_DRIVERS}}) {
2215759b3d2Safresh1        next unless $driver->can('is_viable') && $driver->is_viable;
2225759b3d2Safresh1        $self->{+IPC} = $driver->new or next;
2235759b3d2Safresh1        return;
2245759b3d2Safresh1    }
2255759b3d2Safresh1
2265759b3d2Safresh1    die "IPC has been requested, but no viable drivers were found. Aborting...\n";
2275759b3d2Safresh1}
2285759b3d2Safresh1
2295759b3d2Safresh1sub formatter_set { $_[0]->{+FORMATTER} ? 1 : 0 }
2305759b3d2Safresh1
2315759b3d2Safresh1sub add_formatter {
2325759b3d2Safresh1    my $self = shift;
2335759b3d2Safresh1    my ($formatter) = @_;
2345759b3d2Safresh1    unshift @{$self->{+FORMATTERS}} => $formatter;
2355759b3d2Safresh1
2365759b3d2Safresh1    return unless $self->{+FINALIZED};
2375759b3d2Safresh1
2385759b3d2Safresh1    # Why is the @CARP_NOT entry not enough?
2395759b3d2Safresh1    local %Carp::Internal = %Carp::Internal;
2405759b3d2Safresh1    $Carp::Internal{'Test2::Formatter'} = 1;
2415759b3d2Safresh1
2425759b3d2Safresh1    carp "Formatter $formatter loaded too late to be used as the global formatter";
2435759b3d2Safresh1}
2445759b3d2Safresh1
2455759b3d2Safresh1sub add_context_acquire_callback {
2465759b3d2Safresh1    my $self =  shift;
2475759b3d2Safresh1    my ($code) = @_;
2485759b3d2Safresh1
2495759b3d2Safresh1    my $rtype = reftype($code) || "";
2505759b3d2Safresh1
2515759b3d2Safresh1    confess "Context-acquire callbacks must be coderefs"
2525759b3d2Safresh1        unless $code && $rtype eq 'CODE';
2535759b3d2Safresh1
2545759b3d2Safresh1    push @{$self->{+CONTEXT_ACQUIRE_CALLBACKS}} => $code;
2555759b3d2Safresh1}
2565759b3d2Safresh1
2575759b3d2Safresh1sub add_context_init_callback {
2585759b3d2Safresh1    my $self =  shift;
2595759b3d2Safresh1    my ($code) = @_;
2605759b3d2Safresh1
2615759b3d2Safresh1    my $rtype = reftype($code) || "";
2625759b3d2Safresh1
2635759b3d2Safresh1    confess "Context-init callbacks must be coderefs"
2645759b3d2Safresh1        unless $code && $rtype eq 'CODE';
2655759b3d2Safresh1
2665759b3d2Safresh1    push @{$self->{+CONTEXT_INIT_CALLBACKS}} => $code;
2675759b3d2Safresh1}
2685759b3d2Safresh1
2695759b3d2Safresh1sub add_context_release_callback {
2705759b3d2Safresh1    my $self =  shift;
2715759b3d2Safresh1    my ($code) = @_;
2725759b3d2Safresh1
2735759b3d2Safresh1    my $rtype = reftype($code) || "";
2745759b3d2Safresh1
2755759b3d2Safresh1    confess "Context-release callbacks must be coderefs"
2765759b3d2Safresh1        unless $code && $rtype eq 'CODE';
2775759b3d2Safresh1
2785759b3d2Safresh1    push @{$self->{+CONTEXT_RELEASE_CALLBACKS}} => $code;
2795759b3d2Safresh1}
2805759b3d2Safresh1
2815759b3d2Safresh1sub add_post_load_callback {
2825759b3d2Safresh1    my $self = shift;
2835759b3d2Safresh1    my ($code) = @_;
2845759b3d2Safresh1
2855759b3d2Safresh1    my $rtype = reftype($code) || "";
2865759b3d2Safresh1
2875759b3d2Safresh1    confess "Post-load callbacks must be coderefs"
2885759b3d2Safresh1        unless $code && $rtype eq 'CODE';
2895759b3d2Safresh1
2905759b3d2Safresh1    push @{$self->{+POST_LOAD_CALLBACKS}} => $code;
2915759b3d2Safresh1    $code->() if $self->{+LOADED};
2925759b3d2Safresh1}
2935759b3d2Safresh1
2945759b3d2Safresh1sub add_pre_subtest_callback {
2955759b3d2Safresh1    my $self =  shift;
2965759b3d2Safresh1    my ($code) = @_;
2975759b3d2Safresh1
2985759b3d2Safresh1    my $rtype = reftype($code) || "";
2995759b3d2Safresh1
3005759b3d2Safresh1    confess "Pre-subtest callbacks must be coderefs"
3015759b3d2Safresh1        unless $code && $rtype eq 'CODE';
3025759b3d2Safresh1
3035759b3d2Safresh1    push @{$self->{+PRE_SUBTEST_CALLBACKS}} => $code;
3045759b3d2Safresh1}
3055759b3d2Safresh1
3065759b3d2Safresh1sub load {
3075759b3d2Safresh1    my $self = shift;
3085759b3d2Safresh1    unless ($self->{+LOADED}) {
3095759b3d2Safresh1        confess "Attempt to initialize Test2::API during preload"
3105759b3d2Safresh1            if $self->{+PRELOAD};
3115759b3d2Safresh1
3125759b3d2Safresh1        $self->{+_PID} = $$        unless defined $self->{+_PID};
3135759b3d2Safresh1        $self->{+_TID} = get_tid() unless defined $self->{+_TID};
3145759b3d2Safresh1
3155759b3d2Safresh1        # This is for https://github.com/Test-More/test-more/issues/16
3165759b3d2Safresh1        # and https://rt.perl.org/Public/Bug/Display.html?id=127774
3175759b3d2Safresh1        # END blocks run in reverse order. This insures the END block is loaded
3185759b3d2Safresh1        # as late as possible. It will not solve all cases, but it helps.
3195759b3d2Safresh1        eval "END { Test2::API::test2_set_is_end() }; 1" or die $@;
3205759b3d2Safresh1
3215759b3d2Safresh1        $self->{+LOADED} = 1;
3225759b3d2Safresh1        $_->() for @{$self->{+POST_LOAD_CALLBACKS}};
3235759b3d2Safresh1    }
3245759b3d2Safresh1    return $self->{+LOADED};
3255759b3d2Safresh1}
3265759b3d2Safresh1
3275759b3d2Safresh1sub add_exit_callback {
3285759b3d2Safresh1    my $self = shift;
3295759b3d2Safresh1    my ($code) = @_;
3305759b3d2Safresh1    my $rtype = reftype($code) || "";
3315759b3d2Safresh1
3325759b3d2Safresh1    confess "End callbacks must be coderefs"
3335759b3d2Safresh1        unless $code && $rtype eq 'CODE';
3345759b3d2Safresh1
3355759b3d2Safresh1    push @{$self->{+EXIT_CALLBACKS}} => $code;
3365759b3d2Safresh1}
3375759b3d2Safresh1
3385759b3d2Safresh1sub ipc_disable {
3395759b3d2Safresh1    my $self = shift;
3405759b3d2Safresh1
3415759b3d2Safresh1    confess "Attempt to disable IPC after it has been initialized"
3425759b3d2Safresh1        if $self->{+IPC};
3435759b3d2Safresh1
3445759b3d2Safresh1    $self->{+IPC_DISABLED} = 1;
3455759b3d2Safresh1}
3465759b3d2Safresh1
3475759b3d2Safresh1sub add_ipc_driver {
3485759b3d2Safresh1    my $self = shift;
3495759b3d2Safresh1    my ($driver) = @_;
3505759b3d2Safresh1    unshift @{$self->{+IPC_DRIVERS}} => $driver;
3515759b3d2Safresh1
3525759b3d2Safresh1    return unless $self->{+FINALIZED};
3535759b3d2Safresh1
3545759b3d2Safresh1    # Why is the @CARP_NOT entry not enough?
3555759b3d2Safresh1    local %Carp::Internal = %Carp::Internal;
3565759b3d2Safresh1    $Carp::Internal{'Test2::IPC::Driver'} = 1;
3575759b3d2Safresh1
3585759b3d2Safresh1    carp "IPC driver $driver loaded too late to be used as the global ipc driver";
3595759b3d2Safresh1}
3605759b3d2Safresh1
3615759b3d2Safresh1sub enable_ipc_polling {
3625759b3d2Safresh1    my $self = shift;
3635759b3d2Safresh1
3645759b3d2Safresh1    $self->{+_PID} = $$        unless defined $self->{+_PID};
3655759b3d2Safresh1    $self->{+_TID} = get_tid() unless defined $self->{+_TID};
3665759b3d2Safresh1
3675759b3d2Safresh1    $self->add_context_init_callback(
3685759b3d2Safresh1        # This is called every time a context is created, it needs to be fast.
3695759b3d2Safresh1        # $_[0] is a context object
3705759b3d2Safresh1        sub {
3715759b3d2Safresh1            return unless $self->{+IPC_POLLING};
372f3efcd01Safresh1            return unless $self->{+IPC};
373f3efcd01Safresh1            return unless $self->{+IPC}->pending();
374f3efcd01Safresh1            return $_[0]->{hub}->cull;
3755759b3d2Safresh1        }
3765759b3d2Safresh1    ) unless defined $self->ipc_polling;
3775759b3d2Safresh1
3785759b3d2Safresh1    $self->set_ipc_polling(1);
3795759b3d2Safresh1}
3805759b3d2Safresh1
3815759b3d2Safresh1sub get_ipc_pending {
3825759b3d2Safresh1    my $self = shift;
383f3efcd01Safresh1    return -1 unless $self->{+IPC};
384f3efcd01Safresh1    $self->{+IPC}->pending();
385f3efcd01Safresh1}
386f3efcd01Safresh1
387f3efcd01Safresh1sub _check_pid {
388f3efcd01Safresh1    my $self = shift;
389f3efcd01Safresh1    my ($pid) = @_;
390f3efcd01Safresh1    return kill(0, $pid);
3915759b3d2Safresh1}
3925759b3d2Safresh1
3935759b3d2Safresh1sub set_ipc_pending {
3945759b3d2Safresh1    my $self = shift;
395f3efcd01Safresh1    return unless $self->{+IPC};
3965759b3d2Safresh1    my ($val) = @_;
3975759b3d2Safresh1
3985759b3d2Safresh1    confess "value is required for set_ipc_pending"
3995759b3d2Safresh1        unless $val;
4005759b3d2Safresh1
401f3efcd01Safresh1    $self->{+IPC}->set_pending($val);
4025759b3d2Safresh1}
4035759b3d2Safresh1
4045759b3d2Safresh1sub disable_ipc_polling {
4055759b3d2Safresh1    my $self = shift;
4065759b3d2Safresh1    return unless defined $self->{+IPC_POLLING};
4075759b3d2Safresh1    $self->{+IPC_POLLING} = 0;
4085759b3d2Safresh1}
4095759b3d2Safresh1
4105759b3d2Safresh1sub _ipc_wait {
4115759b3d2Safresh1    my ($timeout) = @_;
4125759b3d2Safresh1    my $fail = 0;
4135759b3d2Safresh1
4145759b3d2Safresh1    $timeout = DEFAULT_IPC_TIMEOUT() unless defined $timeout;
4155759b3d2Safresh1
4165759b3d2Safresh1    my $ok = eval {
4175759b3d2Safresh1        if (CAN_FORK) {
4185759b3d2Safresh1            local $SIG{ALRM} = sub { die "Timeout waiting on child processes" };
4195759b3d2Safresh1            alarm $timeout;
4205759b3d2Safresh1
4215759b3d2Safresh1            while (1) {
4225759b3d2Safresh1                my $pid = CORE::wait();
4235759b3d2Safresh1                my $err = $?;
4245759b3d2Safresh1                last if $pid == -1;
4255759b3d2Safresh1                next unless $err;
4265759b3d2Safresh1                $fail++;
4275759b3d2Safresh1
4285759b3d2Safresh1                my $sig = $err & 127;
4295759b3d2Safresh1                my $exit = $err >> 8;
4305759b3d2Safresh1                warn "Process $pid did not exit cleanly (wstat: $err, exit: $exit, sig: $sig)\n";
4315759b3d2Safresh1            }
4325759b3d2Safresh1
4335759b3d2Safresh1            alarm 0;
4345759b3d2Safresh1        }
4355759b3d2Safresh1
4365759b3d2Safresh1        if (USE_THREADS) {
4375759b3d2Safresh1            my $start = time;
4385759b3d2Safresh1
4395759b3d2Safresh1            while (1) {
4405759b3d2Safresh1                last unless threads->list();
4415759b3d2Safresh1                die "Timeout waiting on child thread" if time - $start >= $timeout;
4425759b3d2Safresh1                sleep 1;
4435759b3d2Safresh1                for my $t (threads->list) {
4445759b3d2Safresh1                    # threads older than 1.34 do not have this :-(
4455759b3d2Safresh1                    next if $t->can('is_joinable') && !$t->is_joinable;
4465759b3d2Safresh1                    $t->join;
4475759b3d2Safresh1                    # In older threads we cannot check if a thread had an error unless
4485759b3d2Safresh1                    # we control it and its return.
4495759b3d2Safresh1                    my $err = $t->can('error') ? $t->error : undef;
4505759b3d2Safresh1                    next unless $err;
4515759b3d2Safresh1                    my $tid = $t->tid();
4525759b3d2Safresh1                    $fail++;
4535759b3d2Safresh1                    chomp($err);
4545759b3d2Safresh1                    warn "Thread $tid did not end cleanly: $err\n";
4555759b3d2Safresh1                }
4565759b3d2Safresh1            }
4575759b3d2Safresh1        }
4585759b3d2Safresh1
4595759b3d2Safresh1        1;
4605759b3d2Safresh1    };
4615759b3d2Safresh1    my $error = $@;
4625759b3d2Safresh1
4635759b3d2Safresh1    return 0 if $ok && !$fail;
4645759b3d2Safresh1    warn $error unless $ok;
4655759b3d2Safresh1    return 255;
4665759b3d2Safresh1}
4675759b3d2Safresh1
4685759b3d2Safresh1sub set_exit {
4695759b3d2Safresh1    my $self = shift;
4705759b3d2Safresh1
4715759b3d2Safresh1    return if $self->{+PRELOAD};
4725759b3d2Safresh1
4735759b3d2Safresh1    my $exit     = $?;
4745759b3d2Safresh1    my $new_exit = $exit;
4755759b3d2Safresh1
4765759b3d2Safresh1    if ($INC{'Test/Builder.pm'} && $Test::Builder::VERSION ne $Test2::API::VERSION) {
4775759b3d2Safresh1        print STDERR <<"        EOT";
4785759b3d2Safresh1
4795759b3d2Safresh1********************************************************************************
4805759b3d2Safresh1*                                                                              *
4815759b3d2Safresh1*            Test::Builder -- Test2::API version mismatch detected             *
4825759b3d2Safresh1*                                                                              *
4835759b3d2Safresh1********************************************************************************
4845759b3d2Safresh1   Test2::API Version: $Test2::API::VERSION
4855759b3d2Safresh1Test::Builder Version: $Test::Builder::VERSION
4865759b3d2Safresh1
4875759b3d2Safresh1This is not a supported configuration, you will have problems.
4885759b3d2Safresh1
4895759b3d2Safresh1        EOT
4905759b3d2Safresh1    }
4915759b3d2Safresh1
4925759b3d2Safresh1    for my $ctx (values %{$self->{+CONTEXTS}}) {
4935759b3d2Safresh1        next unless $ctx;
4945759b3d2Safresh1
4955759b3d2Safresh1        next if $ctx->_aborted && ${$ctx->_aborted};
4965759b3d2Safresh1
4975759b3d2Safresh1        # Only worry about contexts in this PID
4985759b3d2Safresh1        my $trace = $ctx->trace || next;
4995759b3d2Safresh1        next unless $trace->pid && $trace->pid == $$;
5005759b3d2Safresh1
5015759b3d2Safresh1        # Do not worry about contexts that have no hub
5025759b3d2Safresh1        my $hub = $ctx->hub  || next;
5035759b3d2Safresh1
5045759b3d2Safresh1        # Do not worry if the state came to a sudden end.
5055759b3d2Safresh1        next if $hub->bailed_out;
5065759b3d2Safresh1        next if defined $hub->skip_reason;
5075759b3d2Safresh1
5085759b3d2Safresh1        # now we worry
5095759b3d2Safresh1        $trace->alert("context object was never released! This means a testing tool is behaving very badly");
5105759b3d2Safresh1
5115759b3d2Safresh1        $exit     = 255;
5125759b3d2Safresh1        $new_exit = 255;
5135759b3d2Safresh1    }
5145759b3d2Safresh1
5155759b3d2Safresh1    if (!defined($self->{+_PID}) or !defined($self->{+_TID}) or $self->{+_PID} != $$ or $self->{+_TID} != get_tid()) {
5165759b3d2Safresh1        $? = $exit;
5175759b3d2Safresh1        return;
5185759b3d2Safresh1    }
5195759b3d2Safresh1
5205759b3d2Safresh1    my @hubs = $self->{+STACK} ? $self->{+STACK}->all : ();
5215759b3d2Safresh1
5225759b3d2Safresh1    if (@hubs and $self->{+IPC} and !$self->{+NO_WAIT}) {
5235759b3d2Safresh1        local $?;
5245759b3d2Safresh1        my %seen;
5255759b3d2Safresh1        for my $hub (reverse @hubs) {
5265759b3d2Safresh1            my $ipc = $hub->ipc or next;
5275759b3d2Safresh1            next if $seen{$ipc}++;
5285759b3d2Safresh1            $ipc->waiting();
5295759b3d2Safresh1        }
5305759b3d2Safresh1
5315759b3d2Safresh1        my $ipc_exit = _ipc_wait($self->{+IPC_TIMEOUT});
5325759b3d2Safresh1        $new_exit ||= $ipc_exit;
5335759b3d2Safresh1    }
5345759b3d2Safresh1
5355759b3d2Safresh1    # None of this is necessary if we never got a root hub
5365759b3d2Safresh1    if(my $root = shift @hubs) {
5375759b3d2Safresh1        my $trace = Test2::EventFacet::Trace->new(
5385759b3d2Safresh1            frame  => [__PACKAGE__, __FILE__, 0, __PACKAGE__ . '::END'],
5395759b3d2Safresh1            detail => __PACKAGE__ . ' END Block finalization',
5405759b3d2Safresh1        );
5415759b3d2Safresh1        my $ctx = Test2::API::Context->new(
5425759b3d2Safresh1            trace => $trace,
5435759b3d2Safresh1            hub   => $root,
5445759b3d2Safresh1        );
5455759b3d2Safresh1
5465759b3d2Safresh1        if (@hubs) {
5475759b3d2Safresh1            $ctx->diag("Test ended with extra hubs on the stack!");
5485759b3d2Safresh1            $new_exit  = 255;
5495759b3d2Safresh1        }
5505759b3d2Safresh1
5515759b3d2Safresh1        unless ($root->no_ending) {
5525759b3d2Safresh1            local $?;
5535759b3d2Safresh1            $root->finalize($trace) unless $root->ended;
5545759b3d2Safresh1            $_->($ctx, $exit, \$new_exit) for @{$self->{+EXIT_CALLBACKS}};
5555759b3d2Safresh1            $new_exit ||= $root->failed;
5565759b3d2Safresh1            $new_exit ||= 255 unless $root->is_passing;
5575759b3d2Safresh1        }
5585759b3d2Safresh1    }
5595759b3d2Safresh1
5605759b3d2Safresh1    $new_exit = 255 if $new_exit > 255;
5615759b3d2Safresh1
5625759b3d2Safresh1    if ($new_exit && eval { require Test2::API::Breakage; 1 }) {
5635759b3d2Safresh1        my @warn = Test2::API::Breakage->report();
5645759b3d2Safresh1
5655759b3d2Safresh1        if (@warn) {
5665759b3d2Safresh1            print STDERR "\nYou have loaded versions of test modules known to have problems with Test2.\nThis could explain some test failures.\n";
5675759b3d2Safresh1            print STDERR "$_\n" for @warn;
5685759b3d2Safresh1            print STDERR "\n";
5695759b3d2Safresh1        }
5705759b3d2Safresh1    }
5715759b3d2Safresh1
5725759b3d2Safresh1    $? = $new_exit;
5735759b3d2Safresh1}
5745759b3d2Safresh1
5755759b3d2Safresh11;
5765759b3d2Safresh1
5775759b3d2Safresh1__END__
5785759b3d2Safresh1
5795759b3d2Safresh1=pod
5805759b3d2Safresh1
5815759b3d2Safresh1=encoding UTF-8
5825759b3d2Safresh1
5835759b3d2Safresh1=head1 NAME
5845759b3d2Safresh1
5855759b3d2Safresh1Test2::API::Instance - Object used by Test2::API under the hood
5865759b3d2Safresh1
5875759b3d2Safresh1=head1 DESCRIPTION
5885759b3d2Safresh1
5895759b3d2Safresh1This object encapsulates the global shared state tracked by
5905759b3d2Safresh1L<Test2>. A single global instance of this package is stored (and
5915759b3d2Safresh1obscured) by the L<Test2::API> package.
5925759b3d2Safresh1
5935759b3d2Safresh1There is no reason to directly use this package. This package is documented for
5945759b3d2Safresh1completeness. This package can change, or go away completely at any time.
5955759b3d2Safresh1Directly using, or monkeypatching this package is not supported in any way
5965759b3d2Safresh1shape or form.
5975759b3d2Safresh1
5985759b3d2Safresh1=head1 SYNOPSIS
5995759b3d2Safresh1
6005759b3d2Safresh1    use Test2::API::Instance;
6015759b3d2Safresh1
6025759b3d2Safresh1    my $obj = Test2::API::Instance->new;
6035759b3d2Safresh1
6045759b3d2Safresh1=over 4
6055759b3d2Safresh1
6065759b3d2Safresh1=item $pid = $obj->pid
6075759b3d2Safresh1
6085759b3d2Safresh1PID of this instance.
6095759b3d2Safresh1
6105759b3d2Safresh1=item $obj->tid
6115759b3d2Safresh1
6125759b3d2Safresh1Thread ID of this instance.
6135759b3d2Safresh1
6145759b3d2Safresh1=item $obj->reset()
6155759b3d2Safresh1
6165759b3d2Safresh1Reset the object to defaults.
6175759b3d2Safresh1
6185759b3d2Safresh1=item $obj->load()
6195759b3d2Safresh1
6205759b3d2Safresh1Set the internal state to loaded, and run and stored post-load callbacks.
6215759b3d2Safresh1
6225759b3d2Safresh1=item $bool = $obj->loaded
6235759b3d2Safresh1
6245759b3d2Safresh1Check if the state is set to loaded.
6255759b3d2Safresh1
6265759b3d2Safresh1=item $arrayref = $obj->post_load_callbacks
6275759b3d2Safresh1
6285759b3d2Safresh1Get the post-load callbacks.
6295759b3d2Safresh1
6305759b3d2Safresh1=item $obj->add_post_load_callback(sub { ... })
6315759b3d2Safresh1
6325759b3d2Safresh1Add a post-load callback. If C<load()> has already been called then the callback will
6335759b3d2Safresh1be immediately executed. If C<load()> has not been called then the callback will be
6345759b3d2Safresh1stored and executed later when C<load()> is called.
6355759b3d2Safresh1
6365759b3d2Safresh1=item $hashref = $obj->contexts()
6375759b3d2Safresh1
6385759b3d2Safresh1Get a hashref of all active contexts keyed by hub id.
6395759b3d2Safresh1
6405759b3d2Safresh1=item $arrayref = $obj->context_acquire_callbacks
6415759b3d2Safresh1
6425759b3d2Safresh1Get all context acquire callbacks.
6435759b3d2Safresh1
6445759b3d2Safresh1=item $arrayref = $obj->context_init_callbacks
6455759b3d2Safresh1
6465759b3d2Safresh1Get all context init callbacks.
6475759b3d2Safresh1
6485759b3d2Safresh1=item $arrayref = $obj->context_release_callbacks
6495759b3d2Safresh1
6505759b3d2Safresh1Get all context release callbacks.
6515759b3d2Safresh1
6525759b3d2Safresh1=item $arrayref = $obj->pre_subtest_callbacks
6535759b3d2Safresh1
6545759b3d2Safresh1Get all pre-subtest callbacks.
6555759b3d2Safresh1
6565759b3d2Safresh1=item $obj->add_context_init_callback(sub { ... })
6575759b3d2Safresh1
6585759b3d2Safresh1Add a context init callback. Subs are called every time a context is created. Subs
6595759b3d2Safresh1get the newly created context as their only argument.
6605759b3d2Safresh1
6615759b3d2Safresh1=item $obj->add_context_release_callback(sub { ... })
6625759b3d2Safresh1
6635759b3d2Safresh1Add a context release callback. Subs are called every time a context is released. Subs
6645759b3d2Safresh1get the released context as their only argument. These callbacks should not
6655759b3d2Safresh1call release on the context.
6665759b3d2Safresh1
6675759b3d2Safresh1=item $obj->add_pre_subtest_callback(sub { ... })
6685759b3d2Safresh1
6695759b3d2Safresh1Add a pre-subtest callback. Subs are called every time a subtest is
6705759b3d2Safresh1going to be run. Subs get the subtest name, coderef, and any
6715759b3d2Safresh1arguments.
6725759b3d2Safresh1
6735759b3d2Safresh1=item $obj->set_exit()
6745759b3d2Safresh1
6755759b3d2Safresh1This is intended to be called in an C<END { ... }> block. This will look at
6765759b3d2Safresh1test state and set $?. This will also call any end callbacks, and wait on child
6775759b3d2Safresh1processes/threads.
6785759b3d2Safresh1
6795759b3d2Safresh1=item $obj->set_ipc_pending($val)
6805759b3d2Safresh1
681f3efcd01Safresh1Tell other processes and threads there is a pending event. C<$val> should be a
682f3efcd01Safresh1unique value no other thread/process will generate.
6835759b3d2Safresh1
684f3efcd01Safresh1B<Note:> This will also make the current process see a pending event.
6855759b3d2Safresh1
6865759b3d2Safresh1=item $pending = $obj->get_ipc_pending()
6875759b3d2Safresh1
688f3efcd01Safresh1This returns -1 if it is not possible to know.
6895759b3d2Safresh1
690f3efcd01Safresh1This returns 0 if there are no pending events.
6915759b3d2Safresh1
692f3efcd01Safresh1This returns 1 if there are pending events.
6935759b3d2Safresh1
6945759b3d2Safresh1=item $timeout = $obj->ipc_timeout;
6955759b3d2Safresh1
6965759b3d2Safresh1=item $obj->set_ipc_timeout($timeout);
6975759b3d2Safresh1
6985759b3d2Safresh1How long to wait for child processes and threads before aborting.
6995759b3d2Safresh1
7005759b3d2Safresh1=item $drivers = $obj->ipc_drivers
7015759b3d2Safresh1
7025759b3d2Safresh1Get the list of IPC drivers.
7035759b3d2Safresh1
7045759b3d2Safresh1=item $obj->add_ipc_driver($DRIVER_CLASS)
7055759b3d2Safresh1
7065759b3d2Safresh1Add an IPC driver to the list. The most recently added IPC driver will become
7075759b3d2Safresh1the global one during initialization. If a driver is added after initialization
7085759b3d2Safresh1has occurred a warning will be generated:
7095759b3d2Safresh1
7105759b3d2Safresh1    "IPC driver $driver loaded too late to be used as the global ipc driver"
7115759b3d2Safresh1
7125759b3d2Safresh1=item $bool = $obj->ipc_polling
7135759b3d2Safresh1
7145759b3d2Safresh1Check if polling is enabled.
7155759b3d2Safresh1
7165759b3d2Safresh1=item $obj->enable_ipc_polling
7175759b3d2Safresh1
7185759b3d2Safresh1Turn on polling. This will cull events from other processes and threads every
7195759b3d2Safresh1time a context is created.
7205759b3d2Safresh1
7215759b3d2Safresh1=item $obj->disable_ipc_polling
7225759b3d2Safresh1
7235759b3d2Safresh1Turn off IPC polling.
7245759b3d2Safresh1
7255759b3d2Safresh1=item $bool = $obj->no_wait
7265759b3d2Safresh1
7275759b3d2Safresh1=item $bool = $obj->set_no_wait($bool)
7285759b3d2Safresh1
7295759b3d2Safresh1Get/Set no_wait. This option is used to turn off process/thread waiting at exit.
7305759b3d2Safresh1
7315759b3d2Safresh1=item $arrayref = $obj->exit_callbacks
7325759b3d2Safresh1
7335759b3d2Safresh1Get the exit callbacks.
7345759b3d2Safresh1
7355759b3d2Safresh1=item $obj->add_exit_callback(sub { ... })
7365759b3d2Safresh1
7375759b3d2Safresh1Add an exit callback. This callback will be called by C<set_exit()>.
7385759b3d2Safresh1
7395759b3d2Safresh1=item $bool = $obj->finalized
7405759b3d2Safresh1
7415759b3d2Safresh1Check if the object is finalized. Finalization happens when either C<ipc()>,
7425759b3d2Safresh1C<stack()>, or C<format()> are called on the object. Once finalization happens
7435759b3d2Safresh1these fields are considered unchangeable (not enforced here, enforced by
7445759b3d2Safresh1L<Test2>).
7455759b3d2Safresh1
7465759b3d2Safresh1=item $ipc = $obj->ipc
7475759b3d2Safresh1
7485759b3d2Safresh1Get the one true IPC instance.
7495759b3d2Safresh1
7505759b3d2Safresh1=item $obj->ipc_disable
7515759b3d2Safresh1
7525759b3d2Safresh1Turn IPC off
7535759b3d2Safresh1
7545759b3d2Safresh1=item $bool = $obj->ipc_disabled
7555759b3d2Safresh1
7565759b3d2Safresh1Check if IPC is disabled
7575759b3d2Safresh1
7585759b3d2Safresh1=item $stack = $obj->stack
7595759b3d2Safresh1
7605759b3d2Safresh1Get the one true hub stack.
7615759b3d2Safresh1
7625759b3d2Safresh1=item $formatter = $obj->formatter
7635759b3d2Safresh1
7645759b3d2Safresh1Get the global formatter. By default this is the C<'Test2::Formatter::TAP'>
7655759b3d2Safresh1package. This could be any package that implements the C<write()> method. This
7665759b3d2Safresh1can also be an instantiated object.
7675759b3d2Safresh1
7685759b3d2Safresh1=item $bool = $obj->formatter_set()
7695759b3d2Safresh1
7705759b3d2Safresh1Check if a formatter has been set.
7715759b3d2Safresh1
7725759b3d2Safresh1=item $obj->add_formatter($class)
7735759b3d2Safresh1
7745759b3d2Safresh1=item $obj->add_formatter($obj)
7755759b3d2Safresh1
7765759b3d2Safresh1Add a formatter. The most recently added formatter will become the global one
7775759b3d2Safresh1during initialization. If a formatter is added after initialization has occurred
7785759b3d2Safresh1a warning will be generated:
7795759b3d2Safresh1
7805759b3d2Safresh1    "Formatter $formatter loaded too late to be used as the global formatter"
7815759b3d2Safresh1
7825759b3d2Safresh1=item $obj->set_add_uuid_via(sub { ... })
7835759b3d2Safresh1
7845759b3d2Safresh1=item $sub = $obj->add_uuid_via()
7855759b3d2Safresh1
7865759b3d2Safresh1This allows you to provide a UUID generator. If provided UUIDs will be attached
7875759b3d2Safresh1to all events, hubs, and contexts. This is useful for storing, tracking, and
7885759b3d2Safresh1linking these objects.
7895759b3d2Safresh1
7905759b3d2Safresh1The sub you provide should always return a unique identifier. Most things will
7915759b3d2Safresh1expect a proper UUID string, however nothing in Test2::API enforces this.
7925759b3d2Safresh1
7935759b3d2Safresh1The sub will receive exactly 1 argument, the type of thing being tagged
7945759b3d2Safresh1'context', 'hub', or 'event'. In the future additional things may be tagged, in
7955759b3d2Safresh1which case new strings will be passed in. These are purely informative, you can
7965759b3d2Safresh1(and usually should) ignore them.
7975759b3d2Safresh1
7985759b3d2Safresh1=back
7995759b3d2Safresh1
8005759b3d2Safresh1=head1 SOURCE
8015759b3d2Safresh1
8025759b3d2Safresh1The source code repository for Test2 can be found at
803*5486feefSafresh1L<https://github.com/Test-More/test-more/>.
8045759b3d2Safresh1
8055759b3d2Safresh1=head1 MAINTAINERS
8065759b3d2Safresh1
8075759b3d2Safresh1=over 4
8085759b3d2Safresh1
8095759b3d2Safresh1=item Chad Granum E<lt>exodist@cpan.orgE<gt>
8105759b3d2Safresh1
8115759b3d2Safresh1=back
8125759b3d2Safresh1
8135759b3d2Safresh1=head1 AUTHORS
8145759b3d2Safresh1
8155759b3d2Safresh1=over 4
8165759b3d2Safresh1
8175759b3d2Safresh1=item Chad Granum E<lt>exodist@cpan.orgE<gt>
8185759b3d2Safresh1
8195759b3d2Safresh1=back
8205759b3d2Safresh1
8215759b3d2Safresh1=head1 COPYRIGHT
8225759b3d2Safresh1
823256a93a4Safresh1Copyright 2020 Chad Granum E<lt>exodist@cpan.orgE<gt>.
8245759b3d2Safresh1
8255759b3d2Safresh1This program is free software; you can redistribute it and/or
8265759b3d2Safresh1modify it under the same terms as Perl itself.
8275759b3d2Safresh1
828*5486feefSafresh1See L<https://dev.perl.org/licenses/>
8295759b3d2Safresh1
8305759b3d2Safresh1=cut
831