use warnings;
use lib qw(t/lib);
use Test::More;
+use Test::Exception;
use DBICTest;
BEGIN {
- eval "use Moose; use Test::Moose";
+ eval "use DBIx::Class::Storage::DBI::Replicated; use Test::Moose";
plan $@
- ? ( skip_all => 'needs Moose for testing' )
- : ( tests => 46 );
+ ? ( skip_all => "Deps not installed: $@" )
+ : ( tests => 79 );
}
use_ok 'DBIx::Class::Storage::DBI::Replicated::Pool';
## Get the Schema and set the replication storage type
sub init_schema {
+ # current SQLT SQLite producer does not handle DROP TABLE IF EXISTS, trap warnings here
+ local $SIG{__WARN__} = sub { warn @_ unless $_[0] =~ /no such table.+DROP TABLE/ };
+
my $class = shift @_;
-
+
my $schema = DBICTest->init_schema(
- storage_type=>[
+ sqlite_use_file => 1,
+ storage_type=>{
'::DBI::Replicated' => {
balancer_type=>'::Random',
+ balancer_args=>{
+ auto_validate_every=>100,
+ },
}
- ],
+ },
deploy_args=>{
add_drop_table => 1,
},
isa_ok $replicated->schema->storage->pool
=> 'DBIx::Class::Storage::DBI::Replicated::Pool';
-isa_ok $replicated->schema->storage->balancer
+does_ok $replicated->schema->storage->balancer
=> 'DBIx::Class::Storage::DBI::Replicated::Balancer';
ok my @replicant_connects = $replicated->generate_replicant_connect_info
ok $replicated->schema->storage->pool->has_replicants
=> 'does have replicants';
-is $replicated->schema->storage->num_replicants => 2
+is $replicated->schema->storage->pool->num_replicants => 2
=> 'has two replicants';
does_ok $replicated_storages[0]
## Make sure all the slaves have the table definitions
$replicated->replicate;
+$replicated->schema->storage->replicants->{$replicant_names[0]}->active(1);
+$replicated->schema->storage->replicants->{$replicant_names[1]}->active(1);
+$replicated->schema->storage->pool->validate_replicants;
## Make sure we can read the data.
[ 7, "Watergate"],
]);
-SKIP: {
- ## We can't do this test if we have a custom replicants, since we assume
- ## if there are custom one that you are trying to test a real replicating
- ## system. See docs above for more.
-
- skip 'Cannot test inconsistent replication since you have a real replication system', 1
- if DBICTest->has_custom_dsn && $ENV{"DBICTEST_SLAVE0_DSN"};
-
- ## Alright, the database 'cluster' is not in a consistent state. When we do
- ## a read now we expect bad news
- is $replicated->schema->resultset('Artist')->find(5), undef
- => 'read after disconnect fails because it uses a replicant which we have neglected to "replicate" yet';
-}
-
## Make sure all the slaves have the table definitions
$replicated->replicate;
=> 'Found expected name for first result';
is $replicated->schema->storage->pool->connected_replicants => 1
- => "One replicant reconnected to handle the job";
+ => "At Least One replicant reconnected to handle the job";
## What happens when we try to select something that doesn't exist?
$replicated->schema->storage->replicants->{$replicant_names[0]}->active(1);
$replicated->schema->storage->replicants->{$replicant_names[1]}->active(1);
+$replicated->schema->storage->pool->validate_replicants;
ok $replicated->schema->resultset('Artist')->find(2)
=> 'Returned to replicates';
## We skip this tests unless you have a custom replicants, since the default
## sqlite based replication tests don't support these functions.
- skip 'Cannot Test Replicant Status on Non Replicating Database', 3
+ skip 'Cannot Test Replicant Status on Non Replicating Database', 9
unless DBICTest->has_custom_dsn && $ENV{"DBICTEST_SLAVE0_DSN"};
$replicated->replicate; ## Give the slaves a chance to catchup.
is $replicated->schema->storage->pool->active_replicants, 2
=> 'Both replicants in good standing again';
+
+ ## Check auto validate
+
+ is $replicated->schema->storage->balancer->auto_validate_every, 100
+ => "Got the expected value for auto validate";
+
+ ## This will make sure we auto validatge everytime
+ $replicated->schema->storage->balancer->auto_validate_every(0);
+
+ ## set all the replicants to inactive, and make sure the balancer falls back to
+ ## the master.
+
+ $replicated->schema->storage->replicants->{$replicant_names[0]}->active(0);
+ $replicated->schema->storage->replicants->{$replicant_names[1]}->active(0);
+
+ ## Ok, now when we go to run a query, autovalidate SHOULD reconnect
+
+ is $replicated->schema->storage->pool->active_replicants => 0
+ => "both replicants turned off";
+
+ ok $replicated->schema->resultset('Artist')->find(5)
+ => 'replicant reactivated';
+
+ is $replicated->schema->storage->pool->active_replicants => 2
+ => "both replicants reactivated";
}
-## Delete the old database files
-$replicated->cleanup;
+## Test the reliably callback
+
+ok my $reliably = sub {
+
+ ok $replicated->schema->resultset('Artist')->find(5)
+ => 'replicant reactivated';
+
+} => 'created coderef properly';
+
+$replicated->schema->storage->execute_reliably($reliably);
+
+## Try something with an error
+
+ok my $unreliably = sub {
+
+ ok $replicated->schema->resultset('ArtistXX')->find(5)
+ => 'replicant reactivated';
+
+} => 'created coderef properly';
+
+throws_ok {$replicated->schema->storage->execute_reliably($unreliably)}
+ qr/Can't find source for ArtistXX/
+ => 'Bad coderef throws proper error';
+
+## Make sure replication came back
+ok $replicated->schema->resultset('Artist')->find(3)
+ => 'replicant reactivated';
+
+## make sure transactions are set to execute_reliably
+ok my $transaction = sub {
+
+ my $id = shift @_;
+
+ $replicated
+ ->schema
+ ->populate('Artist', [
+ [ qw/artistid name/ ],
+ [ $id, "Children of the Grave"],
+ ]);
+
+ ok my $result = $replicated->schema->resultset('Artist')->find($id)
+ => 'Found expected artist';
+
+ ok my $more = $replicated->schema->resultset('Artist')->find(1)
+ => 'Found expected artist again';
+
+ return ($result, $more);
+
+} => 'Created a coderef properly';
+## Test the transaction with multi return
+{
+ ok my @return = $replicated->schema->txn_do($transaction, 666)
+ => 'did transaction';
+
+ is $return[0]->id, 666
+ => 'first returned value is correct';
+
+ is $return[1]->id, 1
+ => 'second returned value is correct';
+}
+
+## Test that asking for single return works
+{
+ ok my $return = $replicated->schema->txn_do($transaction, 777)
+ => 'did transaction';
+
+ is $return->id, 777
+ => 'first returned value is correct';
+}
+## Test transaction returning a single value
+
+{
+ ok my $result = $replicated->schema->txn_do(sub {
+ ok my $more = $replicated->schema->resultset('Artist')->find(1)
+ => 'found inside a transaction';
+ return $more;
+ }) => 'successfully processed transaction';
+
+ is $result->id, 1
+ => 'Got expected single result from transaction';
+}
+## Make sure replication came back
+ok $replicated->schema->resultset('Artist')->find(1)
+ => 'replicant reactivated';
+
+## Test Discard changes
+
+{
+ ok my $artist = $replicated->schema->resultset('Artist')->find(2)
+ => 'got an artist to test discard changes';
+
+ ok $artist->discard_changes
+ => 'properly discard changes';
+}
+
+## Test some edge cases, like trying to do a transaction inside a transaction, etc
+
+{
+ ok my $result = $replicated->schema->txn_do(sub {
+ return $replicated->schema->txn_do(sub {
+ ok my $more = $replicated->schema->resultset('Artist')->find(1)
+ => 'found inside a transaction inside a transaction';
+ return $more;
+ });
+ }) => 'successfully processed transaction';
+
+ is $result->id, 1
+ => 'Got expected single result from transaction';
+}
+
+{
+ ok my $result = $replicated->schema->txn_do(sub {
+ return $replicated->schema->storage->execute_reliably(sub {
+ return $replicated->schema->txn_do(sub {
+ return $replicated->schema->storage->execute_reliably(sub {
+ ok my $more = $replicated->schema->resultset('Artist')->find(1)
+ => 'found inside crazy deep transactions and execute_reliably';
+ return $more;
+ });
+ });
+ });
+ }) => 'successfully processed transaction';
+
+ is $result->id, 1
+ => 'Got expected single result from transaction';
+}
+
+## Test the force_pool resultset attribute.
+
+{
+ ok my $artist_rs = $replicated->schema->resultset('Artist')
+ => 'got artist resultset';
+
+ ## Turn on Forced Pool Storage
+ ok my $reliable_artist_rs = $artist_rs->search(undef, {force_pool=>'master'})
+ => 'Created a resultset using force_pool storage';
+
+ ok my $artist = $reliable_artist_rs->find(2)
+ => 'got an artist result via force_pool storage';
+}
+
+## Delete the old database files
+$replicated->cleanup;