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 Time::HiRes qw(sleep); 13use Test::More; 14 15use PerconaTest; 16use Sandbox; 17require "$trunk/bin/pt-kill"; 18 19use Data::Dumper; 20$Data::Dumper::Indent = 1; 21$Data::Dumper::Sortkeys = 1; 22$Data::Dumper::Quotekeys = 0; 23 24my $dp = new DSNParser(opts=>$dsn_opts); 25my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp); 26my $master_dbh = $sb->get_dbh_for('master'); 27my $slave_dbh = $sb->get_dbh_for('slave1'); 28my $target_dbh = $sb->get_dbh_for('master'); 29 30if ( !$master_dbh ) { 31 plan skip_all => 'Cannot connect to sandbox master'; 32} 33elsif ( !$target_dbh ) { 34 plan skip_all => 'Cannot connect to sandbox master (target)'; 35} 36elsif ( !$slave_dbh ) { 37 plan skip_all => 'Cannot connect to sandbox slave'; 38} 39 40my $output; 41my $master_dsn = $sb->dsn_for('master'); 42my $master_cnf = $sb->cnf_for('master'); 43my $slave_dsn = $sb->dsn_for('slave1'); 44 45# Create the --log-dsn table. 46$sb->create_dbs($master_dbh, [qw(kill_test)]); 47my $log_table = "kill_test.log_table"; 48my $log_dsn = "D=kill_test,t=log_table"; 49my $log_sql = OptionParser->read_para_after( 50 "$trunk/bin/pt-kill", qr/MAGIC_create_log_table/); 51$log_sql =~ s/kill_log/$log_table/; 52$master_dbh->do($log_sql); 53$sb->wait_for_slaves(); 54 55# Create the target db for --match-db. 56my $target_db = "x$PID"; 57$sb->create_dbs($target_dbh, [$target_db]); 58 59sub setup_target { 60 eval { 61 $target_dbh->do("SELECT 1"); 62 }; 63 if ( $EVAL_ERROR ) { 64 eval { 65 $target_dbh->disconnect(); 66 }; 67 $target_dbh = $sb->get_dbh_for('master'); 68 } 69 $target_dbh->do("USE $target_db"); 70} 71 72# ############################################################################# 73# Require D and t in --log-dsn 74# ############################################################################# 75 76foreach my $test ( 77 [q/h=127.1,P=12345,u=msandbox,p=msandbox/, 'D and t'], 78 [q/h=127.1,P=12345,u=msandbox,p=msandbox,t=log_table/, 'D'], 79 [q/h=127.1,P=12345,u=msandbox,p=msandbox,D=kill_test/, 't'], 80) { 81 eval { 82 pt_kill::main($master_dsn, qw(--kill --run-time 1 --interval 1), 83 "--match-db", $target_db, 84 "--log-dsn", $test->[0], 85 ) 86 }; 87 like( 88 $EVAL_ERROR, 89 qr/\Q--log-dsn does not specify a database (D) or a database-qualified table (t)\E/, 90 "--log-dsn croaks if missing $test->[1]" 91 ); 92} 93 94# ############################################################################# 95# Basic usage 96# ############################################################################# 97 98eval { 99 setup_target(); 100 pt_kill::main($master_dsn, qw(--kill --run-time 1 --interval 1), 101 "--match-db", $target_db, 102 "--log-dsn", "$master_dsn,$log_dsn" 103 ) 104}; 105 106is( 107 $EVAL_ERROR, 108 '', 109 "--log-dsn with existing log table, no error" 110); 111 112# Should get a row like: 113# $VAR1 = [ 114# { 115# command => 'Sleep', 116# db => 'x32282', 117# host => 'localhost:62581', 118# id => '365', 119# info => undef, 120# kill_error => '', 121# kill_id => '1', 122# reason => 'Query matches db spec', 123# server_id => '12345', 124# state => '', 125# time => '0', 126# time_ms => undef, 127# timestamp => '2013-08-12 12:46:26', 128# user => 'msandbox' 129# } 130# ]; 131my $rows = $master_dbh->selectall_arrayref( 132 "SELECT * FROM $log_table", { Slice =>{} }); 133 134is( 135 scalar @$rows, 136 1, 137 "... which contains one row" 138) or diag(Dumper($rows)); 139 140is( 141 $rows->[0]->{db}, 142 $target_db, 143 "... got the target db" 144) or diag(Dumper($rows)); 145 146is( 147 $rows->[0]->{server_id}, 148 12345, 149 "... on the correct server" 150) or diag(Dumper($rows)); 151 152is( 153 $rows->[0]->{reason}, 154 'Query matches db spec', 155 "... correct kill reason" 156) or diag(Dumper($rows)); 157 158# Get the current ts in MySQL's format. 159my $current_ts = Transformers::ts(time()); 160($current_ts) = $master_dbh->selectrow_array("SELECT TIMESTAMP('$current_ts')"); 161 162# Chop off the minutes & seconds. If the rest of the date is right, 163# this is unlikely to be broken. 164substr($current_ts, -5, 5, ""); 165like( 166 $rows->[0]->{timestamp}, 167 qr/\A\Q$current_ts\E.{5}\Z/, 168 "... timestamp is correct (bug 1086259)" 169); 170 171my $against = { 172 user => 'msandbox', 173 host => 'localhost', 174 db => $target_db, 175 command => 'Sleep', 176 state => '', #($sandbox_version lt '5.1' ? "executing" : "User sleep"), 177 info => undef, 178}; 179my %trimmed_result; 180@trimmed_result{ keys %$against } = @{$rows->[0]}{ keys %$against }; 181$trimmed_result{host} =~ s/localhost:[0-9]+/localhost/; 182 183is_deeply( 184 \%trimmed_result, 185 $against, 186 "... populated as expected", 187) or diag(Dumper($rows)); 188 189# ############################################################################# 190# --create-log-table 191# ############################################################################# 192 193# XXX This test assumes that the log table exists from previous tests. 194 195eval { 196 setup_target(); 197 pt_kill::main('-F', $master_cnf, qw(--kill --run-time 1 --interval 1), 198 "--create-log-table", 199 "--match-info", 'select sleep\(4\)', 200 "--log-dsn", "$master_dsn,$log_dsn", 201 ) 202}; 203 204is( 205 $EVAL_ERROR, 206 '', 207 "--log-dsn --create-log-table and the table exists, no error" 208); 209 210$master_dbh->do("DROP TABLE IF EXISTS $log_table"); 211$sb->wait_for_slaves(); 212 213eval { 214 setup_target(); 215 pt_kill::main('-F', $master_cnf, qw(--kill --run-time 1 --interval 1), 216 "--create-log-table", 217 "--match-info", 'select sleep\(4\)', 218 "--log-dsn", "$master_dsn,$log_dsn", 219 ) 220}; 221 222is( 223 $EVAL_ERROR, 224 '', 225 "--log-dsn --create-log-table and the table doesn't exist, no error" 226); 227 228$master_dbh->do("DROP TABLE IF EXISTS $log_table"); 229$sb->wait_for_slaves(); 230 231eval { 232 setup_target(); 233 pt_kill::main('-F', $master_cnf, qw(--kill --run-time 1 --interval 1), 234 "--match-info", 'select sleep\(4\)', 235 "--log-dsn", "$master_dsn,$log_dsn", 236 ) 237}; 238 239like( 240 $EVAL_ERROR, 241 qr/\Q--log-dsn table does not exist. Please create it or specify\E/, 242 "--create-log-table is off by default" 243); 244 245# Re-create the log table for the next tests. 246$master_dbh->do($log_sql); 247$sb->wait_for_slaves(); 248 249# ############################################################################# 250# Can re-use the log table. 251# ############################################################################# 252 253for (1,2) { 254 setup_target(); 255 pt_kill::main($master_dsn, qw(--kill --run-time 1 --interval 1), 256 "--create-log-table", 257 "--match-db", $target_db, 258 "--log-dsn", "$master_dsn,$log_dsn", 259 ); 260 sleep 0.5; 261} 262 263$rows = $master_dbh->selectall_arrayref("SELECT * FROM $log_table"); 264 265is( 266 scalar @$rows, 267 2, 268 "Different --log-dsn runs reuse the log table" 269) or diag(Dumper($rows)); 270 271# ############################################################################# 272# --log-dsn and --daemonize 273# https://bugs.launchpad.net/percona-toolkit/+bug/1209436 274# ############################################################################# 275 276$master_dbh->do("TRUNCATE $log_table"); 277$sb->wait_for_slaves(); 278 279my $pid_file = "/tmp/pt-kill-test.$PID"; 280my $log_file = "/tmp/pt-kill-test-log.$PID"; 281diag(`rm -f $pid_file $log_file >/dev/null 2>&1`); 282 283setup_target(); 284system("$trunk/bin/pt-kill $master_dsn --daemonize --run-time 1 --kill-query --interval 1 --match-db $target_db --log-dsn $slave_dsn,$log_dsn --pid $pid_file --log $log_file"); 285PerconaTest::wait_for_files($pid_file); # start 286# ... # run 287PerconaTest::wait_until(sub { !-f $pid_file}); # stop 288 289# Should *not* log to master 290$rows = $master_dbh->selectall_arrayref("SELECT * FROM $log_table"); 291ok( 292 !@$rows, 293 "--log-dsn --daemonize, master (bug 1209436)", 294) or diag(Dumper($rows)); 295 296# Should log to slave 297$rows = $slave_dbh->selectall_arrayref("SELECT * FROM $log_table"); 298ok( 299 scalar @$rows, 300 "--log-dsn --daemonize, slave (bug 1209436)" 301) or diag(Dumper($rows)); 302 303# ############################################################################# 304# --log-dsn in a --config file 305# https://bugs.launchpad.net/percona-toolkit/+bug/1209436 306# ############################################################################# 307 308$master_dbh->do("TRUNCATE $log_table"); 309$sb->wait_for_slaves(); 310 311my $cnf_file = "/tmp/pt-kill-test.cnf.$PID"; 312diag(`rm -f $pid_file $log_file $cnf_file >/dev/null 2>&1`); 313 314open my $fh, '>', $cnf_file or die "Error opening $cnf_file: $OS_ERROR"; 315print { $fh } <<EOF; 316defaults-file=$master_cnf 317log-dsn=$slave_dsn,$log_dsn 318daemonize 319run-time=1 320kill-query 321interval=1 322match-db=$target_db 323pid=$pid_file 324log=$log_file 325EOF 326close $fh; 327 328setup_target(); 329system("$trunk/bin/pt-kill --config $cnf_file"); 330PerconaTest::wait_for_files($pid_file); # start 331# ... # run 332PerconaTest::wait_until(sub { !-f $pid_file}); # stop 333 334# Should *not* log to master 335$rows = $master_dbh->selectall_arrayref("SELECT * FROM $log_table"); 336ok( 337 !@$rows, 338 "--log-dsn in --config file, master (bug 1209436)", 339) or diag(Dumper($rows)); 340 341# Should log to slave 342$rows = $slave_dbh->selectall_arrayref("SELECT * FROM $log_table"); 343ok( 344 scalar @$rows, 345 "--log-dsn in --config file, slave (bug 1209436)" 346) or diag(Dumper($rows)); 347 348diag(`rm -f $pid_file $log_file $cnf_file >/dev/null 2>&1`); 349 350# ############################################################################# 351# Done. 352# ############################################################################# 353eval { $target_dbh->disconnect() }; 354$sb->wipe_clean($master_dbh); 355$sb->wipe_clean($slave_dbh); 356ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox"); 357done_testing; 358