use strict;
use warnings;
use Test::More;
use Test::Exception;
use lib qw(t/lib);
use DBICTest;
use Storable qw(dclone freeze nfreeze thaw);
use Scalar::Util qw/refaddr/;
use Carp;
plan skip_all => 'Something causes this to fail on TravisCI'
if $ENV{TRAVIS};
sub ref_ne {
my ($refa, $refb) = map { refaddr $_ or croak "$_ is not a reference!" } @_[0,1];
cmp_ok (
$refa,
'!=',
$refb,
sprintf ('%s (0x%07x != 0x%07x)',
$_[2],
$refa,
$refb,
),
);
}
my $schema = DBICTest->init_schema;
my %stores = (
dclone_method => sub { return $schema->dclone($_[0]) },
dclone_func => sub {
local $DBIx::Class::ResultSourceHandle::thaw_schema = $schema;
return dclone($_[0])
},
"freeze/thaw_method" => sub {
my $ice = $schema->freeze($_[0]);
return $schema->thaw($ice);
},
"nfreeze/thaw_func" => sub {
my $ice = freeze($_[0]);
local $DBIx::Class::ResultSourceHandle::thaw_schema = $schema;
return thaw($ice);
},
"freeze/thaw_func (cdbi legacy)" => sub {
# this one is special-cased to leak the $schema all over
# the same way as cdbi-compat does
DBICTest::Artist->result_source_instance->schema($schema);
DBICTest::CD->result_source_instance->schema($schema);
my $fire = thaw(freeze($_[0]));
# clean up the mess
$_->result_source_instance->schema(undef)
for map { $schema->class ($_) } $schema->sources;
return $fire;
},
);
if ($ENV{DBICTEST_MEMCACHED}) {
if (DBIx::Class::Optional::Dependencies->req_ok_for ('test_memcached')) {
my $memcached = Cache::Memcached->new(
{ servers => [ $ENV{DBICTEST_MEMCACHED} ] }
);
my $key = 'tmp_dbic_84serialize_memcached_test';
$stores{memcached} = sub {
$memcached->set( $key, $_[0], 60 );
local $DBIx::Class::ResultSourceHandle::thaw_schema = $schema;
return $memcached->get($key);
};
}
else {
SKIP: {
skip 'Memcached tests need ' . DBIx::Class::Optional::Dependencies->req_missing_for ('test_memcached'), 1;
}
}
}
else {
SKIP: {
skip 'Set $ENV{DBICTEST_MEMCACHED} to run the memcached serialization tests', 1;
}
}
for my $name (keys %stores) {
my $store = $stores{$name};
my $copy;
my $artist = $schema->resultset('Artist')->find(1);
lives_ok { $copy = $store->($artist) } "serialize row object lives: $name";
ref_ne($copy, $artist, 'Simple row cloned');
is_deeply($copy, $artist, "serialize row object works: $name");
my $cd_rs = $artist->search_related("cds");
# test that a live result source can be serialized as well
is( $cd_rs->count, 3, '3 CDs in database');
ok( $cd_rs->next, 'Advance cursor' );
lives_ok {
$copy = $store->($cd_rs);
ref_ne($copy, $artist, 'Simple row cloned');
is_deeply (
[ $copy->all ],
[ $cd_rs->all ],
"serialize resultset works: $name",
);
} "serialize resultset lives: $name";
# Test that an object with a related_resultset can be serialized.
ok $artist->{related_resultsets}, 'has key: related_resultsets';
lives_ok { $copy = $store->($artist) } "serialize row object with related_resultset lives: $name";
for my $key (keys %$artist) {
next if $key eq 'related_resultsets';
next if $key eq '_inflated_column';
ref_ne($copy->{$key}, $artist->{$key}, "Simple row internals cloned '$key'")
if ref $artist->{$key};
is_deeply($copy->{$key}, $artist->{$key},
qq[serialize with related_resultset '$key']);
}
lives_ok(
sub { $copy->discard_changes }, "Discard changes works: $name"
) or diag $@;
is($copy->id, $artist->id, "IDs still match ");
# Test resultsource with cached rows
my $query_count;
$cd_rs = $cd_rs->search ({}, { cache => 1 });
my $orig_debug = $schema->storage->debug;
$schema->storage->debug(1);
$schema->storage->debugcb(sub { $query_count++ } );
# this will hit the database once and prime the cache
my @cds = $cd_rs->all;
lives_ok {
$copy = $store->($cd_rs);
ref_ne($copy, $cd_rs, 'Cached resultset cloned');
is_deeply (
[ $copy->all ],
[ $cd_rs->all ],
"serialize cached resultset works: $name",
);
is ($copy->count, $cd_rs->count, 'Cached count identical');
} "serialize cached resultset lives: $name";
is ($query_count, 1, 'Only one db query fired');
$schema->storage->debug($orig_debug);
$schema->storage->debugcb(undef);
}
# test schema-less detached thaw
{
my $artist = $schema->resultset('Artist')->find(1);
$artist = dclone $artist;
is( $artist->name, 'Caterwauler McCrae', 'getting column works' );
ok( $artist->update, 'Non-dirty update noop' );
ok( $artist->name( 'Beeeeeeees' ), 'setting works' );
ok( $artist->is_column_changed( 'name' ), 'Column dirtyness works' );
ok( $artist->is_changed, 'object dirtyness works' );
my $rs = $artist->result_source->resultset;
$rs->set_cache([ $artist ]);
is( $rs->count, 1, 'Synthetic resultset count works' );
my $exc = qr/Unable to perform storage-dependent operations with a detached result source.+use \$schema->thaw/;
throws_ok { $artist->update }
$exc,
'Correct exception on row op'
;
throws_ok { $artist->discard_changes }
$exc,
'Correct exception on row op'
;
throws_ok { $rs->find(1) }
$exc,
'Correct exception on rs op'
;
}
done_testing;