Finally implement compound OptDep group augmentation
[dbsrgits/DBIx-Class.git] / t / 52leaks.t
index af8caa2..a212a49 100644 (file)
@@ -21,6 +21,19 @@ use strict;
 use warnings;
 use Test::More;
 
+use lib qw(t/lib);
+use DBICTest::RunMode;
+
+plan skip_all => "Temporarily no smoke testing of Test::More 1.3xx alphas" if (
+  DBICTest::RunMode->is_smoker
+    and
+  eval { Test::More->VERSION("1.300") }
+    and
+  require ExtUtils::MakeMaker
+    and
+  MM->parse_version($INC{"Test/Builder.pm"}) =~ / ^ 1 \. 3.. ... \_ /x
+);
+
 my $TB = Test::More->builder;
 if ($ENV{DBICTEST_IN_PERSISTENT_ENV}) {
   # without this explicit close older TBs warn in END after a ->reset
@@ -45,11 +58,10 @@ 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);
+use DBICTest::Util::LeakTracer qw(populate_weakregistry assert_empty_weakregistry visit_refs);
+use Scalar::Util qw(weaken blessed reftype);
 use DBIx::Class;
+use DBIx::Class::_Util qw(hrefaddr sigwarn_silencer);
 BEGIN {
   plan skip_all => "Your perl version $] appears to leak like a sieve - skipping test"
     if DBIx::Class::_ENV_::PEEPEENESS;
@@ -105,7 +117,7 @@ unless (DBICTest::RunMode->is_plain) {
   # Load them and empty the registry
 
   # this loads the DT armada
-  $has_dt = DBIx::Class::Optional::Dependencies->req_ok_for('test_dt_sqlite');
+  $has_dt = DBIx::Class::Optional::Dependencies->req_ok_for([qw( test_rdbms_sqlite icdt )]);
 
   require Errno;
   require DBI;
@@ -214,9 +226,6 @@ unless (DBICTest::RunMode->is_plain) {
   my $getcol_rs = $cds_rs->get_column('me.cdid');
   my $pref_getcol_rs = $cds_with_stuff->get_column('me.cdid');
 
-  # fire the column getters
-  my @throwaway = $pref_getcol_rs->all;
-
   my $base_collection = {
     resultset => $rs,
 
@@ -256,16 +265,34 @@ unless (DBICTest::RunMode->is_plain) {
     leaky_resultset_cond => $cond_rowobj,
   };
 
-  # fire all resultsets multiple times
-  # even if some of them can't find anything
-  # (notably leaky_resultset)
-  my @rsets = grep
-    { blessed $_ and $_->isa('DBIx::Class::ResultSet') }
-    values %$base_collection
-  ;
+  # fire all resultsets multiple times, once here, more below
+  # some of these can't find anything (notably leaky_resultset)
+  my @rsets = grep {
+    blessed $_
+      and
+    (
+      $_->isa('DBIx::Class::ResultSet')
+        or
+      $_->isa('DBIx::Class::ResultSetColumn')
+    )
+  } values %$base_collection;
+
+
+  my $fire_resultsets = sub {
+    local $ENV{DBIC_COLUMNS_INCLUDE_FILTER_RELS} = 1;
+    local $SIG{__WARN__} = sigwarn_silencer(
+      qr/Unable to deflate 'filter'-type relationship 'artist'.+related object primary key not retrieved/
+    );
+
+    map
+      { $_, (blessed($_) ? { $_->get_columns } : ()) }
+      map
+        { $_->all }
+        @rsets
+    ;
+  };
 
-  push @{$base_collection->{random_results}}, map { $_->all } @rsets
-    for (1,2);
+  push @{$base_collection->{random_results}}, $fire_resultsets->();
 
   # FIXME - something throws a Storable for a spin if we keep
   # the results in-collection. The same problem is seen above,
@@ -304,6 +331,65 @@ unless (DBICTest::RunMode->is_plain) {
         1;  # true means "keep descending"
       },
     );
+
+    # do a heavy-duty fire-and-compare loop on all resultsets
+    # this is expensive - not running on install
+    my $typecounts = {};
+    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
+      # an "empty" resulting hash
+      # However due to gross inefficiencies in the ::ResultSet code we
+      # end up recalculating a new set of aliasmaps which could have very
+      # well been cached if it wasn't for... anyhow
+      # What we do here for the time being is similar to the lazy approach
+      # of Devel::LeakTrace - we just make sure we do not end up with more
+      # reftypes than when we started. At least we are not blanket-counting
+      # SVs like D::LT does, but going by reftype... sigh...
+
+      for (values %$weak_registry) {
+        if ( my $r = reftype($_->{weakref}) ) {
+          $typecounts->{$r}--;
+        }
+      }
+
+      # For now we can only reuse the same registry, see FIXME above/below
+      #for my $interim_wr ({}, {}) {
+      for my $interim_wr ( ($weak_registry) x 4 ) {
+
+        visit_refs(
+          refs => [ $fire_resultsets->(), @rsets ],
+          action => sub {
+            populate_weakregistry ($interim_wr, $_[0]);
+            1;  # true means "keep descending"
+          },
+        );
+
+        # FIXME - this is what *should* be here
+        #
+        ## anything we have seen so far is cool
+        #delete @{$interim_wr}{keys %$weak_registry};
+        #
+        ## moment of truth - the rest ought to be gone
+        #assert_empty_weakregistry($interim_wr);
+      }
+
+      for (values %$weak_registry) {
+        if ( my $r = reftype($_->{weakref}) ) {
+          $typecounts->{$r}++;
+        }
+      }
+    }
+
+    for (keys %$typecounts) {
+      fail ("Amount of $_ refs changed by $typecounts->{$_} during resultset mass-execution")
+        if ( abs ($typecounts->{$_}) > 1 ); # there is a pad caught somewhere, the +1/-1 can be ignored
+    }
   }
 
   if ($has_dt) {
@@ -380,6 +466,17 @@ for my $addr (keys %$weak_registry) {
     delete $weak_registry->{$addr}
       unless $cleared->{hash_merge_singleton}{$weak_registry->{$addr}{weakref}{behavior}}++;
   }
+  elsif (
+#    # 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
+    # and non-quoted DDL, allow one for each quoting style
+    delete $weak_registry->{$addr}
+      unless $cleared->{sqlt_ddl_sqlite}->{@{$weak_registry->{$addr}{weakref}->quote_chars}}++;
+  }
 }
 
 # FIXME !!!
@@ -436,23 +533,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};
@@ -462,6 +543,23 @@ SKIP: {
 
   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: {
@@ -510,10 +608,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,
+    );
   }
 }