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