Test-Dynamic
view release on metacpan or search on metacpan
t/bucardo.testfile view on Meta::CPAN
if ($type ne 'master') {
$dbh->do("SET client_min_messages = 'warning'");
$dbh->do("CREATE SCHEMA $TEST_SCHEMA") unless $ENV{BUCARDO_TEST_NOCREATEDB};
$dbh->do("SET search_path = $TEST_SCHEMA");
$dbh->do("ALTER USER $testuser SET search_path = $TEST_SCHEMA");
}
$dbh->commit();
return $dbh;
} ## end of setup_database
sub shutdown_bucardo {
my $STOPFILE = "$PIDDIR/fullstopbucardo";
open my $stop, '>', $STOPFILE or die qq{Could not create "$STOPFILE": $!\n};
print {$stop} "Stopped by $0 on " . (scalar localtime) . "\n";
close $stop or warn qq{Could not close "$STOPFILE": $!\n};
pass(" Existing Bucardo asked to shut down");
## Find a grep we can use.
my $grep_path = $ENV{GREP_PATH} ||
qx!which grep! ||
qx!whereis -b grep!;
if (defined $grep_path) {
$grep_path =~ s!\Agrep: /!!;
$grep_path =~ s!\n\z!!;
}
else {
for my $path (grep { -x } qw!/bin/grep /usr/bin/grep /usr/local/bin/grep!) {
$grep_path = $path;
last;
}
}
BAIL_OUT q!Cannot find a usable "grep"; set GREP_PATH!
unless -x $grep_path;
my $loop = 1;
{
my $res = qx{/bin/ps -Afwww | $grep_path Bucardo | $grep_path $xname | $grep_path -v grep}; ## no critic
last if $res !~ /Bucardo/m;
if ($loop++ > 10) {
BAIL_OUT "Could not persuade existing Bucardo to shut down\n";
}
sleep 1;
redo;
}
return;
} ## end of shutdown_bucardo
sub wait_until_true {
my $xline = (caller)[2];
my $dbh = shift or die "Need a database handle (from line $xline)\n";
my $sql = shift or die "Need a SQL statement (from line $xline)\n";
my $timeout = shift || $TIMEOUT_SYNCWAIT;
my $sleep = shift || $TIMEOUT_SLEEP;
my $type = shift || 'true';
my $line = shift || $xline;
alarm $timeout;
$sth = $dbh->prepare($sql);
eval {
W: {
$count = $sth->execute();
$sth->finish();
$dbh->commit();
last if ($type eq 'true' and $count >= 1) or ($type eq 'false' and $count < 1);
sleep $sleep;
redo;
}
};
$count = alarm 0;
return $count unless $@;
my $db = $dbmap{$dbh} || '?';
BAIL_OUT (qq{Gave up waiting for "$sql" on db "$db" to be $type: timed out at $timeout from line $line ($@)});
return;
} ## end of wait_until_true
sub wait_until_false {
my $xline = (caller)[2];
my $dbh = shift or die "Need a database handle (from line $xline)\n";
my $sql = shift or die "Need a SQL statement (from line $xline)\n";
my $timeout = shift || $TIMEOUT_SYNCWAIT;
my $sleep = shift || $TIMEOUT_SLEEP;
return wait_until_true($dbh,$sql,$timeout,$sleep,'false',$xline);
} ## end of wait_until_false
sub clean_all_tables {
## Reset out test databases to their original state
## Empty out all data from the tables
## Remove any triggers added
## Drop the helper bucardo schema
$masterdbh->rollback();
$masterdbh->do("DELETE FROM sync"); ## Needs to go first due to trigger tek
for my $dbh ($dbh1,$dbh2,$dbh3) {
$dbh->rollback();
for my $table (sort keys %tabletype) {
$dbh->do("TRUNCATE TABLE $table");
$SQL = "SELECT tgname FROM pg_trigger WHERE tgrelid = (SELECT oid FROM pg_class WHERE relname = '$table')";
for (@{$dbh->selectall_arrayref($SQL)}) {
next if $_->[0] =~ /^bctrig_/o;
$dbh->do("DROP TRIGGER $_->[0] ON $table");
}
}
## Nuke the entire bucardo schema if it exists
if (object_count($dbh,'bucardo','schema','')) {
$dbh->do("DROP SCHEMA bucardo CASCADE");
}
$dbh->do("TRUNCATE TABLE droptest");
$dbh->commit();
}
$masterdbh->do("DELETE FROM q");
$masterdbh->do("DELETE FROM audit_pid");
$masterdbh->commit();
pass(" Finished clean_all_tables");
return;
} ## end of clean_all_tables
sub clean_swap_table {
## Empty out swap table and associated tables on one or more databases
my ($table,$dbs) = @_;
for my $dbh (@{$dbs}) {
$dbh->rollback;
}
for my $dbh (@{$dbs}) {
my $oid = $table{$dbh}{$table};
$dbh->do("DELETE FROM $table");
$dbh->do("DELETE FROM bucardo.bucardo_track WHERE tablename = $oid");
$dbh->do("DELETE FROM bucardo.bucardo_delta WHERE tablename = $oid");
$dbh->do("DELETE FROM bucardo.bucardo_track");
$dbh->do("DELETE FROM bucardo.bucardo_delta");
$dbh->commit;
}
return;
t/bucardo.testfile view on Meta::CPAN
if (!$@) {
## diag "End bucardo_ctl with $command\n";
return $count;
}
if ($@ =~ /Timed out/) {
system("touch $PIDDIR/fullstopbucardo");
BAIL_OUT("bucardo_ctl was not invoked: is the bucardo.test.helper file running? (command=$command)");
}
BAIL_OUT("bucardo_ctl gave an error: $@");
return;
} ## end of bucardo_ctl
sub wait4kid {
my $notice = shift;
my $timeout = shift || $ALARM_WAIT4KID;
$SQL = "SELECT 1 FROM pg_catalog.pg_listener WHERE relname = ?";
my $listen = $masterdbh->prepare($SQL);
alarm $timeout;
eval {
S: {
$count = $listen->execute($notice);
$listen->finish();
last if $count == 1;
sleep 0.1;
redo;
}
};
$count = alarm 0;
return $count unless $@;
BAIL_OUT("Waited too long ($timeout) for kid to LISTEN to $notice");
return;
} ## end of wait4kid
sub wait_for_notice {
my $dbh = shift;
my $text = shift;
my $timeout = shift || $TIMEOUT_NOTICE;
my $sleep = shift || $TIMEOUT_SLEEP;
my $n;
alarm $timeout;
eval {
N: {
while ($n = $dbh->func('pg_notifies')) {
last N if $n->[0] eq $text;
}
sleep $sleep;
redo;
}
};
$count = alarm 0;
return $count unless $@;
my $line = (caller)[2];
BAIL_OUT (qq{Gave up waiting for notice "$text": timed out at $timeout from line $line ($@)});
return;
} ## end of wait_for_notice
## no critic
{
no warnings; ## Yes, we know they are being redefined!
sub is_deeply {
t($_[2],$_[3] || (caller)[2]);
return if Test::More::is_deeply($_[0],$_[1],$testmsg);
if ($bail_on_error > $total_errors++) {
my $line = (caller)[2];
my $time = time;
diag("GOT: ".Dumper $_[0]);
diag("EXPECTED: ". Dumper $_[1]);
BAIL_OUT "Stopping on a failed 'is_deeply' test from line $line. Time: $time";
}
} ## end of is_deeply
sub like {
t($_[2],(caller)[2]);
return if Test::More::like($_[0],$_[1],$testmsg);
if ($bail_on_error > $total_errors++) {
my $line = (caller)[2];
my $time = time;
BAIL_OUT "Stopping on a failed 'like' test from line $line. Time: $time";
}
} ## end of like
sub pass {
t($_[0],$_[1]||(caller)[2]);
Test::More::pass($testmsg);
} ## end of pass
sub is {
t($_[2],(caller)[2]);
return if Test::More::is($_[0],$_[1],$testmsg);
if ($bail_on_error > $total_errors++) {
my $line = (caller)[2];
my $time = time;
BAIL_OUT "Stopping on a failed 'is' test from line $line. Time: $time";
}
} ## end of is
sub isa_ok {
t("Object isa $_[1]",(caller)[2]);
my ($name, $type, $msg) = ($_[0],$_[1]);
if (ref $name and ref $name eq $type) {
Test::More::pass($testmsg);
return;
}
$bail_on_error > $total_errors++ and BAIL_OUT "Stopping on a failed test";
} ## end of isa_ok
sub ok {
t($_[1]||$testmsg);
return if Test::More::ok($_[0],$testmsg);
if ($bail_on_error > $total_errors++) {
my $line = (caller)[2];
my $time = time;
BAIL_OUT "Stopping on a failed 'ok' test from line $line. Time: $time";
}
} ## end of ok
}
## use critic
sub now_time {
my $dbh = shift;
return $dbh->selectall_arrayref("SELECT now()")->[0][0];
} ## end of now_time
sub bc_deeply {
my ($exp,$dbh,$sql,$msg) = @_;
my $line = (caller)[2];
local $Data::Dumper::Terse = 1;
local $Data::Dumper::Indent = 0;
die "Very invalid statement from line $line: $sql\n" if $sql !~ /^\s*select/i;
my $got;
eval {
$got = $dbh->selectall_arrayref($sql);
};
if ($@) {
die "bc_deeply failed from line $line. SQL=$sql\n";
}
return is_deeply($got,$exp,$msg,(caller)[2]);
} ## end of bc_deeply
sub compare_tables {
my ($table,$sdbh,$rdbh) = @_;
my ($line) = (caller)[2];
local $Data::Dumper::Terse = 1;
local $Data::Dumper::Indent = 0;
my $msg = "Table $table is the same on both databases";
$SQL = "SELECT * FROM $table ORDER BY inty, id";
$SQL =~ s/inty, // if $table =~ /0/;
my $uno = $sdbh->selectall_arrayref($SQL);
my $dos = $rdbh->selectall_arrayref($SQL);
if ((Dumper $uno) eq (Dumper $dos)) {
pass($msg,$line);
return 1;
}
return is_deeply($uno,$dos,$msg,$line);
} ## end of compare_tables
sub tt {
## Simple timing routine. Call twice with the same arg, before and after
my $name = shift or die qq{Need a name!\n};
if (exists $timing{$name}) {
my $newtime = tv_interval($timing{$name});
warn "Timing for $name: $newtime\n";
delete $timing{$name};
}
else {
$timing{$name} = [gettimeofday];
}
return;
} ## end of tt
sub t {
$testmsg = shift;
$testline = shift || (caller)[2];
$testmsg =~ s/^\s+//;
if ($location) {
$testmsg = "($location) $testmsg";
}
if ($showline) {
$testmsg .= " [line: $testline]";
}
if ($showtime) {
my $time = time;
$testmsg .= " [time: $time]";
}
} ## end of t
sub exitnow {
$need_shutdown = 0;
exit;
} ## end of exitnow
sub test_customcode_methods {
## Test methods related to custom code: customcode, remove_customcode
$location = 'customcode_methods';
my ($code, $codeid);
$t=q{ Method customcode fails if no arguments are given };
eval { $bc->customcode(); };
like($@, qr{must be a hashref}, $t);
$t=q{ Method customcode fails if no 'src_code' argument given };
eval { $bc->customcode({name => 'test'}); };
like($@, qr{\QAttribute (src_code) is required}, $t);
$t=q{ Method customcode fails if no 'name' argument given };
eval { $bc->customcode({src_code => 'foo'}); };
like($@, qr{\QAttribute (name) is required}, $t);
$t=q{ Method customcode fails if no 'whenrun' argument given };
eval { $bc->customcode({name => 'test', src_code => 'foo'}); };
like($@, qr{\QAttribute (whenrun) is required}, $t);
$t=q{ Method customcode fails if 'whenrun' is invalid };
eval { $bc->customcode({name => 'test', src_code => 'foo', whenrun => 'invalid'}); };
like($@, qr{violates check constraint "customcode_whenrun"}, $t);
$t=q{ Method customcode works if given valid arguments };
eval { $code = $bc->customcode({name => 'test', src_code => 'foo', whenrun => 'before_txn'}); };
is($@, q{}, $t);
$t=q{ Method customcode returns a hashref };
is(ref $code, 'HASH', $t);
$t=q{ Method customcode returns a hashref containing a numeric 'id' key };
$codeid = $code->{id} || 0;
like($codeid, qr{^\d$}, $t);
( run in 2.113 seconds using v1.01-cache-2.11-cpan-cdf2f3d4e48 )