Make sure tests pass without a compiler present (another step to RT#74706)
[dbsrgits/DBIx-Class.git] / t / 52leaks.t
index b87ca20..b3b9b9c 100644 (file)
@@ -21,23 +21,26 @@ use strict;
 use warnings;
 use Test::More;
 
+use lib qw(t/lib);
+use DBICTest::RunMode;
+use DBICTest::Util::LeakTracer qw(populate_weakregistry assert_empty_weakregistry visit_refs);
+use Scalar::Util qw(weaken blessed reftype);
+use DBIx::Class::_Util qw(hrefaddr sigwarn_silencer modver_gt_or_eq modver_gt_or_eq_and_lt);
+BEGIN {
+  plan skip_all => "Your perl version $] appears to leak like a sieve - skipping test"
+    if DBIx::Class::_ENV_::PEEPEENESS;
+}
+
+
 my $TB = Test::More->builder;
 if ($ENV{DBICTEST_IN_PERSISTENT_ENV}) {
-  # without this explicit close older TBs warn in END after a ->reset
-  if ($TB->VERSION < 1.005) {
-    close ($TB->$_) for (qw/output failure_output todo_output/);
-  }
-
-  # if I do not do this, I get happy sigpipes on new TB, no idea why
-  # (the above close-and-forget doesn't work - new TB does *not* reopen
-  # its handles automatically anymore)
-  else {
-    for (qw/failure_output todo_output/) {
-      close $TB->$_;
-      open ($TB->$_, '>&', *STDERR);
-    }
+  # without this explicit close TB warns in END after a ->reset
+  close ($TB->$_) for qw(output failure_output todo_output);
 
-    close $TB->output;
+  # newer TB does not auto-reopen handles
+  if ( modver_gt_or_eq( 'Test::More', '1.200' ) ) {
+    open ($TB->$_, '>&', *STDERR)
+      for qw( failure_output todo_output );
     open ($TB->output, '>&', *STDOUT);
   }
 
@@ -45,17 +48,6 @@ if ($ENV{DBICTEST_IN_PERSISTENT_ENV}) {
   $TB->reset;
 }
 
-use lib qw(t/lib);
-use DBICTest::RunMode;
-use DBICTest::Util::LeakTracer qw(populate_weakregistry assert_empty_weakregistry visit_refs hrefaddr);
-use Scalar::Util qw(weaken blessed reftype);
-use DBIx::Class;
-use DBIx::Class::_Util 'sigwarn_silencer';
-BEGIN {
-  plan skip_all => "Your perl version $] appears to leak like a sieve - skipping test"
-    if DBIx::Class::_ENV_::PEEPEENESS;
-}
-
 # this is what holds all weakened refs to be checked for leakage
 my $weak_registry = {};
 
@@ -87,7 +79,7 @@ unless (DBICTest::RunMode->is_plain) {
     # Test Builder is now making a new object for every pass/fail (que bloat?)
     # and as such we can't really store any of its objects (since it will
     # re-populate the registry while checking it, ewwww!)
-    return $obj if (ref $obj) =~ /^TB2::/;
+    return $obj if (ref $obj) =~ /^TB2::|^Test::Stream/;
 
     # populate immediately to avoid weird side effects
     return populate_weakregistry ($weak_registry, $obj );
@@ -324,7 +316,11 @@ unless (DBICTest::RunMode->is_plain) {
     # do a heavy-duty fire-and-compare loop on all resultsets
     # this is expensive - not running on install
     my $typecounts = {};
-    unless (DBICTest::RunMode->is_plain) {
+    if (
+      ! DBICTest::RunMode->is_plain
+        and
+      ! $ENV{DBICTEST_IN_PERSISTENT_ENV}
+    ) {
 
       # FIXME - ideally we should be able to just populate an alternative
       # registry, subtract everything from the main one, and arrive at
@@ -360,13 +356,6 @@ unless (DBICTest::RunMode->is_plain) {
         ## anything we have seen so far is cool
         #delete @{$interim_wr}{keys %$weak_registry};
         #
-        ## I still don't get any of this...
-        #delete $interim_wr->{$_} for grep {
-        #  ref ($interim_wr->{$_}{weakref}) eq 'SCALAR'
-        #    and
-        #  ${$interim_wr->{$_}{weakref}} eq 'very closure... much wtf... wow!!!'
-        #} keys %$interim_wr;
-        #
         ## moment of truth - the rest ought to be gone
         #assert_empty_weakregistry($interim_wr);
       }
@@ -458,10 +447,22 @@ for my $addr (keys %$weak_registry) {
     delete $weak_registry->{$addr}
       unless $cleared->{hash_merge_singleton}{$weak_registry->{$addr}{weakref}{behavior}}++;
   }
+  elsif ($names =~ /^B::Hooks::EndOfScope::PP::_TieHintHashFieldHash/m) {
+    # there is one tied lexical which stays alive until GC time
+    # https://metacpan.org/source/ETHER/B-Hooks-EndOfScope-0.15/lib/B/Hooks/EndOfScope/PP/FieldHash.pm#L24
+    # simply ignore it here, instead of teaching the leaktracer to examine ties
+    # the latter is possible yet terrible: https://github.com/dbsrgits/dbix-class/blob/v0.082820/t/lib/DBICTest/Util/LeakTracer.pm#L113-L117
+    delete $weak_registry->{$addr}
+      unless $cleared->{bheos_pptiehinthashfieldhash}++;
+  }
+  elsif ($names =~ /^DateTime::TimeZone::UTC/m) {
+    # DT is going through a refactor it seems - let it leak zones for now
+    delete $weak_registry->{$addr};
+  }
   elsif (
-    # if we can look at closed over pieces - we will register it as a global
-    !DBICTest::Util::LeakTracer::CV_TRACING
-      and
+#    # if we can look at closed over pieces - we will register it as a global
+#    !DBICTest::Util::LeakTracer::CV_TRACING
+#      and
     $names =~ /^SQL::Translator::Generator::DDL::SQLite/m
   ) {
     # SQLT::Producer::SQLite keeps global generators around for quoted
@@ -525,23 +526,7 @@ $ENV{PERL5LIB} = join ($Config::Config{path_sep}, @INC);
 ($ENV{PATH}) = $ENV{PATH} =~ /(.+)/;
 
 
-my $persistence_tests = {
-  PPerl => {
-    cmd => [qw/pperl --prefork=1/, __FILE__],
-  },
-  'CGI::SpeedyCGI' => {
-    cmd => [qw/speedy -- -t5/, __FILE__],
-  },
-};
-
-# scgi is smart and will auto-reap after -t amount of seconds
-# pperl needs an actual killer :(
-$persistence_tests->{PPerl}{termcmd} = [
-  $persistence_tests->{PPerl}{cmd}[0],
-  '--kill',
-  @{$persistence_tests->{PPerl}{cmd}}[ 1 .. $#{$persistence_tests->{PPerl}{cmd}} ],
-];
-
+my $persistence_tests;
 SKIP: {
   skip 'Test already in a persistent loop', 1
     if $ENV{DBICTEST_IN_PERSISTENT_ENV};
@@ -549,8 +534,28 @@ SKIP: {
   skip 'Main test failed - skipping persistent env tests', 1
     unless $TB->is_passing;
 
+  skip "Test::Builder\@@{[ Test::Builder->VERSION ]} known to break persistence tests", 1
+    if modver_gt_or_eq_and_lt( 'Test::More', '1.200', '1.301001_099' );
+
   local $ENV{DBICTEST_IN_PERSISTENT_ENV} = 1;
 
+  $persistence_tests = {
+    PPerl => {
+      cmd => [qw/pperl --prefork=1/, __FILE__],
+    },
+    'CGI::SpeedyCGI' => {
+      cmd => [qw/speedy -- -t5/, __FILE__],
+    },
+  };
+
+  # scgi is smart and will auto-reap after -t amount of seconds
+  # pperl needs an actual killer :(
+  $persistence_tests->{PPerl}{termcmd} = [
+    $persistence_tests->{PPerl}{cmd}[0],
+    '--kill',
+    @{$persistence_tests->{PPerl}{cmd}}[ 1 .. $#{$persistence_tests->{PPerl}{cmd}} ],
+  ];
+
   require IPC::Open2;
 
   for my $type (keys %$persistence_tests) { SKIP: {
@@ -599,10 +604,13 @@ done_testing;
 # just an extra precaution in case we blew away from the SKIP - since there are no
 # PID files to go by (man does pperl really suck :(
 END {
-  unless ($ENV{DBICTEST_IN_PERSISTENT_ENV}) {
-    close $_ for (*STDIN, *STDOUT, *STDERR);
+  if ($persistence_tests->{PPerl}{termcmd}) {
     local $?; # otherwise test will inherit $? of the system()
-    system (@{$persistence_tests->{PPerl}{termcmd}})
-      if $persistence_tests->{PPerl}{termcmd};
+    require IPC::Open3;
+    open my $null, ">", File::Spec->devnull;
+    waitpid(
+      IPC::Open3::open3(undef, $null, $null, @{$persistence_tests->{PPerl}{termcmd}}),
+      0,
+    );
   }
 }