use Test::More;
use Test::Exception;
use DBICTest;
+use List::Util 'first';
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 => 71 );
+ ? ( skip_all => "Deps not installed: $@" )
+ : ( tests => 82 );
}
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(
+ sqlite_use_file => 1,
storage_type=>{
'::DBI::Replicated' => {
balancer_type=>'::Random',
"dbi:SQLite:${_}";
} @{$self->slave_paths};
- return map { [$_,'','',{AutoCommit=>1}] } @dsn;
+ my @connect_infos = map { [$_,'','',{AutoCommit=>1}] } @dsn;
+
+ # try a hashref too
+ my $c = $connect_infos[0];
+ $connect_infos[0] = {
+ dsn => $c->[0],
+ user => $c->[1],
+ password => $c->[2],
+ %{ $c->[3] }
+ };
+
+ @connect_infos
}
-
+
## Do a 'good enough' replication by copying the master dbfile over each of
## the slave dbfiles. If the master is SQLite we do this, otherwise we
## just do a one second pause to let the slaves catch up.
ok my @replicated_storages = $replicated->schema->storage->connect_replicants(@replicant_connects)
=> 'Created some storages suitable for replicants';
-
+
+ok my @all_storages = $replicated->schema->storage->all_storages
+ => '->all_storages';
+
+ok @all_storages == 3
+ => 'correct number of ->all_storages';
+
+ok ((grep $_->isa('DBIx::Class::Storage::DBI'), @all_storages) == 3
+ => '->all_storages are correct type');
+
+my @replicant_names = keys %{ $replicated->schema->storage->replicants };
+
+## Silence warning about not supporting the is_replicating method if using the
+## sqlite dbs.
+$replicated->schema->storage->debugobj->silence(1)
+ if first { m{^t/} } @replicant_names;
+
isa_ok $replicated->schema->storage->balancer->current_replicant
- => 'DBIx::Class::Storage::DBI';
-
+ => 'DBIx::Class::Storage::DBI';
+
+$replicated->schema->storage->debugobj->silence(0);
+
ok $replicated->schema->storage->pool->has_replicants
=> 'does have replicants';
does_ok $replicated_storages[1]
=> 'DBIx::Class::Storage::DBI::Replicated::Replicant';
-my @replicant_names = keys %{$replicated->schema->storage->replicants};
-
does_ok $replicated->schema->storage->replicants->{$replicant_names[0]}
=> 'DBIx::Class::Storage::DBI::Replicated::Replicant';
## 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);
+
+## Silence warning about not supporting the is_replicating method if using the
+## sqlite dbs.
+$replicated->schema->storage->debugobj->silence(1)
+ if first { m{^t/} } @replicant_names;
+
+$replicated->schema->storage->pool->validate_replicants;
+
+$replicated->schema->storage->debugobj->silence(0);
## 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(0);
$replicated->schema->storage->replicants->{$replicant_names[1]}->active(0);
-
+
+## Silence warning about falling back to master.
+$replicated->schema->storage->debugobj->silence(1);
+
ok $replicated->schema->resultset('Artist')->find(2)
=> 'Fallback to master';
+$replicated->schema->storage->debugobj->silence(0);
+
$replicated->schema->storage->replicants->{$replicant_names[0]}->active(1);
$replicated->schema->storage->replicants->{$replicant_names[1]}->active(1);
+## Silence warning about not supporting the is_replicating method if using the
+## sqlite dbs.
+$replicated->schema->storage->debugobj->silence(1)
+ if first { m{^t/} } @replicant_names;
+
+$replicated->schema->storage->pool->validate_replicants;
+
+$replicated->schema->storage->debugobj->silence(0);
+
ok $replicated->schema->resultset('Artist')->find(2)
=> 'Returned to replicates';
[ $id, "Children of the Grave"],
]);
- ok my $result = $replicated->schema->resultset('Artist')->find($id);
- ok my $more = $replicated->schema->resultset('Artist')->find(1);
-
+ 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 $result = $replicated->schema->txn_do(sub {
- ok my $more = $replicated->schema->resultset('Artist')->find(1);
+ ok my $more = $replicated->schema->resultset('Artist')->find(1)
+ => 'found inside a transaction';
return $more;
}) => 'successfully processed transaction';
ok $artist->discard_changes
=> 'properly discard changes';
}
-
-## Delete the old database files
-$replicated->cleanup;
-
+## 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;