Files
percona-toolkit/t/pt-table-checksum/bugs.t
2012-10-17 15:39:06 -03:00

396 lines
13 KiB
Perl

#!/usr/bin/env perl
BEGIN {
die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n"
unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH};
unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib";
};
use strict;
use warnings FATAL => 'all';
use English qw(-no_match_vars);
use Test::More;
# Hostnames make testing less accurate. Tests need to see
# that such-and-such happened on specific slave hosts, but
# the sandbox servers are all on one host so all slaves have
# the same hostname.
$ENV{PERCONA_TOOLKIT_TEST_USE_DSN_NAMES} = 1;
use Data::Dumper;
use PerconaTest;
use Sandbox;
# Fix @INC because pt-table-checksum uses subclass OobNibbleIterator.
shift @INC; # our unshift (above)
shift @INC; # PerconaTest's unshift
require "$trunk/bin/pt-table-checksum";
my $dp = new DSNParser(opts=>$dsn_opts);
my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp);
my $master_dbh = $sb->get_dbh_for('master');
my $slave1_dbh = $sb->get_dbh_for('slave1');
my $slave2_dbh = $sb->get_dbh_for('slave2');
if ( !$master_dbh ) {
plan skip_all => 'Cannot connect to sandbox master';
}
elsif ( !$slave1_dbh ) {
plan skip_all => 'Cannot connect to sandbox slave1';
}
elsif ( !$slave2_dbh ) {
plan skip_all => 'Cannot connect to sandbox slave2';
}
# The sandbox servers run with lock_wait_timeout=3 and it's not dynamic
# so we need to specify --lock-wait-timeout=3 else the tool will die.
my $master_dsn = 'h=127.1,P=12345,u=msandbox,p=msandbox';
my @args = ($master_dsn, qw(--lock-wait-timeout 3));
my $output;
my $exit_status;
my $sample = "t/pt-table-checksum/samples/";
# ############################################################################
# https://bugs.launchpad.net/percona-toolkit/+bug/995274
# Can't use an undefined value as an ARRAY reference at pt-table-checksum
# line 2206
# ############################################################################
$sb->load_file('master', "$sample/undef-arrayref-bug-995274.sql");
# Must chunk the table so an index is used.
$output = output(
sub { $exit_status = pt_table_checksum::main(@args,
qw(-d test --chunk-size 100)) },
stderr => 1,
);
is(
$exit_status,
0,
"Bug 995274 (undef array): zero exit status"
) or diag($output);
cmp_ok(
PerconaTest::count_checksum_results($output, 'rows'),
'>',
1,
"Bug 995274 (undef array): checksummed rows"
);
# #############################################################################
# https://bugs.launchpad.net/percona-toolkit/+bug/987393
# Empy tables cause "undefined value as an ARRAY" errors
# #############################################################################
$master_dbh->do("DROP DATABASE IF EXISTS percona"); # clear old checksums
$sb->load_file('master', "$sample/empty-table-bug-987393.sql");
$output = output(
sub { $exit_status = pt_table_checksum::main(
@args, qw(-d test --chunk-size-limit 0)) },
stderr => 1,
);
is(
$exit_status,
0,
"Bug 987393 (empty table): zero exit status"
);
is(
PerconaTest::count_checksum_results($output, 'errors'),
0,
"Bug 987393 (empty table): no errors"
);
my $rows = $master_dbh->selectall_arrayref("SELECT db, tbl, chunk, master_crc, master_cnt FROM percona.checksums ORDER BY db, tbl, chunk");
is_deeply(
$rows,
[
['test', 'test_empty', '1', '0', '0'], # empty
['test', 'test_full', '1', 'ac967054', '1'], # row
],
"Bug 987393 (empty table): checksums"
) or print STDERR Dumper($rows);
# #############################################################################
# https://bugs.launchpad.net/percona-toolkit/+bug/919499
# MySQL error 1592 with MySQL 5.5.18+ and Perl 5.8
# #############################################################################
$output = output(
sub {
print `$trunk/bin/pt-table-checksum $master_dsn -t sakila.country 2>&1`;
}
);
is(
PerconaTest::count_checksum_results($output, 'errors'),
0,
"Bug 987393 (Perl 5.8 scoping): no errors"
);
is(
PerconaTest::count_checksum_results($output, 'rows'),
109,
"Bug 987393 (Perl 5.8 scoping): checksummed table"
);
# #############################################################################
# https://bugs.launchpad.net/percona-toolkit/+bug/1030031
# pt-table-checksum reports wrong number of DIFFS
# #############################################################################
$sb->load_file('master', "$sample/a-z.sql");
$sb->wait_for_slaves();
# Create 2 diffs on slave1 and 1 diff on slave2.
$slave1_dbh->do("UPDATE test.t SET c='' WHERE id=5"); # diff on slave1 & 2
$slave1_dbh->do("SET SQL_LOG_BIN=0");
$slave1_dbh->do("UPDATE test.t SET c='' WHERE id=20"); # diff only on slave1
# Restore sql_log_bin on slave1 in case later tests use it.
$slave1_dbh->do("SET SQL_LOG_BIN=1");
$output = output(
sub { pt_table_checksum::main(@args, qw(-t test.t --chunk-size 10)) },
);
is(
PerconaTest::count_checksum_results($output, 'diffs'),
2,
"Bug 1030031 (wrong DIFFS): 2 diffs"
);
# Restore slave2, but then give it 1 diff that's not the same chunk#
# as slave1, so there's 3 unique chunk that differ.
$slave2_dbh->do("UPDATE test.t SET c='e' WHERE id=5");
$slave2_dbh->do("UPDATE test.t SET c='' WHERE id=26");
$output = output(
sub { pt_table_checksum::main(@args, qw(-t test.t --chunk-size 10)) },
);
is(
PerconaTest::count_checksum_results($output, 'diffs'),
3,
"Bug 1030031 (wrong DIFFS): 3 diffs"
);
# #############################################################################
# pt-table-checksum can crash with --columns if none match
# https://bugs.launchpad.net/percona-toolkit/+bug/1016131
# #############################################################################
($output) = full_output(
sub { pt_table_checksum::main(@args, '--tables', 'mysql.user,mysql.host',
'--columns', 'some_fale_column') },
);
like(
$output,
qr/\QSkipping table mysql.user because all columns are excluded by --columns or --ignore-columns/,
"Bug 1016131: ptc should skip tables where all columns are excluded"
);
# #############################################################################
# pt-table-checksum v2.1.4 doesn't detect diffs on Percona XtraDB Cluster nodes
# https://bugs.launchpad.net/percona-toolkit/+bug/1062563
# #############################################################################
use File::Spec::Functions;
my $db_flavor = VersionParser->new($master_dbh)->flavor();
SKIP: {
skip "PXC-only tests", 8
unless $db_flavor =~ /XtraDB Cluster/;
diag("Creating a 5-node PXC cluster...");
my @nodes = $sb->start_cluster(cluster_size => 5);
diag("Nodes: ", Dumper( { map { $_ => $sb->port_for($_) } @nodes } ));
my $node2 = $nodes[1];
my $node2_dbh = $sb->get_dbh_for($node2);
my $node2_slave = "master3";
diag("Creating a slave for $node2...");
{
local $ENV{BINLOG_FORMAT} = 'ROW';
diag($sb->start_sandbox("slave", $node2_slave, $node2));
}
my $node_slave_dbh = $sb->get_dbh_for($node2_slave);
make_dbh_differ($node2_dbh);
# And make its slave differ as well
PerconaTest::wait_for_table($sb->get_dbh_for($nodes[-1]), "bug_1062563.ptc_pxc");
PerconaTest::wait_for_table($node_slave_dbh, "bug_1062563.ptc_pxc");
$node_slave_dbh->do("INSERT INTO bug_1062563.ptc_pxc (i) VALUES ($_)") for 3, 4;
my $dsns_table_sql = catfile(qw(t lib samples MasterSlave dsn_table.sql));
$sb->load_file($node2, $dsns_table_sql, undef, no_wait => 1);
$node2_dbh->do("DELETE FROM dsn_t.dsns"); # Delete 12346
my $sth = $node2_dbh->prepare("INSERT INTO dsn_t.dsns VALUES (null, null, ?)");
for my $dsn ( map { $sb->dsn_for($_) } @nodes[0,2..$#nodes], $node2_slave ) {
$sth->execute($dsn);
}
my $node2_dsn = $sb->dsn_for($node2);
$output = output(
sub { pt_table_checksum::main(
$node2_dsn, qw(--lock-wait-timeout 3),
qw(-d bug_1062563),
'--recursion-method', "dsn=D=dsn_t,t=dsns"
) },
stderr => 1,
);
is(
PerconaTest::count_checksum_results($output, 'diffs'),
1,
"Bug 1062563: Detects diffs between PXC nodes"
) or diag($output);
my @cluster_nodes = $output =~ /(because it is a cluster node)/g;
is(
scalar(@cluster_nodes),
4,
"Skips all the cluster nodes in the dsns table"
) or diag($output);
# Now try with just the slave
$node2_dbh->do("DELETE FROM dsn_t.dsns");
$sth->execute($sb->dsn_for($node2_slave));
$output = output(
sub { pt_table_checksum::main(
$node2_dsn, qw(--lock-wait-timeout 3),
qw(--chunk-size 1),
qw(-d bug_1062563),
'--recursion-method', "dsn=D=dsn_t,t=dsns"
) },
stderr => 1,
);
is(
PerconaTest::count_checksum_results($output, 'diffs'),
1,
"Bug 1062563: Detects diffs on slaves where the master is a PXC node"
) or diag($output);
$sth->finish();
diag("Stopping the PXC cluster and the slave...");
$sb->stop_sandbox($node2_slave, @nodes);
# Now checking that cluster -> cluster works
diag("Creating two 3-node clusters...");
my @cluster1 = $sb->start_cluster(cluster_size => 3, cluster_name => "pt_test_cluster_1");
my @cluster2 = $sb->start_cluster(cluster_size => 3, cluster_name => "pt_test_cluster_2");
diag("Cluster 1: ", Dumper( { map { $_ => $sb->port_for($_) } @cluster1 } ));
diag("Cluster 2: ", Dumper( { map { $_ => $sb->port_for($_) } @cluster2 } ));
$sb->set_as_slave($cluster2[0], $cluster1[0]);
my $cluster1_dbh = $sb->get_dbh_for($cluster1[0]);
my $cluster2_dbh = $sb->get_dbh_for($cluster2[0]);
make_dbh_differ($cluster1_dbh);
# And make its slave differ as well
PerconaTest::wait_for_table($sb->get_dbh_for($cluster2[-1]), "bug_1062563.ptc_pxc");
PerconaTest::wait_for_table($sb->get_dbh_for($cluster1[-1]), "bug_1062563.ptc_pxc");
PerconaTest::wait_for_table($cluster2_dbh, "bug_1062563.ptc_pxc");
$cluster2_dbh->do("INSERT INTO bug_1062563.ptc_pxc (i) VALUES ($_)") for 3, 4;
$dsns_table_sql = catfile(qw(t lib samples MasterSlave dsn_table.sql));
$sb->load_file($cluster1[0], $dsns_table_sql, undef, no_wait => 1);
$cluster1_dbh->do("DELETE FROM dsn_t.dsns"); # Delete 12346
$sth = $cluster1_dbh->prepare("INSERT INTO dsn_t.dsns VALUES (null, null, ?)");
for my $dsn ( map { $sb->dsn_for($_) } @cluster1[1..$#cluster1], $cluster2[0] ) {
$sth->execute($dsn);
}
$sth->finish();
my $cluster1_dsn = $sb->dsn_for($cluster1[0]);
$output = output(
sub { pt_table_checksum::main(
$cluster1_dsn, qw(--lock-wait-timeout 3),
qw(-d bug_1062563),
'--recursion-method', "dsn=D=dsn_t,t=dsns"
) },
stderr => 1,
);
is(
PerconaTest::count_checksum_results($output, 'diffs'),
1,
"Bug 1062563: Detects diffs between PXC nodes when cluster -> cluster"
) or diag($output);
like(
$output,
qr/is a cluster node, but doesn't belong to the same cluster as/, #'
"Shows a warning when cluster -> cluster"
) or diag($output);
diag("Starting master1...");
$sb->start_sandbox("master", "master1");
diag("Setting it as master of a node in the first cluster");
$sb->set_as_slave($cluster1[0], "master1");
my $master1_dbh = $sb->get_dbh_for("master1");
make_dbh_differ($master1_dbh, 10..50);
my $master1_dsn = $sb->dsn_for("master1");
$output = output(
sub { pt_table_checksum::main(
$master1_dsn, qw(--lock-wait-timeout 3),
qw(-d bug_1062563),
) },
stderr => 1,
);
is(
PerconaTest::count_checksum_results($output, 'diffs'),
1,
"Bug 1062563: Detects diffs when master -> cluster"
) or diag($output);
is(
PerconaTest::count_checksum_results($output, 'rows'),
41,
"Bug 1062563: Correct number of rows for master -> cluster"
) or diag($output);
like(
$output,
qr/is a cluster node, but .*? is not. This is not currently supported/,
"Shows a warning when master -> cluster"
) or diag($output);
diag("Stopping both clusters and master1...");
$sb->stop_sandbox(@cluster1, @cluster2, "master1");
}
sub make_dbh_differ {
my ($dbh, @vals) = @_;
@vals = (@vals ? @vals : 1);
# Make them differ...
$dbh->do("DROP DATABASE IF EXISTS bug_1062563");
$dbh->do("CREATE DATABASE bug_1062563");
$dbh->do("CREATE TABLE bug_1062563.ptc_pxc (i int)");
# Now make this node different from the rest
$dbh->do("set sql_log_bin=0");
$dbh->do("INSERT INTO bug_1062563.ptc_pxc (i) VALUES ($_)") for @vals;
$dbh->do("set sql_log_bin=1");
}
# #############################################################################
# Done.
# #############################################################################
$sb->wipe_clean($master_dbh);
ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox");
done_testing;
exit;