File Coverage

blib/lib/KiokuDB/Test/Fixture.pm
Criterion Covered Total %
statement 125 139 89.9
branch 15 26 57.6
condition 6 14 42.8
subroutine 36 37 97.3
pod 0 24 0.0
total 182 240 75.8


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2              
3             package KiokuDB::Test::Fixture;
4 4     4   2983 use Moose::Role;
  4         3401  
  4         30  
5              
6 4     4   19049 use Test::More;
  4         8  
  4         39  
7 4     4   2205 use Test::Exception;
  4         5080  
  4         27  
8              
9             sub _lives_and_ret (&;$) {
10             my ( $sub, @args ) = @_;
11              
12             my @ret;
13             my $wrapped = sub { @ret = $sub->() };
14              
15             local $Test::Builder::Level = $Test::Builder::Level + 2;
16             &lives_ok($wrapped, @args);
17              
18             return ( ( @ret == 1 ) ? $ret[0] : @ret );
19             }
20              
21 4     4   1244 use namespace::clean -except => 'meta';
  4         7  
  4         37  
22              
23             requires qw(create verify);
24              
25 102     102 0 157 sub sort { 0 }
26              
27 231     231 0 778 sub required_backend_roles { return () }
28              
29             has populate_ids => (
30             isa => "ArrayRef[Str]",
31             is => "rw",
32             predicate => "has_populate_ids",
33             clearer => "clear_populate_ids",
34             );
35              
36             sub populate {
37 314     314 0 1120 my $self = shift;
38              
39             {
40 314         682 my $s = $self->new_scope;
  314         1356  
41              
42 314         1848 my @objects = $self->create;
43              
44 314         34184 my @ids = $self->store_ok(@objects);
45              
46 314         14793 $self->populate_ids(\@ids);
47             }
48              
49 314         1821 $self->no_live_objects;
50             }
51              
52             sub name {
53 2001     2001 0 2597 my $self = shift;
54 2001   33     4850 my $class = ref($self) || $self;
55 2001         6686 $class =~ s{KiokuDB::Test::Fixture::}{};
56 2001         10672 return $class;
57             }
58              
59             sub skip_fixture {
60 81     81 0 206 my ( $self, $reason, $count ) = @_;
61              
62 81   50     326 skip $self->name . " fixture ($reason)", $count || 1
63             }
64              
65             sub precheck {
66 561     561 0 801 my $self = shift;
67              
68 561         2996 my $backend = $self->backend;
69              
70 561 50       3706 if ( $backend->does("KiokuDB::Backend::Role::Broken") ) {
71 0         0 foreach my $fixture ( $backend->skip_fixtures ) {
72 0 0 0     0 $self->skip_fixture("broken backend") if $fixture eq ref($self) or $fixture eq $self->name;
73             }
74             }
75              
76 561         33395 my @missing;
77              
78 561         2374 role: foreach my $role ( $self->required_backend_roles ) {
79 561         6713 foreach my $role_fmt ( $role, "KiokuDB::Backend::Role::$role", "KiokuDB::Backend::$role" ) {
80 1236 100 66     20362 next role if $backend->does($role_fmt) or $backend->can("serializer") and $backend->serializer->does($role_fmt);
      66        
81             }
82 81         2257 push @missing, $role;
83             }
84              
85 561 100       8203 if ( @missing ) {
86 81         284 $_ =~ s/^KiokuDB::Backend::Role::// for @missing;
87 81         754 $self->skip_fixture("Backend does not implement required roles (@missing)")
88             }
89             }
90              
91             sub run {
92 561     561 0 175076 my $self = shift;
93              
94 561         1381 SKIP: {
95 561         839 local $Test::Builder::Level = $Test::Builder::Level + 1;
96              
97 561         2418 $self->precheck;
98              
99 480         2260 $self->clear_live_objects;
100              
101 480         1631 is_deeply( [ $self->live_objects ], [ ], "no live objects at start of " . $self->name . " fixture" );
102 480         249791 is_deeply( [ $self->live_entries ], [ ], "no live entries at start of " . $self->name . " fixture" );
103              
104             lives_ok {
105 480     480   13903 local $Test::Builder::Level = $Test::Builder::Level - 1;
106             $self->txn_do(sub {
107 480         2527 my $s = $self->new_scope;
108 480         2231 $self->populate;
109 480         3483 });
110 480         27603 $self->verify;
111 480         238841 } "no error in fixture";
112              
113 480         275419 is_deeply( [ $self->live_objects ], [ ], "no live objects at end of " . $self->name . " fixture" );
114 480         252244 is_deeply( [ $self->live_entries ], [ ], "no live entries at end of " . $self->name . " fixture" );
115              
116 480         235881 $self->clear_live_objects;
117             }
118             }
119              
120             has get_directory => (
121             isa => "CodeRef|Str",
122             is => "ro",
123             );
124              
125             has directory => (
126             is => "ro",
127             isa => "KiokuDB",
128             lazy_build => 1,
129             handles => [qw(
130             lookup exists
131             store
132             insert update delete
133              
134             clear_live_objects
135              
136             backend
137             linker
138             collapser
139              
140             search
141             simple_search
142             backend_search
143              
144             is_root
145             set_root
146             unset_root
147              
148             all_objects
149             root_set
150             scan
151             grep
152              
153             new_scope
154              
155             txn_do
156              
157             object_to_id
158             objects_to_ids
159             )],
160             );
161              
162             sub _build_directory {
163 561     561   1042 my $self = shift;
164 561 50       17362 my $method = $self->get_directory or die "either 'directory' or 'get_directory' is required";
165 561         2187 return $self->$method;
166             }
167              
168             sub live_objects {
169             shift->directory->live_objects->live_objects
170 3037     3037 0 101565 }
171              
172             sub live_entries {
173             shift->directory->live_objects->live_entries
174 960     960 0 36806 }
175              
176              
177             sub update_live_objects {
178 34     34 0 60 my $self = shift;
179              
180 34     34   262 _lives_and_ret { $self->update( $self->live_objects ) } "updated live objects";
  34         103  
181             }
182              
183             sub store_ok {
184 514     514 0 1645 my ( $self, @objects ) = @_;
185              
186 514         1281 local $Test::Builder::Level = 1;
187              
188 514     514   3403 _lives_and_ret { $self->store( @objects ) } "stored " . scalar(grep { ref } @objects) . " objects";
  514         2904  
  1524         4325  
189             }
190              
191             sub update_ok {
192 468     468 0 1385 my ( $self, @objects ) = @_;
193              
194 468     468   3788 _lives_and_ret { $self->update( @objects ) } "updated " . scalar(@objects) . " objects";
  468         2425  
195             }
196              
197             sub insert_ok {
198 198     198 0 64803 my ( $self, @objects ) = @_;
199              
200 198     198   1655 _lives_and_ret { $self->insert( @objects ) } "inserted " . scalar(@objects) . " objects";
  198         1209  
201             }
202              
203             sub delete_ok {
204 166     166 0 515 my ( $self, @objects ) = @_;
205              
206 166     166   1437 _lives_and_ret { $self->delete( @objects ) } "deleted " . scalar(@objects) . " objects";
  166         1081  
207             }
208              
209             sub lookup_ok {
210 1141     1141 0 2668 my ( $self, @ids ) = @_;
211              
212 1141         1910 my @ret;
213 1141     1141   9460 _lives_and_ret { @ret = $self->lookup( @ids ) } "lookup " . scalar(@ids) . " objects";
  1141         4856  
214              
215 1141         5109 local $Test::Builder::Level = $Test::Builder::Level + 1;
216              
217 1141         2939 is( scalar(grep { ref } @ret), scalar(@ids), "all lookups succeeded" );
  1290         7327  
218              
219 1141 100       369335 return ( ( @ret == 1 ) ? $ret[0] : @ret );
220             }
221              
222             sub exists_ok {
223 165     165 0 427 my ( $self, @ids ) = @_;
224              
225 165         377 local $Test::Builder::Level = $Test::Builder::Level + 1;
226              
227 165         847 is( scalar(grep { $_ } $self->exists(@ids)), scalar(@ids), "[@ids] exist in DB" );
  165         1057  
228             }
229              
230             sub root_ok {
231 231     231 0 568 my ( $self, @objects ) = @_;
232              
233 231         527 local $Test::Builder::Level = $Test::Builder::Level + 1;
234              
235 231         938 is( scalar(grep { $_ } $self->is_root(@objects)), scalar(@objects), "[@{[ $self->objects_to_ids(@objects) ]}] are in the root set" );
  231         679  
  231         1049  
236             }
237              
238             sub not_root_ok {
239 363     363 0 749 my ( $self, @objects ) = @_;
240              
241 363         728 local $Test::Builder::Level = $Test::Builder::Level + 1;
242              
243 363         1392 is( scalar(grep { not $_ } $self->is_root(@objects)), scalar(@objects), "[@{[ $self->objects_to_ids(@objects) ]}] aren't in the root set" );
  495         1051  
  363         1327  
244             }
245              
246             sub deleted_ok {
247 266     266 0 636 my ( $self, @ids ) = @_;
248              
249 266         564 local $Test::Builder::Level = $Test::Builder::Level + 1;
250              
251 266         1144 is( scalar(grep { !$_ } $self->exists(@ids)), scalar(@ids), "@ids do not exist in DB" );
  299         1780  
252             }
253              
254             sub lookup_obj_ok {
255 204     204 0 546 my ( $self, $id, $class ) = @_;
256              
257 204         821 local $Test::Builder::Level = $Test::Builder::Level + 1;
258              
259 204         1006 ok( my $obj = $self->lookup($id), "lookup $id" );
260              
261 204 100       112575 isa_ok( $obj, $class ) if $class;
262              
263 204         50333 return $obj;
264             }
265              
266             sub no_live_objects {
267 1776     1776 0 4512 my $self = shift;
268              
269 1776         3842 local $Test::Builder::Level = $Test::Builder::Level + 1;
270              
271 1776         2067 my $fail;
272              
273 1776         6363 my @l = $self->live_objects;
274 1776         2865 my @e;
275              
276             my $failed;
277            
278 1776 50       7922 $failed++ unless is( scalar(@l), 0, "no live objects" );
279              
280 1776 100       649628 unless ( $self->directory->live_objects->txn_scope ) {
281             # no live objects should imply no live entries
282             # however, under keep_entries a txn stack is maintained
283 1545 50       6057 $failed++ unless is( scalar(@e), 0, "no live entries" );
284 1545         545337 @e = $self->directory->live_objects->live_entries;
285             }
286              
287 1776 50       19552 if ( $failed ) {
288 0 0       0 diag "live objects: " . join ", ", map { $self->object_to_id($_) . " ($_)" } @l if @l;
  0         0  
289 0         0 diag "live entries: " . join ", ", map { $_->id . " (" . $_->class . ")" } @e;
  0         0  
290              
291             #use Scalar::Util qw(weaken);
292             #weaken($_) for @l;
293              
294 0         0 $self->directory->live_objects->clear;
295              
296             #use Devel::FindRef;
297             #my $track = Devel::FindRef::track(@l);
298             #warn $track;
299             #my ( @ids ) = map { hex } ( $track =~ /by \w+\(0x([a-z0-9]+)\)/ );
300             #warn Data::Dumper::Dumper(map { Devel::FindRef::ptr2ref($_) } @ids);
301             }
302             }
303              
304             sub no_live_entries {
305 0     0 0 0 my $self = shift;
306              
307 0         0 local $Test::Builder::Level = $Test::Builder::Level + 1;
308              
309 0         0 my @e = $self->directory->live_objects->live_entries;
310              
311 0 0       0 unless ( is( scalar(@e), 0, "no live entries" ) ) {
312 0         0 diag "live entries: " . join ", ", map { $_->id . " (" . $_->class . ")" } @e;
  0         0  
313              
314 0         0 $self->directory->live_objects->clear;
315             }
316             }
317              
318             sub live_objects_are {
319 233     233 0 723 my ( $self, @objects ) = @_;
320              
321 233         692 local $Test::Builder::Level = $Test::Builder::Level + 1;
322              
323 233         937 is_deeply( [ sort $self->live_objects ], [ sort @objects ], "correct live objects" );
324             }
325              
326             sub txn_lives {
327 1147     1147 0 3426 my ( $self, $code, @args ) = @_;
328              
329             lives_ok {
330             $self->txn_do(sub {
331 1147         5570 my $s = $self->new_scope;
332 1147         4528 $code->(@_);
333 1147     1147   38476 }, @args);
334 1147         7257 } "transaction finished without errors";
335             }
336              
337             __PACKAGE__
338              
339             __END__