DBIx-QuickORM
view release on metacpan or search on metacpan
t/AI/transaction_audit.t view on Meta::CPAN
$txn = $con->auto_retry_txn({count => 2}, sub { die "boom\n" unless ++$calls > 2 });
};
is($calls, 3, "(\\\%params, sub) form respected count from the params hashref");
is($warnings, 2, "warned once per retry");
ok($txn->committed, "retried transaction eventually committed");
$calls = 0;
$done = 0;
$txn = $con->auto_retry_txn(count => 2, on_completion => sub { $done++ }, action => sub { $calls++ });
is($calls, 1, "(\%params with action) form ran the action once");
is($done, 1, "(\%params with action) form passed params through to txn()");
$calls = 0;
$txn = $con->auto_retry_txn(2, sub { $calls++ });
is($calls, 1, "(\$count, sub) form ran the action once");
$calls = 0;
$txn = $con->auto_retry_txn(2, {action => sub { $calls++ }});
is($calls, 1, "(\$count, \\\%params) form ran the action once");
my $err = dies { $con->auto_retry_txn(2, \"nope") };
like($err, qr/Not sure what to do with second argument/, "bad second argument croaks");
};
{
package My::Test::FakeAsync;
sub new { my ($class, %p) = @_; return bless {%p}, $class }
sub done { $_[0]->{done} }
sub set_done { $_[0]->{done} = $_[1] }
}
subtest failed_commit_is_recoverable => sub {
my $con = connect_orm();
my $txn = $con->txn();
$con->handle('things')->insert({name => 'wedge'});
my $fake = My::Test::FakeAsync->new(done => 0);
$con->{in_async} = $fake;
my $err = dies { $txn->commit };
like($err, qr/Cannot stop a transaction while there is an active async query/, "commit during an active async query throws");
ok(!$txn->complete, "transaction is still open after the failed commit");
is(scalar(@{$con->transactions}), 1, "transaction is still on the stack");
$fake->set_done(1);
ok(lives { $txn->rollback }, "rollback still works after the async query completes") or diag $@;
ok($txn->complete, "transaction is complete after rollback");
ok($txn->rolled_back, "transaction rolled back");
is(scalar(@{$con->transactions}), 0, "transaction stack is clean");
ok(!$con->dialect->in_txn, "no transaction left open on the database");
my $dbh = DBI->connect($dsn, '', '', {RaiseError => 1, PrintError => 0});
my ($count) = $dbh->selectrow_array("SELECT COUNT(*) FROM things WHERE name = 'wedge'");
$dbh->disconnect;
is($count, 0, "the insert really was rolled back");
};
subtest on_parent_callbacks => sub {
my $con = connect_orm();
my %fired;
my $ok = eval {
$con->txn(
on_parent_fail => sub { $fired{parent_fail}++ },
on_parent_completion => sub { $fired{parent_completion}++ },
on_root_fail => sub { $fired{root_fail}++ },
on_root_completion => sub { $fired{root_completion}++ },
action => sub { die "boom\n" },
);
1;
};
ok(!$ok, "root transaction failed");
is(\%fired, {root_fail => 1, root_completion => 1}, "on_parent_* are no-ops without a parent, on_root_* fire on self");
%fired = ();
$con->txn(sub {
$con->txn(
on_parent_success => sub { $fired{parent_success}++ },
on_parent_completion => sub { $fired{parent_completion}++ },
action => sub { 1 },
);
is(\%fired, {}, "parent callbacks have not fired before the parent completes");
});
is(\%fired, {parent_success => 1, parent_completion => 1}, "on_parent_* attach to the real parent when nested");
};
subtest already_complete_croaks => sub {
my $con = connect_orm();
my $txn = $con->txn();
$txn->commit;
ok($txn->complete, "transaction completed");
my $err = dies { $txn->commit };
like($err, qr/Transaction is already complete/, "second commit croaks instead of 'Label not found'");
$err = dies { $txn->rollback };
like($err, qr/Transaction is already complete/, "rollback after completion croaks too");
};
subtest savepoint_metadata_survives_completion => sub {
my $con = connect_orm();
my $saw;
$con->txn(sub {
$con->txn(
on_completion => sub { my $t = shift; $saw = $t->is_savepoint },
action => sub { 1 },
);
});
is($saw, 1, "post-completion callbacks still see is_savepoint true for a savepoint txn");
};
done_testing;
( run in 1.520 second using v1.01-cache-2.11-cpan-140bd7fdf52 )