Force xt/ tests to run on anything involving a create_distdir
[dbsrgits/DBIx-Class.git] / t / 84serialize.t
1 use strict;
2 use warnings;
3
4 use Test::More;
5 use Test::Exception;
6 use lib qw(t/lib);
7 use DBICTest;
8 use Storable qw(dclone freeze nfreeze thaw);
9 use Scalar::Util qw/refaddr/;
10
11 sub ref_ne {
12   my ($refa, $refb) = map { refaddr $_ or die "$_ is not a reference!" } @_[0,1];
13   cmp_ok (
14     $refa,
15       '!=',
16     $refb,
17     sprintf ('%s (0x%07x != 0x%07x)',
18       $_[2],
19       $refa,
20       $refb,
21     ),
22   );
23 }
24
25 my $schema = DBICTest->init_schema;
26
27 my %stores = (
28     dclone_method           => sub { return $schema->dclone($_[0]) },
29     dclone_func             => sub {
30       local $DBIx::Class::ResultSourceHandle::thaw_schema = $schema;
31       return dclone($_[0])
32     },
33     "freeze/thaw_method"    => sub {
34       my $ice = $schema->freeze($_[0]);
35       return $schema->thaw($ice);
36     },
37     "nfreeze/thaw_func"      => sub {
38       my $ice = freeze($_[0]);
39       local $DBIx::Class::ResultSourceHandle::thaw_schema = $schema;
40       return thaw($ice);
41     },
42
43     "freeze/thaw_func (cdbi legacy)" => sub {
44       # this one is special-cased to leak the $schema all over
45       # the same way as cdbi-compat does
46       DBICTest::Artist->result_source_instance->schema($schema);
47       DBICTest::CD->result_source_instance->schema($schema);
48
49       my $fire = thaw(freeze($_[0]));
50
51       # clean up the mess
52       $_->result_source_instance->schema(undef)
53         for map { $schema->class ($_) } $schema->sources;
54
55       return $fire;
56     },
57
58 );
59
60 if ($ENV{DBICTEST_MEMCACHED}) {
61   if (DBIx::Class::Optional::Dependencies->req_ok_for ('test_memcached')) {
62     my $memcached = Cache::Memcached->new(
63       { servers => [ $ENV{DBICTEST_MEMCACHED} ] }
64     );
65
66     my $key = 'tmp_dbic_84serialize_memcached_test';
67
68     $stores{memcached} = sub {
69       $memcached->set( $key, $_[0], 60 );
70       local $DBIx::Class::ResultSourceHandle::thaw_schema = $schema;
71       return $memcached->get($key);
72     };
73   }
74   else {
75     SKIP: {
76       skip 'Memcached tests need ' . DBIx::Class::Optional::Dependencies->req_missing_for ('test_memcached'), 1;
77     }
78   }
79 }
80 else {
81   SKIP: {
82     skip 'Set $ENV{DBICTEST_MEMCACHED} to run the memcached serialization tests', 1;
83   }
84 }
85
86
87
88 for my $name (keys %stores) {
89
90     my $store = $stores{$name};
91     my $copy;
92
93     my $artist = $schema->resultset('Artist')->find(1);
94
95     lives_ok { $copy = $store->($artist) } "serialize row object lives: $name";
96     ref_ne($copy, $artist, 'Simple row cloned');
97     is_deeply($copy, $artist, "serialize row object works: $name");
98
99     my $cd_rs = $artist->search_related("cds");
100
101     # test that a live result source can be serialized as well
102     is( $cd_rs->count, 3, '3 CDs in database');
103     ok( $cd_rs->next, 'Advance cursor' );
104
105     lives_ok {
106       $copy = $store->($cd_rs);
107
108       ref_ne($copy, $artist, 'Simple row cloned');
109
110       is_deeply (
111         [ $copy->all ],
112         [ $cd_rs->all ],
113         "serialize resultset works: $name",
114       );
115     } "serialize resultset lives: $name";
116
117     # Test that an object with a related_resultset can be serialized.
118     ok $artist->{related_resultsets}, 'has key: related_resultsets';
119
120     lives_ok { $copy = $store->($artist) } "serialize row object with related_resultset lives: $name";
121     for my $key (keys %$artist) {
122         next if $key eq 'related_resultsets';
123         next if $key eq '_inflated_column';
124
125         ref_ne($copy->{$key}, $artist->{$key}, "Simple row internals cloned '$key'")
126           if ref $artist->{$key};
127
128         is_deeply($copy->{$key}, $artist->{$key},
129                   qq[serialize with related_resultset '$key']);
130     }
131
132     lives_ok(
133       sub { $copy->discard_changes }, "Discard changes works: $name"
134     ) or diag $@;
135     is($copy->id, $artist->id, "IDs still match ");
136
137
138     # Test resultsource with cached rows
139     my $query_count;
140     $cd_rs = $cd_rs->search ({}, { cache => 1 });
141
142     my $orig_debug = $schema->storage->debug;
143     $schema->storage->debug(1);
144     $schema->storage->debugcb(sub { $query_count++ } );
145
146     # this will hit the database once and prime the cache
147     my @cds = $cd_rs->all;
148
149     lives_ok {
150       $copy = $store->($cd_rs);
151       ref_ne($copy, $cd_rs, 'Cached resultset cloned');
152       is_deeply (
153         [ $copy->all ],
154         [ $cd_rs->all ],
155         "serialize cached resultset works: $name",
156       );
157
158       is ($copy->count, $cd_rs->count, 'Cached count identical');
159     } "serialize cached resultset lives: $name";
160
161     is ($query_count, 1, 'Only one db query fired');
162
163     $schema->storage->debug($orig_debug);
164     $schema->storage->debugcb(undef);
165 }
166
167 # test schema-less detached thaw
168 {
169   my $artist = $schema->resultset('Artist')->find(1);
170
171   $artist = dclone $artist;
172
173   is( $artist->name, 'Caterwauler McCrae', 'getting column works' );
174
175   ok( $artist->update, 'Non-dirty update noop' );
176
177   ok( $artist->name( 'Beeeeeeees' ), 'setting works' );
178
179   ok( $artist->is_column_changed( 'name' ), 'Column dirtyness works' );
180   ok( $artist->is_changed, 'object dirtyness works' );
181
182   my $rs = $artist->result_source->resultset;
183   $rs->set_cache([ $artist ]);
184
185   is( $rs->count, 1, 'Synthetic resultset count works' );
186
187   my $exc = qr/Unable to perform storage-dependent operations with a detached result source.+use \$schema->thaw/;
188
189   throws_ok { $artist->update }
190     $exc,
191     'Correct exception on row op'
192   ;
193
194   throws_ok { $artist->discard_changes }
195     $exc,
196     'Correct exception on row op'
197   ;
198
199   throws_ok { $rs->find(1) }
200     $exc,
201     'Correct exception on rs op'
202   ;
203 }
204
205 done_testing;