# Copyright (C) 2008-2010 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 2 of the License. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 # USA use strict; use lib 'lib'; use lib '../lib'; use DBI; use Carp; use File::Compare; use File::Copy; use Getopt::Long; use Time::HiRes; use GenTest; use GenTest::Properties; use GenTest::Constants; use GenTest::Simplifier::Mysqltest; # NOTE: oracle function behaves differently if basedir2 is specified in addition # to basedir. In this case expected_mtr_output is ignored, and result # comparison between servers is performed instead. my $options = {}; my $o = GetOptions($options, 'config=s', 'input_file=s', 'basedir=s', 'basedir2=s', 'expected_mtr_output=s', 'verbose!', 'mtr_options=s%', 'mysqld=s%', 'replication!'); my $config = GenTest::Properties->new( options => $options, legal => [ 'config', 'input_file', 'basedir', 'basedir2', 'expected_mtr_output', 'mtr_options', 'vebose', 'replication', 'header', 'footer', 'filter', 'mysqld', 'use_connections' ], required => [ 'basedir', 'input_file', 'mtr_options'], defaults => { replication => 0, # Set to 1 to turn on --source # include/master-slave.inc and # --sync_slave_with_master } ); $config->printHelp if not $o; $config->printProps; my $header = $config->header() || []; my $footer = $config->footer() || []; if ($config->replication()) { push @$header , '--source include/master-slave.inc'; push @$footer , '--sync_slave_with_master'; } # End of user-configurable section my $iteration = 0; my $run_id = time(); say("run_id = $run_id"); my $simplifier = GenTest::Simplifier::Mysqltest->new( filter => $config->filter(), use_connections => $config->use_connections(), oracle => sub { my $oracle_mysqltest = shift; $iteration++; chdir($config->basedir.'/mysql-test'); # assume forward slash works my $tmpfile_base_name = $run_id.'-'.$iteration; # we need this for both test- and result file name my $tmpfile = $tmpfile_base_name.'.test'; # test file of this iteration open (ORACLE_MYSQLTEST, ">t/$tmpfile") or croak "Unable to open $tmpfile: $!"; print ORACLE_MYSQLTEST join("\n",@{$header})."\n\n"; print ORACLE_MYSQLTEST $oracle_mysqltest."\n"; print ORACLE_MYSQLTEST "\n".join("\n",@{$footer})."\n"; close ORACLE_MYSQLTEST; my $mysqldopt = $config->genOpt('--mysqld=--', 'mysqld'); my $mtr_start_time = Time::HiRes::time(); my $mysqltest_cmd = "perl mysql-test-run.pl $mysqldopt ". $config->genOpt('--', 'mtr_options')." t/$tmpfile 2>&1"; my $mysqltest_output = `$mysqltest_cmd`; my $mtr_exit_code = $? >> 8; my $mtr_duration = Time::HiRes::time() - $mtr_start_time; if ($iteration == 1) { say ($mysqltest_output); } else { say ("MTR test duration: $mtr_duration; exit_code: $mtr_exit_code"); } system("grep -i safe ".$config->basedir()."/mysql-test/var/log/mysqld.1.err"); my $grep_exit_code = $? >> 8; if ($grep_exit_code == 0) { say("Messages about unsafe replication found in master error log."); return ORACLE_ISSUE_NO_LONGER_REPEATABLE; } elsif ($grep_exit_code > 1) { die("grep on the mysqld.1.err error log failed"); } ######################################################################## # Start of comparison mode (two basedirs) ######################################################################## if (defined $config->basedir2) { if ($iteration == 1) { say ('Two basedirs specified. Will compare outputs instead of looking for expected output.'); say ('Server A: '.$config->basedir); say ('Server B: '.$config->basedir2); # NOTE: --record MTR option is required. TODO: Check for this? } # # Run the test against basedir2 and compare results against the previous run. # chdir($config->basedir2.'/mysql-test'); # working dir is now for Server B, so we need full path to Server A's files for later my $tmpfile_full_path = $config->basedir.'/mysql-test/t/'.$tmpfile; my $resultfile_full_path = $config->basedir.'/mysql-test/r/'.$tmpfile_base_name.'.result'; # tests/results for Server B include "-b" in the filename my $tmpfile2_base_name = $run_id.'-'.$iteration.'-b'; my $tmpfile2 = $tmpfile2_base_name.'.test'; my $tmpfile2_full_path = $config->basedir2.'/mysql-test/t/'.$tmpfile2; my $resultfile2_full_path = $config->basedir2.'/mysql-test/r/'.$tmpfile2_base_name.'.result'; # Copy test file to server B copy($tmpfile_full_path, $tmpfile2_full_path) or croak("Unable to copy test file $tmpfile to $tmpfile2"); my $mysqltest_cmd2 = "perl mysql-test-run.pl $mysqldopt ". $config->genOpt('--', 'mtr_options'). " $tmpfile2 2>&1"; # Run the test against server B # we don't really use this output for anything right now my $mysqltest_output2 = `$mysqltest_cmd2`; #say $mysqltest_output2 if $iteration == 1; # Compare the two results # We declare the tests to have failed properly only if the results # from the two test runs differ. # (We ignore expected_mtr_output in this mode) my $compare_result = compare($resultfile_full_path, $resultfile2_full_path); if ( $compare_result == 0) { # no diff say('Issue not repeatable (results were equal) with test '.$tmpfile_base_name); unlink($tmpfile_full_path) if $iteration > 1; # deletes test for Server A unlink($tmpfile2_full_path) if $iteration > 1; # deletes test for Server B unlink($resultfile_full_path) if $iteration > 1; # deletes result for Server A unlink($resultfile2_full_path) if $iteration > 1; # deletes result for Server B return ORACLE_ISSUE_NO_LONGER_REPEATABLE; } elsif ($compare_result > 0) { # diff say("Issue is repeatable (results differ) with test $tmpfile_base_name"); return ORACLE_ISSUE_STILL_REPEATABLE; } else { # error ($compare_result < 0) say("\nError ($compare_result) comparing result files for test $tmpfile_base_name"); if (! -e $resultfile_full_path) { say("Test output was:"); say $mysqltest_output; # TODO: No result file may mean that we tried an invalid query # Try comparing .reject files in this case? croak("Resultfile $resultfile_full_path not found"); } elsif (! -e $resultfile_full_path) { say("Test output was:"); say $mysqltest_output2; croak("Resultfile2 $resultfile2_full_path not found"); } } ######################################################################## # End of comparison mode (two basedirs) ######################################################################## } else { # Only one basedir specified - retain old behavior (look for expected output). # # We declare the test to have failed properly only if the # desired message is present in the output and it is not a # result of an error that caused part of the test, including # the --croak construct, to be printed to stdout. # my $expected_mtr_output = $config->expected_mtr_output; if ( ($mysqltest_output =~ m{$expected_mtr_output}sio) && ($mysqltest_output !~ m{--die}sio) ) { say("Issue repeatable with $tmpfile"); return ORACLE_ISSUE_STILL_REPEATABLE; } else { say("Issue not repeatable with $tmpfile."); unlink('t/'.$tmpfile) if $mtr_exit_code == 0; say $mysqltest_output if $iteration > 1 && $mtr_exit_code != 0; return ORACLE_ISSUE_NO_LONGER_REPEATABLE; } } } ); my $simplified_mysqltest; ## Copy input file if (-f $config->input_file){ $config->input_file =~ m/\.([a-z]+$)/i; my $extension = $1; my $input_file_copy = $config->basedir."/mysql-test/t/".$run_id."-0.".$extension; system("cp ".$config->input_file." ".$input_file_copy); if (lc($extension) eq 'csv') { say("Treating ".$config->input_file." as a CSV file"); $simplified_mysqltest = $simplifier->simplifyFromCSV($input_file_copy); } elsif (lc($extension) eq 'test') { say("Treating ".$config->input_file." as a mysqltest file"); open (MYSQLTEST_FILE , $input_file_copy) or croak "Unable to open ".$input_file_copy." as a .test file: $!"; read (MYSQLTEST_FILE , my $initial_mysqltest, -s $input_file_copy); close (MYSQLTEST_FILE); $simplified_mysqltest = $simplifier->simplify($initial_mysqltest); } else { carp "Unknown file type for ".$config->input_file; } if (defined $simplified_mysqltest) { say "Simplified mysqltest:"; print "\n\n".join("\n",@{$header})."\n\n\n".$simplified_mysqltest.join("\n",@{$footer})."\n\n"; exit (STATUS_OK); } else { say "Unable to simplify ". $config->input_file.".\n"; exit (STATUS_ENVIRONMENT_FAILURE); } } else { croak "Can't find ".$config->input_file; } ##