File Coverage

blib/lib/Test/Perinci/Tx/Manager.pm
Criterion Covered Total %
statement 323 356 90.7
branch 115 164 70.1
condition 25 56 44.6
subroutine 14 14 100.0
pod 1 1 100.0
total 478 591 80.8


line stmt bran cond sub pod time code
1             package Test::Perinci::Tx::Manager;
2              
3             our $DATE = '2015-10-22'; # DATE
4             our $VERSION = '0.54'; # VERSION
5              
6 3     3   167105 use 5.010;
  3         13  
7 3     3   15 use strict;
  3         6  
  3         63  
8 3     3   14 use warnings;
  3         6  
  3         88  
9 3     3   3509 use Log::Any::IfLOG '$log';
  3         36  
  3         16  
10              
11 3     3   2237 use File::Remove qw(remove);
  3         5888  
  3         200  
12 3     3   2696 use Perinci::Access::Schemeless;
  3         92692  
  3         116  
13 3     3   2651 use Perinci::Tx::Manager;
  3         12  
  3         123  
14 3     3   16 use Scalar::Util qw(blessed);
  3         7  
  3         207  
15 3     3   16 use Test::More 0.98;
  3         70  
  3         37  
16 3     3   985 use UUID::Random;
  3         6  
  3         1074  
17              
18             require Exporter;
19             our @ISA = qw(Exporter);
20             our @EXPORT_OK = qw(test_tx_action);
21              
22             # note: performing transaction actions is done via riap, just for convenience as
23             # well as testing riap. unless when testing lower-level stuffs, where we access
24             # $tm and the transactional function directly.
25              
26             sub test_tx_action {
27 7     7 1 7916 my %targs = @_;
28              
29 7 50       44 my $tmpdir =$targs{tmpdir} or die "BUG: please supply tmpdir";
30 7 50       40 my $reset_state=$targs{reset_state} or die "BUG: please supply reset_state";
31              
32 7         17 my $tm;
33 7 50       42 if ($targs{reset_db_dir}) {
34 0         0 remove "$tmpdir/.tx";
35             }
36              
37 7         31 $reset_state->();
38              
39             my $pa = Perinci::Access::Schemeless->new(
40             use_tx=>1,
41             custom_tx_manager => sub {
42 202     202   45548 my $self = shift;
43 202   66     1103 $tm //= Perinci::Tx::Manager->new(
44             data_dir => "$tmpdir/.tx", pa => $self);
45 202 50       1895 die $tm unless blessed($tm);
46 202         1113 $tm;
47 7         179 });
48              
49 7         3389 my $f = $targs{f};
50 7   50     40 my $fargs = $targs{args} // {};
51             my $tname = $targs{name} //
52 7   33     29 "call $f => {".join(",", map{"$_=>$fargs->{$_}"} sort keys %$fargs)."}";
  0         0  
