279 lines
10 KiB
Perl
279 lines
10 KiB
Perl
# 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;
|
|
}
|
|
##
|
|
|