1#!/usr/bin/env perl
2
3BEGIN {
4   die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n"
5      unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH};
6   unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib";
7};
8
9use strict;
10use warnings FATAL => 'all';
11use English qw(-no_match_vars);
12use Test::More;
13
14# Hostnames make testing less accurate.  Tests need to see
15# that such-and-such happened on specific slave hosts, but
16# the sandbox servers are all on one host so all slaves have
17# the same hostname.
18$ENV{PERCONA_TOOLKIT_TEST_USE_DSN_NAMES} = 1;
19
20use Data::Dumper;
21use PerconaTest;
22use Sandbox;
23
24# Fix @INC because pt-table-checksum uses subclass OobNibbleIterator.
25require "$trunk/bin/pt-table-checksum";
26
27my $dp = new DSNParser(opts=>$dsn_opts);
28my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp);
29my $master_dbh = $sb->get_dbh_for('master');
30my $slave1_dbh = $sb->get_dbh_for('slave1');
31my $slave2_dbh = $sb->get_dbh_for('slave2');
32
33if ( !$master_dbh ) {
34   plan skip_all => 'Cannot connect to sandbox master';
35}
36elsif ( !$slave1_dbh ) {
37   plan skip_all => 'Cannot connect to sandbox slave1';
38}
39elsif ( !@{$master_dbh->selectall_arrayref("show databases like 'sakila'")} ) {
40   plan skip_all => 'sakila database is not loaded';
41}
42
43# The sandbox servers run with lock_wait_timeout=3 and it's not dynamic
44# so we need to specify --set-vars innodb_lock_wait_timeout=3 else the tool will die.
45my $master_dsn = 'h=127.1,P=12345';
46my @args       = (qw(--set-vars innodb_lock_wait_timeout=3));
47my $row;
48my $output;
49my $exit_status;
50my $sample  = "t/pt-table-checksum/samples/";
51
52# ############################################################################
53# Should always create schema and tables with IF NOT EXISTS
54# https://bugs.launchpad.net/percona-toolkit/+bug/950294
55# ############################################################################
56
57$master_dbh->do("DROP DATABASE IF EXISTS percona");
58diag(`/tmp/12345/use -u root < $trunk/t/lib/samples/ro-checksum-user.sql 2>/dev/null`);
59PerconaTest::wait_for_table($slave2_dbh, "mysql.user", "user='ro_checksum_user'");
60
61$output = output(
62   sub { $exit_status = pt_table_checksum::main(@args,
63      "$master_dsn,u=ro_checksum_user,p=msandbox",
64      qw(--recursion-method none)
65   ) },
66   stderr => 1,
67);
68
69like(
70   $output,
71   qr/\Qdatabase percona does not exist and it cannot be created automatically/,
72   "Error if percona db doesn't exist and user can't create it",
73);
74
75$output = output(
76   sub { pt_table_checksum::main(@args,
77      "$master_dsn,u=ro_checksum_user,p=msandbox",
78      qw(--recursion-method none --no-create-replicate-table)
79   ) },
80   stderr => 1,
81);
82
83like(
84   $output,
85   qr/\Qdatabase percona does not exist and --no-create-replicate-table was/,
86   "Error if percona db doesn't exist and --no-create-replicate-table",
87);
88
89diag(`/tmp/12345/use -u root -e "drop user 'ro_checksum_user'\@'%'"`);
90wait_until(
91   sub {
92      my $rows=$slave2_dbh->selectall_arrayref("SELECT user FROM mysql.user");
93      return !grep { ($_->[0] || '') eq 'ro_checksum_user' } @$rows;
94   }
95);
96
97# ############################################################################
98# --recursion-method=none to avoid SHOW SLAVE HOSTS
99# https://bugs.launchpad.net/percona-toolkit/+bug/987694
100# ############################################################################
101
102# Create percona.checksums because ro_checksum_user doesn't have the privs.
103pt_table_checksum::main(@args,
104   "$master_dsn,u=msandbox,p=msandbox",
105   qw(-t sakila.country --quiet --quiet));
106
107diag(`/tmp/12345/use -u root < $trunk/t/lib/samples/ro-checksum-user.sql 2>/dev/null`);
108PerconaTest::wait_for_table($slave1_dbh, "mysql.tables_priv", "user='ro_checksum_user'");
109
110$output = output(
111   sub { $exit_status = pt_table_checksum::main(@args,
112      "$master_dsn,u=ro_checksum_user,p=msandbox",
113      # Comment out this line and the tests fail because ro_checksum_user
114      # doesn't have privs to SHOW SLAVE HOSTS.  This proves that
115      # --recursion-method none is working.
116      qw(--recursion-method none --no-create-replicate-table)
117   ) },
118   stderr => 1,
119);
120
121is(
122   $exit_status,
123   0,
124   "Read-only user (bug 987694): 0 exit"
125);
126
127like(
128   $output,
129   qr/ sakila.store$/m,
130   "Read-only user (bug 987694): checksummed rows"
131);
132
133($output, $exit_status) = full_output(
134   sub { pt_table_checksum::main(@args,
135      "$master_dsn,u=ro_checksum_user,p=msandbox",
136      qw(--recursion-method none)
137   ) }
138);
139
140is(
141   $exit_status,
142   0,
143   "No error if db exists on the master, can't CREATE DATABASE, --no-create-replicate-table was not specified, but the database does exist in all slaves"
144);
145
146diag(qx{/tmp/12345/use -u root -e 'DROP TABLE `percona`.`checksums`'});
147
148($output, $exit_status) = full_output(
149   sub { pt_table_checksum::main(@args,
150      "$master_dsn,u=ro_checksum_user,p=msandbox",
151      qw(--recursion-method none --no-create-replicate-table)
152   ) },
153);
154
155like($output,
156   qr/\Q--replicate table `percona`.`checksums` does not exist and --no/,
157   "Error if checksums db doesn't exist and --no-create-replicate-table"
158);
159
160diag(`/tmp/12345/use -u root -e "drop user 'ro_checksum_user'\@'%'"`);
161wait_until(
162   sub {
163      my $rows=$slave2_dbh->selectall_arrayref("SELECT user FROM mysql.user");
164      return !grep { ($_->[0] || '') eq 'ro_checksum_user' } @$rows;
165   }
166);
167
168# #############################################################################
169# Bug 916168: bug in pt-table-checksum privileges check
170# #############################################################################
171diag(`/tmp/12345/use -u root < $trunk/t/pt-table-checksum/samples/privs-bug-916168.sql`);
172
173$output = output(
174   sub { $exit_status = pt_table_checksum::main(@args,
175      "$master_dsn,u=test_user,p=foo", qw(-t sakila.country)) },
176);
177
178is(
179   PerconaTest::count_checksum_results($output, 'rows'),
180   109,
181   "test_user privs work (bug 916168)"
182);
183
184diag(`/tmp/12345/use -u root -e "drop user 'test_user'\@'%'"`);
185wait_until(
186   sub {
187      my $rows=$slave2_dbh->selectall_arrayref("SELECT user FROM mysql.user");
188      return !grep { ($_->[0] || '') eq 'test_user' } @$rows;
189   }
190);
191
192# #############################################################################
193# Done.
194# #############################################################################
195$sb->wipe_clean($master_dbh);
196ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox");
197done_testing;
198exit;
199