X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=t%2Fstorage%2Freconnect.t;h=199213b92d1b4fde7eed25b2032513d339bda113;hb=c0329273268971824784f239f32c7246e68da9c5;hp=b28734b3c93b4cf245339bb32858af3b6a38b7d5;hpb=a96c80eb706d3ccadf3b29d3f5a71a0e66b72170;p=dbsrgits%2FDBIx-Class.git diff --git a/t/storage/reconnect.t b/t/storage/reconnect.t index b28734b..199213b 100644 --- a/t/storage/reconnect.t +++ b/t/storage/reconnect.t @@ -1,11 +1,15 @@ +BEGIN { do "./t/lib/ANFANG.pm" or die ( $@ || $! ) } + use strict; use warnings; use FindBin; +use B::Deparse; use File::Copy 'move'; +use Scalar::Util 'weaken'; use Test::More; use Test::Exception; -use lib qw(t/lib); + use DBICTest; my $db_orig = DBICTest->_sqlite_dbfilename; @@ -14,8 +18,14 @@ my $db_tmp = "$db_orig.tmp"; # Set up the "usual" sqlite for DBICTest my $schema = DBICTest->init_schema( sqlite_use_file => 1 ); +my $exception_action_count; +$schema->exception_action(sub { + $exception_action_count++; + die @_; +}); + # Make sure we're connected by doing something -my @art = $schema->resultset("Artist")->search({ }, { order_by => 'name DESC'}); +my @art = $schema->resultset("Artist")->search({ }, { order_by => { -desc => 'name' }}); cmp_ok(@art, '==', 3, "Three artists returned"); # Disconnect the dbh, and be sneaky about it @@ -32,30 +42,28 @@ cmp_ok(@art, '==', 3, "Three artists returned"); # 2. It catches the exception, checks ->{Active}/->ping, sees the disconnected state... # 3. Reconnects, and retries the operation # 4. Success! -my @art_two = $schema->resultset("Artist")->search({ }, { order_by => 'name DESC'}); +my @art_two = $schema->resultset("Artist")->search({ }, { order_by => { -desc => 'name' }}); cmp_ok(@art_two, '==', 3, "Three artists returned"); ### Now, disconnect the dbh, and move the db file; -# create a new one and chmod 000 to prevent SQLite from connecting. +# create a new one full of garbage, prevent SQLite from connecting. $schema->storage->_dbh->disconnect; move( $db_orig, $db_tmp ) or die "failed to move $db_orig to $db_tmp: $!"; -open DBFILE, '>', $db_orig; -print DBFILE 'THIS IS NOT A REAL DATABASE'; -close DBFILE; -chmod 0000, $db_orig; +open my $db_file, '>', $db_orig; +print $db_file 'THIS IS NOT A REAL DATABASE'; +close $db_file; -### Try the operation again... it should fail, since there's no db +### Try the operation again... it should fail, since there's no valid db { - # Catch the DBI connection error - local $SIG{__WARN__} = sub {}; - dies_ok { - my @art_three = $schema->resultset("Artist")->search( {}, { order_by => 'name DESC' } ); - } 'The operation failed'; + # Catch the DBI connection error + local $SIG{__WARN__} = sub {}; + throws_ok { + $schema->resultset("Artist")->create({ name => 'not gonna happen' }); + } qr/not a database/, 'The operation failed'; } -# otherwise can't unlink the fake db file -$schema->storage->_dbh->disconnect if $^O eq 'MSWin32'; +ok (! $schema->storage->connected, 'We are not connected' ); ### Now, move the db file back to the correct name unlink($db_orig) or die "could not delete $db_orig: $!"; @@ -65,7 +73,7 @@ move( $db_tmp, $db_orig ) ### Try the operation again... this time, it should succeed my @art_four; lives_ok { - @art_four = $schema->resultset("Artist")->search( {}, { order_by => 'name DESC' } ); + @art_four = $schema->resultset("Artist")->search( {}, { order_by => { -desc => 'name' } } ); } 'The operation succeeded'; cmp_ok( @art_four, '==', 3, "Three artists returned" ); @@ -92,6 +100,8 @@ for my $ctx (keys %$ctx_map) { # start disconnected and then connected $schema->storage->disconnect; + $exception_action_count = 0; + for (1, 2) { my $disarmed; @@ -106,6 +116,86 @@ for my $ctx (keys %$ctx_map) { isa_ok ($schema->resultset('Artist')->next, 'DBICTest::Artist'); }, @$args) }); } + + is( $exception_action_count, 0, 'exception_action never called' ); }; +# make sure RT#110429 does not recur on manual DBI-side disconnect +for my $cref ( + sub { + my $schema = shift; + + my $g = $schema->txn_scope_guard; + + is( $schema->storage->transaction_depth, 1, "Expected txn depth" ); + + $schema->storage->_dbh->disconnect; + + $schema->storage->dbh_do(sub { $_[1]->do('SELECT 1') } ); + }, + sub { + my $schema = shift; + $schema->txn_do(sub { + $schema->storage->_dbh->disconnect + } ); + }, + sub { + my $schema = shift; + $schema->txn_do(sub { + $schema->storage->disconnect; + die "VIOLENCE"; + } ); + }, +) { + + note( "Testing with " . B::Deparse->new->coderef2text($cref) ); + + $schema->storage->disconnect; + $exception_action_count = 0; + + ok( !$schema->storage->connected, 'Not connected' ); + + is( $schema->storage->transaction_depth, undef, "Start with unknown txn depth" ); + + # messages vary depending on version and whether txn or do, whatever + dies_ok { + $cref->($schema) + } 'Threw *something*'; + + ok( !$schema->storage->connected, 'Not connected as a result of failed rollback' ); + + is( $schema->storage->transaction_depth, undef, "Depth expectedly unknown after failed rollbacks" ); + + is( $exception_action_count, 1, "exception_action called only once" ); +} + +# check exception_action under tenacious disconnect +{ + $schema->storage->disconnect; + $exception_action_count = 0; + + throws_ok { $schema->txn_do(sub { + $schema->storage->_dbh->disconnect; + + $schema->resultset('Artist')->next; + })} qr/prepare on inactive database handle/; + + is( $exception_action_count, 1, "exception_action called only once" ); +} + +# check that things aren't crazy with a non-violent disconnect +{ + my $schema = DBICTest->init_schema( sqlite_use_file => 0, no_deploy => 1 ); + weaken( my $ws = $schema ); + + $schema->is_executed_sql_bind( sub { + $ws->txn_do(sub { $ws->storage->disconnect } ); + }, [ [ 'BEGIN' ] ], 'Only one BEGIN statement' ); + + $schema->is_executed_sql_bind( sub { + my $g = $ws->txn_scope_guard; + $ws->storage->disconnect; + }, [ [ 'BEGIN' ] ], 'Only one BEGIN statement' ); +} + done_testing;