xref: /openbsd-src/gnu/usr.bin/perl/cpan/Test-Simple/lib/Test2/IPC/Driver/Files.pm (revision 5486feefcc8cb79b19e014ab332cc5dfd05b3b33)
15759b3d2Safresh1package Test2::IPC::Driver::Files;
25759b3d2Safresh1use strict;
35759b3d2Safresh1use warnings;
45759b3d2Safresh1
5*5486feefSafresh1our $VERSION = '1.302199';
65759b3d2Safresh1
75759b3d2Safresh1BEGIN { require Test2::IPC::Driver; our @ISA = qw(Test2::IPC::Driver) }
85759b3d2Safresh1
95759b3d2Safresh1use Test2::Util::HashBase qw{tempdir event_ids read_ids timeouts tid pid globals};
105759b3d2Safresh1
115759b3d2Safresh1use Scalar::Util qw/blessed/;
125759b3d2Safresh1use File::Temp();
135759b3d2Safresh1use Storable();
145759b3d2Safresh1use File::Spec();
155759b3d2Safresh1use POSIX();
165759b3d2Safresh1
175759b3d2Safresh1use Test2::Util qw/try get_tid pkg_to_file IS_WIN32 ipc_separator do_rename do_unlink try_sig_mask/;
185759b3d2Safresh1use Test2::API qw/test2_ipc_set_pending/;
195759b3d2Safresh1
205759b3d2Safresh1sub is_viable { 1 }
215759b3d2Safresh1
225759b3d2Safresh1sub init {
235759b3d2Safresh1    my $self = shift;
245759b3d2Safresh1
255759b3d2Safresh1    my $tmpdir = File::Temp::tempdir(
265759b3d2Safresh1        $ENV{T2_TEMPDIR_TEMPLATE} || "test2" . ipc_separator . $$ . ipc_separator . "XXXXXX",
275759b3d2Safresh1        CLEANUP => 0,
285759b3d2Safresh1        TMPDIR => 1,
295759b3d2Safresh1    );
305759b3d2Safresh1
315759b3d2Safresh1    $self->abort_trace("Could not get a temp dir") unless $tmpdir;
325759b3d2Safresh1
335759b3d2Safresh1    $self->{+TEMPDIR} = File::Spec->canonpath($tmpdir);
345759b3d2Safresh1
355759b3d2Safresh1    print STDERR "\nIPC Temp Dir: $tmpdir\n\n"
365759b3d2Safresh1        if $ENV{T2_KEEP_TEMPDIR};
375759b3d2Safresh1
385759b3d2Safresh1    $self->{+EVENT_IDS} = {};
395759b3d2Safresh1    $self->{+READ_IDS} = {};
405759b3d2Safresh1    $self->{+TIMEOUTS} = {};
415759b3d2Safresh1
425759b3d2Safresh1    $self->{+TID} = get_tid();
435759b3d2Safresh1    $self->{+PID} = $$;
445759b3d2Safresh1
455759b3d2Safresh1    $self->{+GLOBALS} = {};
465759b3d2Safresh1
475759b3d2Safresh1    return $self;
485759b3d2Safresh1}
495759b3d2Safresh1
505759b3d2Safresh1sub hub_file {
515759b3d2Safresh1    my $self = shift;
525759b3d2Safresh1    my ($hid) = @_;
535759b3d2Safresh1    my $tdir = $self->{+TEMPDIR};
545759b3d2Safresh1    return File::Spec->catfile($tdir, "HUB" . ipc_separator . $hid);
555759b3d2Safresh1}
565759b3d2Safresh1
575759b3d2Safresh1sub event_file {
585759b3d2Safresh1    my $self = shift;
595759b3d2Safresh1    my ($hid, $e) = @_;
605759b3d2Safresh1
615759b3d2Safresh1    my $tempdir = $self->{+TEMPDIR};
625759b3d2Safresh1    my $type = blessed($e) or $self->abort("'$e' is not a blessed object!");
635759b3d2Safresh1
645759b3d2Safresh1    $self->abort("'$e' is not an event object!")
655759b3d2Safresh1        unless $type->isa('Test2::Event');
665759b3d2Safresh1
675759b3d2Safresh1    my $tid = get_tid();
685759b3d2Safresh1    my $eid = $self->{+EVENT_IDS}->{$hid}->{$$}->{$tid} += 1;
695759b3d2Safresh1
705759b3d2Safresh1    my @type = split '::', $type;
715759b3d2Safresh1    my $name = join(ipc_separator, $hid, $$, $tid, $eid, @type);
725759b3d2Safresh1
735759b3d2Safresh1    return File::Spec->catfile($tempdir, $name);
745759b3d2Safresh1}
755759b3d2Safresh1
765759b3d2Safresh1sub add_hub {
775759b3d2Safresh1    my $self = shift;
785759b3d2Safresh1    my ($hid) = @_;
795759b3d2Safresh1
805759b3d2Safresh1    my $hfile = $self->hub_file($hid);
815759b3d2Safresh1
825759b3d2Safresh1    $self->abort_trace("File for hub '$hid' already exists")
835759b3d2Safresh1        if -e $hfile;
845759b3d2Safresh1
855759b3d2Safresh1    open(my $fh, '>', $hfile) or $self->abort_trace("Could not create hub file '$hid': $!");
865759b3d2Safresh1    print $fh "$$\n" . get_tid() . "\n";
875759b3d2Safresh1    close($fh);
885759b3d2Safresh1}
895759b3d2Safresh1
905759b3d2Safresh1sub drop_hub {
915759b3d2Safresh1    my $self = shift;
925759b3d2Safresh1    my ($hid) = @_;
935759b3d2Safresh1
945759b3d2Safresh1    my $tdir = $self->{+TEMPDIR};
955759b3d2Safresh1    my $hfile = $self->hub_file($hid);
965759b3d2Safresh1
975759b3d2Safresh1    $self->abort_trace("File for hub '$hid' does not exist")
985759b3d2Safresh1        unless -e $hfile;
995759b3d2Safresh1
1005759b3d2Safresh1    open(my $fh, '<', $hfile) or $self->abort_trace("Could not open hub file '$hid': $!");
1015759b3d2Safresh1    my ($pid, $tid) = <$fh>;
1025759b3d2Safresh1    close($fh);
1035759b3d2Safresh1
1045759b3d2Safresh1    $self->abort_trace("A hub file can only be closed by the process that started it\nExpected $pid, got $$")
1055759b3d2Safresh1        unless $pid == $$;
1065759b3d2Safresh1
1075759b3d2Safresh1    $self->abort_trace("A hub file can only be closed by the thread that started it\nExpected $tid, got " . get_tid())
1085759b3d2Safresh1        unless get_tid() == $tid;
1095759b3d2Safresh1
1105759b3d2Safresh1    if ($ENV{T2_KEEP_TEMPDIR}) {
1115759b3d2Safresh1        my ($ok, $err) = do_rename($hfile, File::Spec->canonpath("$hfile.complete"));
1125759b3d2Safresh1        $self->abort_trace("Could not rename file '$hfile' -> '$hfile.complete': $err") unless $ok
1135759b3d2Safresh1    }
1145759b3d2Safresh1    else {
1155759b3d2Safresh1        my ($ok, $err) = do_unlink($hfile);
1165759b3d2Safresh1        $self->abort_trace("Could not remove file for hub '$hid': $err") unless $ok
1175759b3d2Safresh1    }
1185759b3d2Safresh1
1195759b3d2Safresh1    opendir(my $dh, $tdir) or $self->abort_trace("Could not open temp dir!");
120de8cc8edSafresh1
121de8cc8edSafresh1    my %bad;
1225759b3d2Safresh1    for my $file (readdir($dh)) {
1235759b3d2Safresh1        next if $file =~ m{\.complete$};
1245759b3d2Safresh1        next unless $file =~ m{^$hid};
125de8cc8edSafresh1
126de8cc8edSafresh1        eval { $bad{$file} = $self->read_event_file(File::Spec->catfile($tdir, $file)); 1 } or $bad{$file} = $@ || "Unknown error reading file";
1275759b3d2Safresh1    }
1285759b3d2Safresh1    closedir($dh);
129de8cc8edSafresh1
130de8cc8edSafresh1    return unless keys %bad;
131de8cc8edSafresh1
132de8cc8edSafresh1    my $data;
133de8cc8edSafresh1    my $ok = eval {
134de8cc8edSafresh1        require JSON::PP;
135de8cc8edSafresh1        local *UNIVERSAL::TO_JSON = sub { +{ %{$_[0]} } };
136de8cc8edSafresh1        my $json = JSON::PP->new->ascii->pretty->canonical->allow_unknown->allow_blessed->convert_blessed;
137de8cc8edSafresh1        $data = $json->encode(\%bad);
138de8cc8edSafresh1        1;
139de8cc8edSafresh1    };
140de8cc8edSafresh1    $ok ||= eval {
141de8cc8edSafresh1        require Data::Dumper;
142de8cc8edSafresh1        local $Data::Dumper::Sortkeys = 1;
143de8cc8edSafresh1        $data = Data::Dumper::Dumper(\%bad);
144de8cc8edSafresh1        1;
145de8cc8edSafresh1    };
146de8cc8edSafresh1
147de8cc8edSafresh1    $data = "Could not dump data... sorry." unless defined $data;
148de8cc8edSafresh1
149de8cc8edSafresh1    $self->abort_trace("Not all files from hub '$hid' have been collected!\nHere is the leftover data:\n========================\n$data\n===================\n");
1505759b3d2Safresh1}
1515759b3d2Safresh1
1525759b3d2Safresh1sub send {
1535759b3d2Safresh1    my $self = shift;
1545759b3d2Safresh1    my ($hid, $e, $global) = @_;
1555759b3d2Safresh1
1565759b3d2Safresh1    my $tempdir = $self->{+TEMPDIR};
1575759b3d2Safresh1    my $hfile = $self->hub_file($hid);
1585759b3d2Safresh1    my $dest = $global ? 'GLOBAL' : $hid;
1595759b3d2Safresh1
1605759b3d2Safresh1    $self->abort(<<"    EOT") unless $global || -f $hfile;
1615759b3d2Safresh1hub '$hid' is not available, failed to send event!
1625759b3d2Safresh1
1635759b3d2Safresh1There was an attempt to send an event to a hub in a parent process or thread,
1645759b3d2Safresh1but that hub appears to be gone. This can happen if you fork, or start a new
1655759b3d2Safresh1thread from inside subtest, and the parent finishes the subtest before the
1665759b3d2Safresh1child returns.
1675759b3d2Safresh1
1685759b3d2Safresh1This can also happen if the parent process is done testing before the child
1695759b3d2Safresh1finishes. Test2 normally waits automatically in the root process, but will not
1705759b3d2Safresh1do so if Test::Builder is loaded for legacy reasons.
1715759b3d2Safresh1    EOT
1725759b3d2Safresh1
1735759b3d2Safresh1    my $file = $self->event_file($dest, $e);
1745759b3d2Safresh1    my $ready = File::Spec->canonpath("$file.ready");
1755759b3d2Safresh1
1765759b3d2Safresh1    if ($global) {
1775759b3d2Safresh1        my $name = $ready;
1785759b3d2Safresh1        $name =~ s{^.*(GLOBAL)}{GLOBAL};
1795759b3d2Safresh1        $self->{+GLOBALS}->{$hid}->{$name}++;
1805759b3d2Safresh1    }
1815759b3d2Safresh1
1825759b3d2Safresh1    # Write and rename the file.
1835759b3d2Safresh1    my ($ren_ok, $ren_err);
184256a93a4Safresh1    my ($ok, $err) = try_sig_mask(sub {
1855759b3d2Safresh1        Storable::store($e, $file);
1865759b3d2Safresh1        ($ren_ok, $ren_err) = do_rename("$file", $ready);
187256a93a4Safresh1    });
1885759b3d2Safresh1
1895759b3d2Safresh1    if ($ok) {
1905759b3d2Safresh1        $self->abort("Could not rename file '$file' -> '$ready': $ren_err") unless $ren_ok;
191f3efcd01Safresh1        test2_ipc_set_pending($file);
1925759b3d2Safresh1    }
1935759b3d2Safresh1    else {
1945759b3d2Safresh1        my $src_file = __FILE__;
1955759b3d2Safresh1        $err =~ s{ at \Q$src_file\E.*$}{};
1965759b3d2Safresh1        chomp($err);
1975759b3d2Safresh1        my $tid = get_tid();
1985759b3d2Safresh1        my $trace = $e->trace->debug;
1995759b3d2Safresh1        my $type = blessed($e);
2005759b3d2Safresh1
2015759b3d2Safresh1        $self->abort(<<"        EOT");
2025759b3d2Safresh1
2035759b3d2Safresh1*******************************************************************************
2045759b3d2Safresh1There was an error writing an event:
2055759b3d2Safresh1Destination: $dest
2065759b3d2Safresh1Origin PID:  $$
2075759b3d2Safresh1Origin TID:  $tid
2085759b3d2Safresh1Event Type:  $type
2095759b3d2Safresh1Event Trace: $trace
2105759b3d2Safresh1File Name:   $file
2115759b3d2Safresh1Ready Name:  $ready
2125759b3d2Safresh1Error: $err
2135759b3d2Safresh1*******************************************************************************
2145759b3d2Safresh1
2155759b3d2Safresh1        EOT
2165759b3d2Safresh1    }
2175759b3d2Safresh1
2185759b3d2Safresh1    return 1;
2195759b3d2Safresh1}
2205759b3d2Safresh1
2215759b3d2Safresh1sub driver_abort {
2225759b3d2Safresh1    my $self = shift;
2235759b3d2Safresh1    my ($msg) = @_;
2245759b3d2Safresh1
2255759b3d2Safresh1    local ($@, $!, $?, $^E);
2265759b3d2Safresh1    eval {
2275759b3d2Safresh1        my $abort = File::Spec->catfile($self->{+TEMPDIR}, "ABORT");
2285759b3d2Safresh1        open(my $fh, '>>', $abort) or die "Could not open abort file: $!";
2295759b3d2Safresh1        print $fh $msg, "\n";
2305759b3d2Safresh1        close($fh) or die "Could not close abort file: $!";
2315759b3d2Safresh1        1;
2325759b3d2Safresh1    } or warn $@;
2335759b3d2Safresh1}
2345759b3d2Safresh1
2355759b3d2Safresh1sub cull {
2365759b3d2Safresh1    my $self = shift;
2375759b3d2Safresh1    my ($hid) = @_;
2385759b3d2Safresh1
2395759b3d2Safresh1    my $tempdir = $self->{+TEMPDIR};
2405759b3d2Safresh1
2415759b3d2Safresh1    opendir(my $dh, $tempdir) or $self->abort("could not open IPC temp dir ($tempdir)!");
2425759b3d2Safresh1
2435759b3d2Safresh1    my $read = $self->{+READ_IDS};
2445759b3d2Safresh1    my $timeouts = $self->{+TIMEOUTS};
2455759b3d2Safresh1
2465759b3d2Safresh1    my @out;
2475759b3d2Safresh1    for my $info (sort cmp_events map { $self->should_read_event($hid, $_) } readdir($dh)) {
2485759b3d2Safresh1        unless ($info->{global}) {
2495759b3d2Safresh1            my $next = $self->{+READ_IDS}->{$info->{hid}}->{$info->{pid}}->{$info->{tid}} ||= 1;
2505759b3d2Safresh1
2515759b3d2Safresh1            $timeouts->{$info->{file}} ||= time;
2525759b3d2Safresh1
2535759b3d2Safresh1            if ($next != $info->{eid}) {
2545759b3d2Safresh1                # Wait up to N seconds for missing events
2555759b3d2Safresh1                next unless 5 < time - $timeouts->{$info->{file}};
2565759b3d2Safresh1                $self->abort("Missing event HID: $info->{hid}, PID: $info->{pid}, TID: $info->{tid}, EID: $info->{eid}.");
2575759b3d2Safresh1            }
2585759b3d2Safresh1
2595759b3d2Safresh1            $self->{+READ_IDS}->{$info->{hid}}->{$info->{pid}}->{$info->{tid}} = $info->{eid} + 1;
2605759b3d2Safresh1        }
2615759b3d2Safresh1
2625759b3d2Safresh1        my $full = $info->{full_path};
2635759b3d2Safresh1        my $obj = $self->read_event_file($full);
2645759b3d2Safresh1        push @out => $obj;
2655759b3d2Safresh1
2665759b3d2Safresh1        # Do not remove global events
2675759b3d2Safresh1        next if $info->{global};
2685759b3d2Safresh1
2695759b3d2Safresh1        if ($ENV{T2_KEEP_TEMPDIR}) {
2705759b3d2Safresh1            my $complete = File::Spec->canonpath("$full.complete");
2715759b3d2Safresh1            my ($ok, $err) = do_rename($full, $complete);
2725759b3d2Safresh1            $self->abort("Could not rename IPC file '$full', '$complete': $err") unless $ok;
2735759b3d2Safresh1        }
2745759b3d2Safresh1        else {
2755759b3d2Safresh1            my ($ok, $err) = do_unlink("$full");
2765759b3d2Safresh1            $self->abort("Could not unlink IPC file '$full': $err") unless $ok;
2775759b3d2Safresh1        }
2785759b3d2Safresh1    }
2795759b3d2Safresh1
2805759b3d2Safresh1    closedir($dh);
2815759b3d2Safresh1    return @out;
2825759b3d2Safresh1}
2835759b3d2Safresh1
2845759b3d2Safresh1sub parse_event_filename {
2855759b3d2Safresh1    my $self = shift;
2865759b3d2Safresh1    my ($file) = @_;
2875759b3d2Safresh1
2885759b3d2Safresh1    # The || is to force 0 in false
2895759b3d2Safresh1    my $complete = substr($file, -9, 9) eq '.complete' || 0 and substr($file, -9, 9, "");
2905759b3d2Safresh1    my $ready    = substr($file, -6, 6) eq '.ready'    || 0 and substr($file, -6, 6, "");
2915759b3d2Safresh1
2925759b3d2Safresh1    my @parts = split ipc_separator, $file;
293f3efcd01Safresh1    my ($global, $hid) = $parts[0] eq 'GLOBAL' ? (1, shift @parts) : (0, join ipc_separator, splice(@parts, 0, 4));
2945759b3d2Safresh1    my ($pid, $tid, $eid) = splice(@parts, 0, 3);
2955759b3d2Safresh1    my $type = join '::' => @parts;
2965759b3d2Safresh1
2975759b3d2Safresh1    return {
2985759b3d2Safresh1        file     => $file,
299256a93a4Safresh1        ready    => !!$ready,
300256a93a4Safresh1        complete => !!$complete,
3015759b3d2Safresh1        global   => $global,
3025759b3d2Safresh1        type     => $type,
3035759b3d2Safresh1        hid      => $hid,
3045759b3d2Safresh1        pid      => $pid,
3055759b3d2Safresh1        tid      => $tid,
3065759b3d2Safresh1        eid      => $eid,
3075759b3d2Safresh1    };
3085759b3d2Safresh1}
3095759b3d2Safresh1
3105759b3d2Safresh1sub should_read_event {
3115759b3d2Safresh1    my $self = shift;
3125759b3d2Safresh1    my ($hid, $file) = @_;
3135759b3d2Safresh1
3145759b3d2Safresh1    return if substr($file, 0, 1) eq '.';
3155759b3d2Safresh1    return if substr($file, 0, 3) eq 'HUB';
3165759b3d2Safresh1    CORE::exit(255) if $file eq 'ABORT';
3175759b3d2Safresh1
3185759b3d2Safresh1    my $parsed = $self->parse_event_filename($file);
3195759b3d2Safresh1
3205759b3d2Safresh1    return if $parsed->{complete};
3215759b3d2Safresh1    return unless $parsed->{ready};
3225759b3d2Safresh1    return unless $parsed->{global} || $parsed->{hid} eq $hid;
3235759b3d2Safresh1
3245759b3d2Safresh1    return if $parsed->{global} && $self->{+GLOBALS}->{$hid}->{$file}++;
3255759b3d2Safresh1
3265759b3d2Safresh1    # Untaint the path.
3275759b3d2Safresh1    my $full = File::Spec->catfile($self->{+TEMPDIR}, $file);
3285759b3d2Safresh1    ($full) = ($full =~ m/^(.*)$/gs) if ${^TAINT};
3295759b3d2Safresh1
3305759b3d2Safresh1    $parsed->{full_path} = $full;
3315759b3d2Safresh1
3325759b3d2Safresh1    return $parsed;
3335759b3d2Safresh1}
3345759b3d2Safresh1
3355759b3d2Safresh1sub cmp_events {
3365759b3d2Safresh1    # Globals first
3375759b3d2Safresh1    return -1 if $a->{global} && !$b->{global};
3385759b3d2Safresh1    return  1 if $b->{global} && !$a->{global};
3395759b3d2Safresh1
3405759b3d2Safresh1    return $a->{pid} <=> $b->{pid}
3415759b3d2Safresh1        || $a->{tid} <=> $b->{tid}
3425759b3d2Safresh1        || $a->{eid} <=> $b->{eid};
3435759b3d2Safresh1}
3445759b3d2Safresh1
3455759b3d2Safresh1sub read_event_file {
3465759b3d2Safresh1    my $self = shift;
3475759b3d2Safresh1    my ($file) = @_;
3485759b3d2Safresh1
3495759b3d2Safresh1    my $obj = Storable::retrieve($file);
3505759b3d2Safresh1    $self->abort("Got an unblessed object: '$obj'")
3515759b3d2Safresh1        unless blessed($obj);
3525759b3d2Safresh1
3535759b3d2Safresh1    unless ($obj->isa('Test2::Event')) {
3545759b3d2Safresh1        my $pkg  = blessed($obj);
3555759b3d2Safresh1        my $mod_file = pkg_to_file($pkg);
3565759b3d2Safresh1        my ($ok, $err) = try { require $mod_file };
3575759b3d2Safresh1
3585759b3d2Safresh1        $self->abort("Event has unknown type ($pkg), tried to load '$mod_file' but failed: $err")
3595759b3d2Safresh1            unless $ok;
3605759b3d2Safresh1
3615759b3d2Safresh1        $self->abort("'$obj' is not a 'Test2::Event' object")
3625759b3d2Safresh1            unless $obj->isa('Test2::Event');
3635759b3d2Safresh1    }
3645759b3d2Safresh1
3655759b3d2Safresh1    return $obj;
3665759b3d2Safresh1}
3675759b3d2Safresh1
3685759b3d2Safresh1sub waiting {
3695759b3d2Safresh1    my $self = shift;
3705759b3d2Safresh1    require Test2::Event::Waiting;
3715759b3d2Safresh1    $self->send(
3725759b3d2Safresh1        GLOBAL => Test2::Event::Waiting->new(
3735759b3d2Safresh1            trace => Test2::EventFacet::Trace->new(frame => [caller()]),
3745759b3d2Safresh1        ),
3755759b3d2Safresh1        'GLOBAL'
3765759b3d2Safresh1    );
3775759b3d2Safresh1    return;
3785759b3d2Safresh1}
3795759b3d2Safresh1
3805759b3d2Safresh1sub DESTROY {
3815759b3d2Safresh1    my $self = shift;
3825759b3d2Safresh1
3835759b3d2Safresh1    return unless defined $self->pid;
3845759b3d2Safresh1    return unless defined $self->tid;
3855759b3d2Safresh1
3865759b3d2Safresh1    return unless $$        == $self->pid;
3875759b3d2Safresh1    return unless get_tid() == $self->tid;
3885759b3d2Safresh1
3895759b3d2Safresh1    my $tempdir = $self->{+TEMPDIR};
3905759b3d2Safresh1
3915759b3d2Safresh1    my $aborted = 0;
3925759b3d2Safresh1    my $abort_file = File::Spec->catfile($self->{+TEMPDIR}, "ABORT");
3935759b3d2Safresh1    if (-e $abort_file) {
3945759b3d2Safresh1        $aborted = 1;
3955759b3d2Safresh1        my ($ok, $err) = do_unlink($abort_file);
3965759b3d2Safresh1        warn $err unless $ok;
3975759b3d2Safresh1    }
3985759b3d2Safresh1
3995759b3d2Safresh1    opendir(my $dh, $tempdir) or $self->abort("Could not open temp dir! ($tempdir)");
4005759b3d2Safresh1    while(my $file = readdir($dh)) {
4015759b3d2Safresh1        next if $file =~ m/^\.+$/;
4025759b3d2Safresh1        next if $file =~ m/\.complete$/;
4035759b3d2Safresh1        my $full = File::Spec->catfile($tempdir, $file);
4045759b3d2Safresh1
4055759b3d2Safresh1        my $sep = ipc_separator;
4065759b3d2Safresh1        if ($aborted || $file =~ m/^(GLOBAL|HUB$sep)/) {
4075759b3d2Safresh1            $full =~ m/^(.*)$/;
4085759b3d2Safresh1            $full = $1; # Untaint it
4095759b3d2Safresh1            next if $ENV{T2_KEEP_TEMPDIR};
4105759b3d2Safresh1            my ($ok, $err) = do_unlink($full);
4115759b3d2Safresh1            $self->abort("Could not unlink IPC file '$full': $err") unless $ok;
4125759b3d2Safresh1            next;
4135759b3d2Safresh1        }
4145759b3d2Safresh1
4155759b3d2Safresh1        $self->abort("Leftover files in the directory ($full)!\n");
4165759b3d2Safresh1    }
4175759b3d2Safresh1    closedir($dh);
4185759b3d2Safresh1
4195759b3d2Safresh1    if ($ENV{T2_KEEP_TEMPDIR}) {
4205759b3d2Safresh1        print STDERR "# Not removing temp dir: $tempdir\n";
4215759b3d2Safresh1        return;
4225759b3d2Safresh1    }
4235759b3d2Safresh1
4245759b3d2Safresh1    my $abort = File::Spec->catfile($self->{+TEMPDIR}, "ABORT");
4255759b3d2Safresh1    unlink($abort) if -e $abort;
4265759b3d2Safresh1    rmdir($tempdir) or warn "Could not remove IPC temp dir ($tempdir)";
4275759b3d2Safresh1}
4285759b3d2Safresh1
4295759b3d2Safresh11;
4305759b3d2Safresh1
4315759b3d2Safresh1__END__
4325759b3d2Safresh1
4335759b3d2Safresh1=pod
4345759b3d2Safresh1
4355759b3d2Safresh1=encoding UTF-8
4365759b3d2Safresh1
4375759b3d2Safresh1=head1 NAME
4385759b3d2Safresh1
4395759b3d2Safresh1Test2::IPC::Driver::Files - Temp dir + Files concurrency model.
4405759b3d2Safresh1
4415759b3d2Safresh1=head1 DESCRIPTION
4425759b3d2Safresh1
4435759b3d2Safresh1This is the default, and fallback concurrency model for L<Test2>. This
4445759b3d2Safresh1sends events between processes and threads using serialized files in a
4455759b3d2Safresh1temporary directory. This is not particularly fast, but it works everywhere.
4465759b3d2Safresh1
4475759b3d2Safresh1=head1 SYNOPSIS
4485759b3d2Safresh1
4495759b3d2Safresh1    use Test2::IPC::Driver::Files;
4505759b3d2Safresh1
4515759b3d2Safresh1    # IPC is now enabled
4525759b3d2Safresh1
4535759b3d2Safresh1=head1 ENVIRONMENT VARIABLES
4545759b3d2Safresh1
4555759b3d2Safresh1=over 4
4565759b3d2Safresh1
4575759b3d2Safresh1=item T2_KEEP_TEMPDIR=0
4585759b3d2Safresh1
4595759b3d2Safresh1When true, the tempdir used by the IPC driver will not be deleted when the test
4605759b3d2Safresh1is done.
4615759b3d2Safresh1
4625759b3d2Safresh1=item T2_TEMPDIR_TEMPLATE='test2-XXXXXX'
4635759b3d2Safresh1
4645759b3d2Safresh1This can be used to set the template for the IPC temp dir. The template should
4655759b3d2Safresh1follow template specifications from L<File::Temp>.
4665759b3d2Safresh1
4675759b3d2Safresh1=back
4685759b3d2Safresh1
4695759b3d2Safresh1=head1 SEE ALSO
4705759b3d2Safresh1
4715759b3d2Safresh1See L<Test2::IPC::Driver> for methods.
4725759b3d2Safresh1
4735759b3d2Safresh1=head1 SOURCE
4745759b3d2Safresh1
4755759b3d2Safresh1The source code repository for Test2 can be found at
476*5486feefSafresh1L<https://github.com/Test-More/test-more/>.
4775759b3d2Safresh1
4785759b3d2Safresh1=head1 MAINTAINERS
4795759b3d2Safresh1
4805759b3d2Safresh1=over 4
4815759b3d2Safresh1
4825759b3d2Safresh1=item Chad Granum E<lt>exodist@cpan.orgE<gt>
4835759b3d2Safresh1
4845759b3d2Safresh1=back
4855759b3d2Safresh1
4865759b3d2Safresh1=head1 AUTHORS
4875759b3d2Safresh1
4885759b3d2Safresh1=over 4
4895759b3d2Safresh1
4905759b3d2Safresh1=item Chad Granum E<lt>exodist@cpan.orgE<gt>
4915759b3d2Safresh1
4925759b3d2Safresh1=back
4935759b3d2Safresh1
4945759b3d2Safresh1=head1 COPYRIGHT
4955759b3d2Safresh1
496256a93a4Safresh1Copyright 2020 Chad Granum E<lt>exodist@cpan.orgE<gt>.
4975759b3d2Safresh1
4985759b3d2Safresh1This program is free software; you can redistribute it and/or
4995759b3d2Safresh1modify it under the same terms as Perl itself.
5005759b3d2Safresh1
501*5486feefSafresh1See L<https://dev.perl.org/licenses/>
5025759b3d2Safresh1
5035759b3d2Safresh1=cut
504