...
 
Commits (12)
Revision history for Perl extension DBD::Mock.
1.42
- Fixed bug rt66815 DBD::Mock::Session error clobbered
- Fixed bug rt69460 Info on META.yml is outdated
- Fixed bug rt69055 Spelling mistakes in POD
- RaiseError now works
1.41 June 22, 2011
- Changed incorrect verion number
1.40 June 19, 2011
- Fixed bug rt44591 second preapre giving an error
- Fixed bug rt57981 warnings during clone
- Fixed bug rt63191 Synopsis errors
- Fixed bug rt66813 Google's group link in the POD
1.39 November 9, 2008
- If a statement handle had bound columns, then the fetch() and
fetchrow_arrayref() methods never returned false. After they
......
This diff is collapsed.
......@@ -96,6 +96,7 @@ use DBI;
eval {
Login::Test::login($dbh, 'user', '****')
};
ok($@, '... got the exception');
like($@, qr/Session Error\: Session states exhausted/, '... got the exception we expected');
......
#!/usr/bin/perl
use Test::More tests => 15;
use strict;
use warnings;
use Test::Exception;
use DBI;
use DBD::Mock;
# This test is designed to expose the bug found in the DBD::Mock
# methods begin_work, commit and rollback (RT #66815), where a failing
# ->prepare invocation (returning nothing) is not detected and the
# undefined value resulting is used anyway. In this test, as in the
# example found in the wild, the failure is triggered by exhaustion of
# the session states.
#
# This is a list of sessions designed to engineer the right condition
# to trigger the bug. They all start with a dummy statement (so that
# there are at least two states) then the final statement is removed
# before it is passed to DBD::Mock::Session->new (which requires at
# least one state). The final statements are 'BEGIN WORK', 'COMMIT'
# and 'ROLLBACK', respectively.
#
# Hence, when the test tries to invoke the final state, the session
# will have run out and DBD::Mock->verify_statement will cause the
# prepare method to fail.
my @cases = (
'begin_work' => [
{
statement => 'SELECT something FROM somewhere',
results => [],
},
{
statement => 'BEGIN WORK',
results => [],
},
],
'commit' => [
{
statement => 'SELECT something FROM somewhere',
results => [],
},
{
statement => 'BEGIN WORK',
results => [],
},
{
statement => 'INSERT INTO foo (bar) VALUES (?);',
results => [],
bound_params => [1],
},
{
statement => 'COMMIT',
results => [],
},
],
'rollback' => [
{
statement => 'SELECT something FROM somewhere',
results => [],
},
{
statement => 'BEGIN WORK',
results => [],
},
{
statement => 'INSERT INTO foo (bar) VALUES (?);',
results => [],
bound_params => [1],
},
{
statement => 'ROLLBACK',
results => [],
},
],
);
while(@cases) {
my ($name, $states) = splice @cases, 0, 2;
my $case_name = "case $name";
my $dbh = DBI->connect('dbi:Mock:', '', '',
{ PrintError => 0,
RaiseError => 1 });
# Add all but the last state of the expected session
my $missing_state = pop @$states;
my $num_states = @$states;
$dbh->{mock_session} = DBD::Mock::Session->new($name => @$states);
# Execute the initial dummy statement.
my $state = $states->[0];
my $sth = $dbh->prepare($state->{statement});
ok $sth,
"$case_name: prepare statement";
ok $sth->execute(),
"$case_name: execute statement";
# Now try and do the next steps in @session, but using the
# appropriate transaction methods directly. This should fail when
# the session is exhausted with a useful message. (The original
# bug meant that the message got clobbered by "Can't call method
# 'execute' on an undefined value".)
throws_ok {
# This stlibatement is always the same.
ok $dbh->begin_work,
"$case_name: start transaction";
my $state = $states->[2];
my $sth = $dbh->prepare($state->{statement});
ok $sth,
"$case_name: prepare statement";
ok $sth->execute(@{$state->{bound_params}}),
"$case_name: execute statement";
# get the final operation from the session
my $operation = lc $missing_state->{statement};
ok $dbh->$operation,
"$case_name: $operation transaction";
} qr/\QSession states exhausted, only '$num_states' in DBD::Mock::Session\E/;
}
#!/usr/bin/perl
use Test::More tests => 3;
use strict;
use warnings;
use Test::Exception;
use DBI;
use DBD::Mock;
# This tests that spurious extra ->execute invocations fail with a
# useful message. This is because there was a bug in which
# DBD::Mock->verify_bound_params didn't check that the session had run
# out, and on return out-of-bounds element of the state array is
# accessed, causing an unhelpful error "Can't use an undefined value
# as an ARRAY reference at ../lib/DBD/Mock.pm line 635."
my @session = (
{
'statement' => 'INSERT INTO foo (bar) values (?);',
'results' => [],
'bound_params' => [1]
},
);
my $dbh = DBI->connect('dbi:Mock:', '', '', { PrintError => 0, RaiseError => 1});
# Add just part of the expected session, such that the next step would be a 'BEGIN WORK'
$dbh->{mock_session} = DBD::Mock::Session->new(@session);
# now execute the steps in the session
my $step = $session[0];
my $sth = $dbh->prepare($step->{statement});
ok $sth,
"prepare statement";
my $params = $step->{bound_params} || [];
ok $sth->execute(@$params),
"execute statement";
# Session expects that to be all. So let's surprise it with another
# ->execute. It should fail appropriately.
throws_ok {
ok $sth->execute(@$params),
} qr/\QSession states exhausted, only '1' in DBD::Mock::Session\E/,
"fails on executing one too many times";