53              
54             subtest $tname => sub {
55 7     7   6481 my $res;
56             my $estatus; # expected status
57 0         0 my $tx_id;
58 0         0 my ($tx_id1);
59 0         0 my $done_testing;
60              
61 7         32 my $uri = "/$f"; $uri =~ s!::!/!g;
  7         37  
62              
63 7         18 my $num_actions = 0;
64 7         17 my $num_undo_actions = 0;
65 3     3   16 no strict 'refs';
  3         5  
  3         12983  
66 7         34 $res = *{$f}{CODE}->(%$fargs, -tx_action=>'check_state');
  7         71  
67 7         337 my $has_do_actions;
68 7 100       34 if ($res->[0] == 200) {
69 2 100       8 if ($res->[3]{do_actions}) {
70 1         2 $num_actions = @{ $res->[3]{do_actions} };
  1         3  
71 1         3 $has_do_actions++;
72             } else {
73 1         2 $num_actions = 1;
74             }
75 2         12 note "number of actions: $num_actions";
76 2         302 $num_undo_actions = @{ $res->[3]{undo_actions} };
  2         7  
77 2         11 note "number of undo actions: $num_undo_actions";
78             }
79              
80              
81             subtest "==test_tx_action 01/11: normal action + commit==" => sub {
82 7         4469 $tx_id = UUID::Random::generate();
83 7         465 $res = $pa->request(begin_tx => "/", {tx_id=>$tx_id});
84 7 50       432 unless (is($res->[0], 200, "begin_tx succeeds")) {
85 0         0 note "res = ", explain($res);
86 0         0 goto DONE_TESTING;
87             }
88              
89             $res = $pa->request(call => $uri, {
90 7         5738 args => $fargs, tx_id=>$tx_id, confirm=>$targs{confirm}});
91 7   100     658 $estatus = $targs{status} // 200;
92 7 50       91 unless(is($res->[0], $estatus, "status is $estatus")) {
93 0         0 note "res = ", explain($res);
94 0         0 goto DONE_TESTING;
95             }
96 7 100       5809 do { $done_testing++; return } unless $estatus == 200;
  4         14  
  4         19  
97              
98 3         34 $res = $pa->request(commit_tx => "/", {tx_id=>$tx_id});
99 3 50       200 unless(is($res->[0], 200, "commit_tx succeeds")) {
100 0         0 note "res = ", explain($res);
101 0         0 goto DONE_TESTING;
102             }
103 3         2679 $tx_id1 = $tx_id;
104 7         356 };
105 0         0 subtest "after_do" => sub { $targs{after_do}->(); ok 1 }
  0         0  
106 7 50       8990 if $targs{after_do};
107 7 100 66     105 goto DONE_TESTING if $done_testing || !Test::More->builder->is_passing;
108              
109              
110             subtest "==test_tx_action 02/11: repeat action -> noop (idempotent), rollback==" => sub {
111 3         3359 $tx_id = UUID::Random::generate();
112 3         299 $res = $pa->request(begin_tx => "/", {tx_id=>$tx_id});
113             $res = $pa->request(call => $uri, {
114 3         399 args => $fargs, tx_id=>$tx_id, confirm=>$targs{confirm}});
115 3 50       270 unless(is($res->[0], 304, "status is 304")) {
116 0         0 note "res = ", explain($res);
117 0         0 goto DONE_TESTING;
118             }
119              
120 3         2934 $res = $pa->request(rollback_tx => "/", {tx_id=>$tx_id});
121 3 50       167 unless(is($res->[0], 200, "rollback_tx succeeds")) {
122 0         0 note "res = ", explain($res);
123 0         0 goto DONE_TESTING;
124             }
125 3         139 };
126 3 50 33     6042 goto DONE_TESTING if $done_testing || !Test::More->builder->is_passing;
127              
128              
129 0         0 subtest "before_undo" => sub { $targs{before_undo}->(); ok 1 }
  0         0  
130 3 50       77 if $targs{before_undo};
131             subtest "==test_tx_action 03/11: undo==" => sub {
132             $res = $pa->request(undo => "/", {
133 3         2690 tx_id=>$tx_id1, confirm=>$targs{confirm}});
134 3   50     201 $estatus = $targs{undo_status} // 200;
135 3 50       53 unless(is($res->[0], $estatus, "status is $estatus")) {
136 0         0 note "res = ", explain($res);
137 0         0 goto DONE_TESTING;
138             }
139 3 50       3045 do { $done_testing++; return } unless $estatus == 200;
  0         0  
  0         0  
140 3         37 $res = $tm->list(tx_id=>$tx_id1, detail=>1);
141 3 50       64 is($res->[2][0]{tx_status}, 'U', "transaction status is U")
142             or note "res = ", explain($res);
143 3         43 };
144 0         0 subtest "after_undo" => sub { $targs{after_undo}->(); ok 1 }
  0         0  
145 3 50       6615 if $targs{after_undo};
146 3 50 33     56 goto DONE_TESTING if $done_testing || !Test::More->builder->is_passing;
147              
148              
149             subtest "==test_tx_action 04/11: crash during action -> rollback==" => sub {
150 3         3530 $tx_id = UUID::Random::generate();
151              
152 3         270 for my $i (1..$num_actions) {
153 4         4185 $res = $pa->request(begin_tx => "/", {tx_id=>$tx_id});
154             subtest "crash at action #$i" => sub {
155 4         5228 my $ja = 0;
156             local $Perinci::Tx::Manager::_hooks{after_fix_state} = sub {
157 14         97 my ($self, %args) = @_;
158 14   50     165 my $nl = $self->{_action_nest_level} // 0;
159 14 100       95 return unless $nl <= ($has_do_actions ? 2:1);
    50          
160 14 100       99 return if $args{which} eq 'rollback';
161 7 50       53 $ja++ if $args{which} eq 'action';
162 7 100 66     91 if ($ja == $i && $nl == ($has_do_actions ? 2:1)) {
    100          
163 4         15 for ("CRASH DURING ACTION") {$log->trace($_);die $_}
  4         59  
  4         140  
164             }
165 4         51 };
166 4         14 eval {
167 4         56 $res = $pa->request(call=>$uri,
168             {args=>$fargs,tx_id=>$tx_id});
169             };
170              
171             # doesn't die, trapped by eval{} in _action_loop. there's
172             # also eval{} placed by periwrap
173             #ok($@, "dies") or note "res = ", explain($res);
174              
175             # reinit TM / recover
176 4         395 $tm = Perinci::Tx::Manager->new(
177             data_dir => "$tmpdir/.tx", pa => $pa);
178 4         38 $res = $tm->list(tx_id=>$tx_id, detail=>1);
179 4 50       131 is($res->[2][0]{tx_status}, 'R', "transaction status is R")
180             or note "res = ", explain($res);
181 4         359 };
182              
183             }
184 3 100       3778 ok 1 if !$num_actions;
185 3         134 };
186 3 50 33     3492 goto DONE_TESTING if $done_testing || !Test::More->builder->is_passing;
187              
188              
189             subtest "==test_tx_action 05/11: crash during rollback -> tx status X==" => sub {
190 3         2220 $tx_id = UUID::Random::generate();
191              
192 3         201 my $i = 0;
193 3         11 my $last;
194 3         11 while (1) {
195 10         69 $i++;
196 10 100       55 last if $last;
197 7         70 $res = $pa->request(begin_tx => "/", {tx_id=>$tx_id});
198             subtest "crash at rollback #$i" => sub {
199 7         10111 my $ja = 0; my $jrb = 0; my $crashed;
  7         28  
  7         23  
200             local $Perinci::Tx::Manager::_hooks{after_fix_state} = sub {
201 25         189 my ($self, %args) = @_;
202 25   50     169 my $nl = $self->{_action_nest_level} // 0;
203 25 100       173 return unless $nl <= ($has_do_actions ? 2:1);
    50          
204 25 100       147 if ($args{which} eq 'action') {
205             # we need to trigger the rollback first, after last
206             # action
207 14 100       117 return unless ++$ja >= $num_actions;
208 6         26 for ("CRASH DURING ACTION") {$log->trace($_);die $_}
  6         56  
  6         221  
209             }
210 11 50       57 $jrb++ if $args{which} eq 'rollback';
211 11 100       81 if ($jrb == $i) {
212 4         15 for("CRASH DURING ROLLBACK"){
213 4         12 $crashed++; $log->trace($_); die $_;
  4         34  
  4         122  
214             }
215             }
216 7         100 };
217 7         31 eval {
218 7         96 $res = $pa->request(call=>$uri,
219             {args=>$fargs,tx_id=>$tx_id});
220             };
221 7 100       545 do { ok 1; $last++; return } unless $crashed;
  3         39  
  3         3142  
  3         80  
222              
223             # doesn't die, trapped by eval{} in _action_loop. there's
224             # also eval{} placed by periwrap
225             #ok($@, "dies") or note "res = ", explain($res);
226              
227             # reinit TM / recover
228 4         72 $tm = Perinci::Tx::Manager->new(
229             data_dir => "$tmpdir/.tx", pa => $pa);
230 4         37 $res = $tm->list(tx_id=>$tx_id, detail=>1);
231 4 50       141 is($res->[2][0]{tx_status}, 'X', "transaction status is X")
232             or note "res = ", explain($res);
233 7         613 };
234 7         12806 $reset_state->();
235             }
236 3         94 };
237 3 50 33     3930 goto DONE_TESTING if $done_testing || !Test::More->builder->is_passing;
238              
239              
240             subtest "==test_tx_action 06/11: redo==" => sub {
241             $res = $pa->request(redo => "/", {
242 3         3202 tx_id=>$tx_id1, confirm=>$targs{confirm}});
243 3 50       375 unless (is($res->[0], 200, "redo succeeds")) {
244 0         0 note "res = ", explain($res);
245 0         0 goto DONE_TESTING;
246             }
247 3         2619 $res = $tm->list(tx_id=>$tx_id1, detail=>1);
248 3 50       57 is($res->[2][0]{tx_status}, 'C', "transaction status is C")
249             or note "res = ", explain($res);
250 3         112 };
251 3 50 33     5325 goto DONE_TESTING if $done_testing || !Test::More->builder->is_passing;
252              
253              
254 0         0 subtest "before_undo" => sub { $targs{before_undo}->(); ok 1 }
  0         0  
255 3 50       80 if $targs{before_undo};
256             subtest "==test_tx_action 07/11: undo #2==" => sub {
257             $res = $pa->request(undo => "/", {
258 3         2759 tx_id=>$tx_id1, confirm=>$targs{confirm}});
259 3 50       207 unless (is($res->[0], 200, "undo succeeds")) {
260 0         0 note "res = ", explain($res);
261 0         0 goto DONE_TESTING;
262             }
263 3         2896 $res = $tm->list(tx_id=>$tx_id1, detail=>1);
264 3 50       66 is($res->[2][0]{tx_status}, 'U', "transaction status is U")
265             or note "res = ", explain($res);
266 3         37 };
267 3 50 33     6034 goto DONE_TESTING if $done_testing || !Test::More->builder->is_passing;
268 0         0 subtest "after_undo" => sub { $targs{after_undo}->(); ok 1 }
  0         0  
269 3 50       92 if $targs{after_undo};
270              
271              
272             subtest "==test_tx_action 08/11: crash while undo -> roll forward==" => sub {
273 3         3226 $tx_id = UUID::Random::generate();
274 3         293 for my $i (1..$num_undo_actions) {
275              
276             # first create a committed transaction
277 4         4464 $pa->request(discard_tx=>"/", {tx_id=>$tx_id});
278 4         267 $pa->request(begin_tx => "/", {tx_id=>$tx_id});
279             $pa->request(call => $uri, {
280 4         274 args=>$fargs, tx_id=>$tx_id, confirm=>$targs{confirm}});
281 4         381 $pa->request(commit_tx => "/", {tx_id=>$tx_id});
282 4         241 $res = $tm->list(tx_id=>$tx_id, detail=>1);
283 4 50       109 is($res->[2][0]{tx_status}, 'C', "transaction status is C")
284             or note "res = ", explain($res);
285              
286             subtest "crash at undo action #$i" => sub {
287 4         4186 my $ju = 0;
288 4         32 local $Perinci::Tx::Manager::_settings{default_rollback_on_action_failure} = 0;
289             local $Perinci::Tx::Manager::_hooks{after_fix_state} = sub {
290 14         104 my ($self, %args) = @_;
291 14   50     135 my $nl = $self->{_action_nest_level} // 0;
292 14 50       81 return unless $args{which} eq 'undo';
293 14 100       107 if (++$ju == $i) {
294 4         17 for ("CRASH DURING UNDO ACTION") {
295 4         36 $log->trace($_);die $_;
  4         138  
296             }
297             }
298 4         47 };
299 4         14 eval {
300 4         45 $res = $pa->request(undo=>"/", {tx_id=>$tx_id});
301             };
302              
303             # doesn't die, trapped by eval{} in _action_loop. there's
304             # also eval{} placed by periwrap
305             #ok($@, "dies") or note "res = ", explain($res);
306              
307             # reinit TM / recover
308 4         252 $tm = Perinci::Tx::Manager->new(
309             data_dir => "$tmpdir/.tx", pa => $pa);
310 4         44 $res = $tm->list(tx_id=>$tx_id, detail=>1);
311 4 50       186 is($res->[2][0]{tx_status}, 'U', "transaction status is U")
312             or note "res = ", explain($res);
313 4         3834 };
314              
315             }
316 3 100       3878 ok 1 if !$num_undo_actions;
317 3         45 };
318 3 50 33     3335 goto DONE_TESTING if $done_testing || !Test::More->builder->is_passing;
319              
320              
321             subtest "==test_tx_action 09/11: crash while roll forward failed undo -> tx status X==" => sub {
322 3         1804 $tx_id = UUID::Random::generate();
323              
324 3         164 my $i = 0;
325 3         8 my $last;
326 3         7 while (1) {
327 10         11181 $i++;
328 10 100       51 last if $last;
329              
330             # first create a committed transaction
331 7         42 $reset_state->();
332 7         95 $pa->request(discard_tx=>"/", {tx_id=>$tx_id});
333 7         346 $pa->request(begin_tx => "/", {tx_id=>$tx_id});
334             $pa->request(call => $uri, {
335 7         372 args=>$fargs, tx_id=>$tx_id, confirm=>$targs{confirm}});
336 7         591 $pa->request(commit_tx => "/", {tx_id=>$tx_id});
337 7         473 $res = $tm->list(tx_id=>$tx_id, detail=>1);
338 7 50       189 is($res->[2][0]{tx_status}, 'C', "transaction status is C")
339             or note "res = ", explain($res);
340              
341             subtest "crash at rollback action #$i" => sub {
342 7         7686 my $ju = 0; my $jrb = 0; my $crashed;
  7         25  
  7         24  
343             local $Perinci::Tx::Manager::_hooks{after_fix_state} = sub {
344 26         179 my ($self, %args) = @_;
345 26 100       200 if ($args{which} eq 'undo') {
    50          
346             # first we trigger a rollback at the last step
347 15 100       152 if (++$ju == $num_undo_actions) {
348 6         23 for ("CRASH DURING UNDO ACTION") {
349 6         54 $log->trace($_);die $_;
  6         198  
350             }
351             }
352             } elsif ($args{which} eq 'rollback') {
353 11 100       88 if (++$jrb == $i) {
354 4         13 for ("CRASH DURING ROLLBACK") {
355 4         10 $crashed++; $log->trace($_);die $_;
  4         33  
  4         111  
356             }
357             }
358             }
359 7         97 };
360 7         29 eval {
361 7         81 $res = $pa->request(undo=>"/", {tx_id=>$tx_id});
362             };
363 7 100       369 do { ok 1; $last++; return } unless $crashed;
  3         36  
  3         3111  
  3         69  
364              
365             # doesn't die, trapped by eval{} in _action_loop. there's
366             # also eval{} placed by periwrap
367             #ok($@, "dies") or note "res = ", explain($res);
368              
369             # reinit TM / recover
370 4         70 $tm = Perinci::Tx::Manager->new(
371             data_dir => "$tmpdir/.tx", pa => $pa);
372 4         32 $res = $tm->list(tx_id=>$tx_id, detail=>1);
373 4 50       104 is($res->[2][0]{tx_status}, 'X', "transaction status is X")
374             or note "res = ", explain($res);
375 7         6714 };
376              
377             }
378 3 100       32 ok 1 if !$num_undo_actions;
379 3         90 };
380 3 50 33     4522 goto DONE_TESTING if $done_testing || !Test::More->builder->is_passing;
381              
382              
383             subtest "==test_tx_action 10/11: crash while redo -> roll forward==" => sub {
384 3         3204 $tx_id = UUID::Random::generate();
385              
386 3         272 my $i = 0;
387 3         10 my $last;
388 3         10 while (1) {
389 11         15128 $i++;
390 11 100       71 last if $last;
391              
392 8         66 $reset_state->();
393             # first create an undone transaction
394 8         147 $pa->request(discard_tx=>"/", {tx_id=>$tx_id});
395 8         483 $pa->request(begin_tx => "/", {tx_id=>$tx_id});
396             $pa->request(call => $uri, {
397 8         500 args=>$fargs, tx_id=>$tx_id, confirm=>$targs{confirm}});
398 8         641 $pa->request(commit_tx => "/", {tx_id=>$tx_id});
399 8         516 $pa->request(undo => "/", {tx_id=>$tx_id});
400 8         445 $res = $tm->list(tx_id=>$tx_id, detail=>1);
401 8 50       230 is($res->[2][0]{tx_status}, 'U', "transaction status is U")
402             or note "res = ", explain($res);
403              
404             subtest "crash at redo action #$i" => sub {
405 8         8104 my $jrd = 0; my $crashed;
  8         24  
406 8         56 local $Perinci::Tx::Manager::_settings{default_rollback_on_action_failure} = 0;
407             local $Perinci::Tx::Manager::_hooks{after_fix_state} = sub {
408 21         162 my ($self, %args) = @_;
409 21   50     213 my $nl = $self->{_action_nest_level} // 0;
410 21 50       118 return unless $args{which} eq 'redo';
411 21 100       164 if (++$jrd == $i) {
412 5         21 for ("CRASH DURING REDO ACTION") {
413 5         14 $crashed++; $log->trace($_); die $_;
  5         58  
  5         174  
414             }
415             }
416 8         93 };
417 8         27 eval {
418 8         93 $res = $pa->request(redo=>"/", {tx_id=>$tx_id});
419             };
420 8 100       424 do { ok 1; $last++; return } unless $crashed;
  3         39  
  3         2922  
  3         71  
421              
422             # doesn't die, trapped by eval{} in _action_loop. there's
423             # also eval{} placed by periwrap
424             #ok($@, "dies") or note "res = ", explain($res);
425              
426             # reinit TM / recover
427 5         111 $tm = Perinci::Tx::Manager->new(
428             data_dir => "$tmpdir/.tx", pa => $pa);
429 5         56 $res = $tm->list(tx_id=>$tx_id, detail=>1);
430 5 50       181 is($res->[2][0]{tx_status}, 'C', "transaction status is C")
431             or note "res = ", explain($res);
432 8         7306 };
433              
434             }
435 3 100       38 ok 1 if !$num_actions;
436 3         118 };
437 3 50 33     4469 goto DONE_TESTING if $done_testing || !Test::More->builder->is_passing;
438              
439              
440             subtest "==test_tx_action 11/11: crash while roll forward failed redo -> tx status X==" => sub {
441 3         3084 $tx_id = UUID::Random::generate();
442              
443 3         269 my $i = 0;
444 3         12 my $last;
445 3         9 while (1) {
446 10         11644 $i++;
447 10 100       63 last if $last;
448              
449             # first create an undone transaction
450 7         52 $reset_state->();
451 7         110 $pa->request(discard_tx=>"/", {tx_id=>$tx_id});
452 7         382 $pa->request(begin_tx => "/", {tx_id=>$tx_id});
453             $pa->request(call => $uri, {
454 7         374 args=>$fargs, tx_id=>$tx_id, confirm=>$targs{confirm}});
455 7         512 $pa->request(commit_tx => "/", {tx_id=>$tx_id});
456 7         388 $pa->request(undo => "/", {tx_id=>$tx_id});
457 7         382 $res = $tm->list(tx_id=>$tx_id, detail=>1);
458 7 50       177 is($res->[2][0]{tx_status}, 'U', "transaction status is U")
459             or note "res = ", explain($res);
460              
461             subtest "crash at rollback action #$i" => sub {
462 7         7104 my $jrd = 0; my $jrb = 0; my $crashed;
  7         19  
  7         20  
463             local $Perinci::Tx::Manager::_hooks{after_fix_state} = sub {
464 26         178 my ($self, %args) = @_;
465 26 100       184 if ($args{which} eq 'redo') {
    50          
466             # first we trigger a rollback at the last step
467 15 100       114 if (++$jrd == $num_actions) {
468 6         25 for ("CRASH DURING REDO ACTION") {
469 6         61 $log->trace($_);die $_;
  6         229  
470             }
471             }
472             } elsif ($args{which} eq 'rollback') {
473 11 100       82 if (++$jrb == $i) {
474 4         18 for ("CRASH DURING ROLLBACK") {
475 4         13 $crashed++; $log->trace($_); die $_;
  4         37  
  4         134  
476             }
477             }
478             }
479 7         89 };
480 7         27 eval {
481 7         77 $res = $pa->request(redo=>"/", {tx_id=>$tx_id});
482             };
483 7 100       390 do { ok 1; $last++; return } unless $crashed;
  3         39  
  3         2927  
  3         68  
484              
485             # doesn't die, trapped by eval{} in _action_loop. there's
486             # also eval{} placed by periwrap
487             #ok($@, "dies") or note "res = ", explain($res);
488              
489             # reinit TM / recover
490 4         83 $tm = Perinci::Tx::Manager->new(
491             data_dir => "$tmpdir/.tx", pa => $pa);
492 4         38 $res = $tm->list(tx_id=>$tx_id, detail=>1);
493 4 50       118 is($res->[2][0]{tx_status}, 'X', "transaction status is X")
494             or note "res = ", explain($res);
495 7         6325 };
496              
497             }
498 3 100       34 ok 1 if !$num_actions;
499 3         113 };
500 3 50 33     4550 goto DONE_TESTING if $done_testing || !Test::More->builder->is_passing;
501              
502              
503 7         111 DONE_TESTING:
504             done_testing;
505 7         100 };
506             }
507              
508             # TODO: test cleanup: .tmp/XXX and .trash/XXX are cleaned
509              
510             1;
511             # ABSTRACT: Transaction tests
512              
513             __END__
514              
515             =pod
516              
517             =encoding UTF-8
518              
519             =head1 NAME
520              
521             Test::Perinci::Tx::Manager - Transaction tests
522              
523             =head1 VERSION
524              
525             This document describes version 0.54 of Test::Perinci::Tx::Manager (from Perl distribution Perinci-Tx-Manager), released on 2015-10-22.
526              
527             =head1 FUNCTIONS
528              
529             =head2 test_tx_action(%args)
530              
531             Test performing action using transaction.
532              
533             Will initialize transaction manager ($tm) and test action. Will test several
534             times with different scenarios to make sure commit, rollback, undo, redo, and
535             crash recoveries work.
536              
537             Arguments (C<*> denotes required arguments):
538              
539             =over 4
540              
541             =item * tmpdir* => STR
542              
543             Specify temporary directory to store transaction data directory in.
544              
545             =item * name => STR
546              
547             The test name.
548              
549             =item * f* => STR
550              
551             Fully-qualified name of transactional function, e.g. C<Setup::File::setup_file>.
552              
553             =item * args* => HASH (default: {})
554              
555             Arguments to feed to transactional function (via $tm->call()).
556              
557             =item * reset_state* => CODE
558              
559             The code to reset to initial state. This is called at the start of tests, as
560             well as after each rollback crash test, because crash during rollback causes the
561             state to become inconsistent.
562              
563             =item * status => INT (default: 200)
564              
565             Expect $tm->action() to return this status.
566              
567             =item * reset_db_dir => BOOL (default: 0)
568              
569             Whether to reset transaction data directory before running the tests. Note that
570             alternatively, you can also use a different C<tmpdir> for each call to this
571             function.
572              
573             =back
574              
575             =head1 HOMEPAGE
576              
577             Please visit the project's homepage at L<https://metacpan.org/release/Perinci-Tx-Manager>.
578              
579             =head1 SOURCE
580              
581             Source repository is at L<https://github.com/perlancar/perl-Perinci-Tx-Manager>.
582              
583             =head1 BUGS
584              
585             Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perinci-Tx-Manager>
586              
587             When submitting a bug or request, please include a test-file or a
588             patch to an existing test-file that illustrates the bug or desired
589             feature.
590              
591             =head1 AUTHOR
592              
593             perlancar <perlancar@cpan.org>
594              
595             =head1 COPYRIGHT AND LICENSE
596              
597             This software is copyright (c) 2015 by perlancar@cpan.org.
598              
599             This is free software; you can redistribute it and/or modify it under
600             the same terms as the Perl 5 programming language system itself.
601              
602             =cut