diff --git a/lib/Sandbox.pm b/lib/Sandbox.pm index eccc9651..79011079 100644 --- a/lib/Sandbox.pm +++ b/lib/Sandbox.pm @@ -77,7 +77,7 @@ sub use { return if !defined $cmd || !$cmd; my $use = $self->_use_for($server) . " $cmd"; PTDEBUG && _d('"Executing', $use, 'on', $server); - my $out = `$use 2>&1`; + my $out = `$use`; if ( $? >> 8 ) { die "Failed to execute $cmd on $server: $out"; } @@ -141,7 +141,7 @@ sub load_file { my $use = $self->_use_for($server) . " $d < $file"; PTDEBUG && _d('Loading', $file, 'on', $server, ':', $use); - my $out = `$use 2>&1`; + my $out = `$use`; if ( $? >> 8 ) { die "Failed to execute $file on $server: $out"; } @@ -432,7 +432,7 @@ sub start_sandbox { my ($self, $mode, $server, $master_server) = @_; my $port = $port_for{$server}; my $master_port = $master_server ? $port_for{$master_server} : ''; - my $out = `$trunk/sandbox/start-sandbox $mode $port $master_port 2>&1`; + my $out = `$trunk/sandbox/start-sandbox $mode $port $master_port`; die $out if $CHILD_ERROR; return $out; } @@ -440,7 +440,7 @@ sub start_sandbox { sub stop_sandbox { my ($self, @sandboxes) = @_; my @ports = @port_for{@sandboxes}; - my $out = `$trunk/sandbox/stop-sandbox @ports 2>&1`; + my $out = `$trunk/sandbox/stop-sandbox @ports`; die $out if $CHILD_ERROR; return $out; } diff --git a/t/lib/Cxn.t b/t/lib/Cxn.t index eae15ac6..a9517b5b 100644 --- a/t/lib/Cxn.t +++ b/t/lib/Cxn.t @@ -10,6 +10,7 @@ use strict; use warnings FATAL => 'all'; use English qw(-no_match_vars); use Test::More; +use Data::Dumper; use Sandbox; use OptionParser; @@ -17,8 +18,7 @@ use DSNParser; use Quoter; use PerconaTest; use Cxn; - -use Data::Dumper; +use VersionParser; my $q = new Quoter(); my $dp = new DSNParser(opts=>$dsn_opts); @@ -261,15 +261,14 @@ ok( "is_cluster_node works correctly for non-nodes" ); -use VersionParser; my $db_flavor = VersionParser->new($master_dbh)->flavor(); SKIP: { - skip "PXC-only test", 1 + skip "PXC-only test", 17 unless $db_flavor =~ /XtraDB Cluster/; - + diag("Starting a 1-node PXC"); my ($node) = $sb->start_cluster(cluster_size => 1); - + my $cxn1 = make_cxn( dsn_string => $sb->dsn_for($node) ); $cxn1->connect(); ok( @@ -281,7 +280,7 @@ SKIP: { !$cxn->is_master_of($cxn1), "->is_master_of works correctly for a server unrelated to a cluster" ); - + diag("Setting node as a slave of master1"); $sb->set_as_slave($node, "master1"); ok( @@ -360,10 +359,11 @@ SKIP: { diag($sb->stop_sandbox($node2, $node3)); diag("Starting a 3-node cluster"); my $node4; - ($node2, $node3, $node4) = $sb->start_cluster( - cluster_size => 3, - cluster_name => "pt_cxn_test", - ); + ($node2, $node3, $node4) + = $sb->start_cluster( + cluster_size => 3, + cluster_name => "pt_cxn_test", + ); $cxn2 = make_cxn( dsn_string => $sb->dsn_for($node2) ); $cxn2->connect(); $cxn3 = make_cxn( dsn_string => $sb->dsn_for($node3) ); diff --git a/t/pt-table-checksum/bugs.t b/t/pt-table-checksum/bugs.t index 0dcac017..7262cdff 100644 --- a/t/pt-table-checksum/bugs.t +++ b/t/pt-table-checksum/bugs.t @@ -191,201 +191,6 @@ like( "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. # ############################################################################# diff --git a/t/pt-table-checksum/pxc.t b/t/pt-table-checksum/pxc.t new file mode 100644 index 00000000..edf24a85 --- /dev/null +++ b/t/pt-table-checksum/pxc.t @@ -0,0 +1,244 @@ +#!/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; +use Data::Dumper; +use File::Spec::Functions; + +# 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 PerconaTest; +use Sandbox; +use VersionParser; + +# 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 $db_flavor = VersionParser->new($master_dbh)->flavor(); + +if ( !$master_dbh ) { + plan skip_all => 'Cannot connect to sandbox master'; +} +elsif ( $db_flavor !~ /XtraDB Cluster/ ) { + plan skip_all => "PXC tests"; +} + +# 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/"; + +# ############################################################################# +# pt-table-checksum v2.1.4 doesn't detect diffs on Percona XtraDB Cluster nodes +# https://bugs.launchpad.net/percona-toolkit/+bug/1062563 +# ############################################################################# + +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"); +} + +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"); + +# ############################################################################# +# Done. +# ############################################################################# +$sb->wipe_clean($master_dbh); +ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox"); +done_testing;