#!/usr/bin/perl
# -*- cperl -*-
#
##############################################################################
#
# mysql-test-run.pl
#
# Tool used for executing a suite of .test file
#
# See the "MySQL Test framework manual" for more information
# http://dev.mysql.com/doc/mysqltest/en/index.html
#
# Please keep the test framework tools identical in all versions!
#
##############################################################################
#
# Coding style directions for this perl script
#
# - To make this Perl script easy to alter even for those that not
# code Perl that often, keeep the coding style as close as possible to
# the C/C++ MySQL coding standard.
#
# - All lists of arguments to send to commands are Perl lists/arrays,
# not strings we append args to. Within reason, most string
# concatenation for arguments should be avoided.
#
# - Functions defined in the main program are not to be prefixed,
# functions in "library files" are to be prefixed with "mtr_" (for
# Mysql-Test-Run). There are some exceptions, code that fits best in
# the main program, but are put into separate files to avoid
# clutter, may be without prefix.
#
# - All stat/opendir/-f/ is to be kept in collect_test_cases(). It
# will create a struct that the rest of the program can use to get
# the information. This separates the "find information" from the
# "do the work" and makes the program more easy to maintain.
#
# - The rule when it comes to the logic of this program is
#
# command_line_setup() - is to handle the logic between flags
# collect_test_cases() - is to do its best to select what tests
# to run, dig out options, if needs restart etc.
# run_testcase() - is to run a single testcase, and follow the
# logic set in both above. No, or rare file
# system operations. If a test seems complex,
# it should probably not be here.
#
# A nice way to trace the execution of this script while debugging
# is to use the Devel::Trace package found at
# "http://www.plover.com/~mjd/perl/Trace/" and run this script like
# "perl -d:Trace mysql-test-run.pl"
#
$Devel::Trace::TRACE= 0; # Don't trace boring init stuff
#require 5.6.1;
use File::Path;
use File::Basename;
use File::Copy;
use Cwd;
use Getopt::Long;
use Sys::Hostname;
use IO::Socket;
use IO::Socket::INET;
use Data::Dumper;
use strict;
use warnings;
use diagnostics;
select(STDOUT);
$| = 1; # Automatically flush STDOUT
our $glob_win32_perl= ($^O eq "MSWin32"); # ActiveState Win32 Perl
our $glob_cygwin_perl= ($^O eq "cygwin"); # Cygwin Perl
our $glob_win32= ($glob_win32_perl or $glob_cygwin_perl);
our $glob_netware= ($^O eq "NetWare"); # NetWare
require "lib/mtr_cases.pl";
require "lib/mtr_im.pl";
require "lib/mtr_process.pl";
require "lib/mtr_timer.pl";
require "lib/mtr_io.pl";
require "lib/mtr_gcov.pl";
require "lib/mtr_gprof.pl";
require "lib/mtr_report.pl";
require "lib/mtr_diff.pl";
require "lib/mtr_match.pl";
require "lib/mtr_misc.pl";
require "lib/mtr_stress.pl";
$Devel::Trace::TRACE= 1;
##############################################################################
#
# Default settings
#
##############################################################################
# Misc global variables
our $mysql_version_id;
our $glob_mysql_test_dir= undef;
our $glob_mysql_bench_dir= undef;
our $glob_hostname= undef;
our $glob_scriptname= undef;
our $glob_timers= undef;
our $glob_use_running_ndbcluster= 0;
our $glob_use_running_ndbcluster_slave= 0;
our $glob_use_embedded_server= 0;
our @glob_test_mode;
our $glob_basedir;
our $path_charsetsdir;
our $path_client_bindir;
our $path_language;
our $path_timefile;
our $path_snapshot;
our $path_mysqltest_log;
our $path_current_test_log;
our $path_my_basedir;
our $opt_vardir; # A path but set directly on cmd line
our $path_vardir_trace; # unix formatted opt_vardir for trace files
our $opt_tmpdir; # A path but set directly on cmd line
# Visual Studio produces executables in different sub-directories based on the
# configuration used to build them. To make life easier, an environment
# variable or command-line option may be specified to control which set of
# executables will be used by the test suite.
our $opt_vs_config = $ENV{'MTR_VS_CONFIG'};
our $default_vardir;
our $opt_usage;
our $opt_suite;
our $opt_script_debug= 0; # Script debugging, enable with --script-debug
our $opt_verbose= 0; # Verbose output, enable with --verbose
our $exe_master_mysqld;
our $exe_mysql;
our $exe_mysqladmin;
our $exe_mysql_upgrade;
our $exe_mysqlbinlog;
our $exe_mysql_client_test;
our $exe_mysqld;
our $exe_mysqlcheck;
our $exe_mysqldump;
our $exe_mysqlslap;
our $exe_mysqlimport;
our $exe_mysqlshow;
our $exe_mysql_fix_system_tables;
our $file_mysql_fix_privilege_tables;
our $exe_mysqltest;
our $exe_ndbd;
our $exe_ndb_mgmd;
our $exe_slave_mysqld;
our $exe_im;
our $exe_my_print_defaults;
our $exe_perror;
our $lib_udf_example;
our $exe_libtool;
our $opt_bench= 0;
our $opt_small_bench= 0;
our $opt_big_test= 0;
our @opt_extra_mysqld_opt;
our $opt_compress;
our $opt_ssl;
our $opt_skip_ssl;
our $opt_ssl_supported;
our $opt_ps_protocol;
our $opt_sp_protocol;
our $opt_cursor_protocol;
our $opt_view_protocol;
our $opt_debug;
our $opt_do_test;
our @opt_cases; # The test cases names in argv
our $opt_embedded_server;
our $opt_extern= 0;
our $opt_socket;
our $opt_fast;
our $opt_force;
our $opt_reorder= 0;
our $opt_enable_disabled;
our $opt_mem= $ENV{'MTR_MEM'};
our $opt_gcov;
our $opt_gcov_err;
our $opt_gcov_msg;
our $glob_debugger= 0;
our $opt_gdb;
our $opt_client_gdb;
our $opt_ddd;
our $opt_client_ddd;
our $opt_manual_gdb;
our $opt_manual_ddd;
our $opt_manual_debug;
our $opt_debugger;
our $opt_client_debugger;
our $opt_gprof;
our $opt_gprof_dir;
our $opt_gprof_master;
our $opt_gprof_slave;
our $master;
our $slave;
our $clusters;
our $instance_manager;
our $opt_ndbcluster_port;
our $opt_ndbconnectstring;
our $opt_ndbcluster_port_slave;
our $opt_ndbconnectstring_slave;
our $opt_record;
my $opt_report_features;
our $opt_check_testcases;
our $opt_skip;
our $opt_skip_rpl;
our $max_slave_num= 0;
our $use_innodb;
our $opt_skip_test;
our $opt_skip_im;
our $opt_sleep;
our $opt_testcase_timeout;
our $opt_suite_timeout;
my $default_testcase_timeout= 15; # 15 min max
my $default_suite_timeout= 180; # 3 hours max
our $opt_start_and_exit;
our $opt_start_dirty;
our $opt_start_from;
our $opt_strace_client;
our $opt_timer= 1;
our $opt_user;
our $opt_valgrind= 0;
our $opt_valgrind_mysqld= 0;
our $opt_valgrind_mysqltest= 0;
our $default_valgrind_options= "--show-reachable=yes";
our $opt_valgrind_options;
our $opt_valgrind_path;
our $opt_callgrind;
our $opt_stress= "";
our $opt_stress_suite= "main";
our $opt_stress_mode= "random";
our $opt_stress_threads= 5;
our $opt_stress_test_count= 0;
our $opt_stress_loop_count= 0;
our $opt_stress_test_duration= 0;
our $opt_stress_init_file= "";
our $opt_stress_test_file= "";
our $opt_wait_for_master;
our $opt_wait_for_slave;
our $opt_warnings;
our $opt_udiff;
our $opt_skip_ndbcluster= 0;
our $opt_skip_ndbcluster_slave= 0;
our $opt_with_ndbcluster= 0;
our $opt_with_ndbcluster_only= 0;
our $glob_ndbcluster_supported= 0;
our $opt_ndb_extra_test= 0;
our $opt_skip_master_binlog= 0;
our $opt_skip_slave_binlog= 0;
our $exe_ndb_mgm;
our $exe_ndb_waiter;
our $path_ndb_tools_dir;
our $path_ndb_examples_dir;
our $exe_ndb_example;
our $path_ndb_testrun_log;
our @data_dir_lst;
our $used_binlog_format;
our $debug_compiled_binaries;
our $glob_tot_real_time= 0;
our %mysqld_variables;
my $source_dist= 0;
######################################################################
#
# Function declarations
#
######################################################################
sub main ();
sub initial_setup ();
sub command_line_setup ();
sub datadir_setup ();
sub executable_setup ();
sub environment_setup ();
sub kill_running_servers ();
sub cleanup_stale_files ();
sub check_ssl_support ($);
sub check_running_as_root();
sub check_ndbcluster_support ($);
sub rm_ndbcluster_tables ($);
sub ndbcluster_start_install ($);
sub ndbcluster_start ($$);
sub ndbcluster_wait_started ($$);
sub mysqld_wait_started($);
sub run_benchmarks ($);
sub initialize_servers ();
sub mysql_install_db ();
sub install_db ($$);
sub copy_install_db ($$);
sub run_testcase ($);
sub run_testcase_stop_servers ($$$);
sub run_testcase_start_servers ($);
sub run_testcase_check_skip_test($);
sub report_failure_and_restart ($);
sub do_before_start_master ($);
sub do_before_start_slave ($);
sub ndbd_start ($$$);
sub ndb_mgmd_start ($);
sub mysqld_start ($$$);
sub mysqld_arguments ($$$$$);
sub stop_all_servers ();
sub run_mysqltest ($);
sub usage ($);
######################################################################
#
# Main program
#
######################################################################
main();
sub main () {
command_line_setup();
check_ndbcluster_support(\%mysqld_variables);
check_ssl_support(\%mysqld_variables);
check_debug_support(\%mysqld_variables);
executable_setup();
environment_setup();
signal_setup();
if ( $opt_gcov )
{
gcov_prepare();
}
if ( $opt_gprof )
{
gprof_prepare();
}
if ( $opt_bench )
{
initialize_servers();
run_benchmarks(shift); # Shift what? Extra arguments?!
}
elsif ( $opt_stress )
{
initialize_servers();
run_stress_test()
}
else
{
# Figure out which tests we are going to run
my $tests= collect_test_cases($opt_suite);
# Turn off NDB and other similar options if no tests use it
my ($need_ndbcluster,$need_im);
foreach my $test (@$tests)
{
next if $test->{skip};
$need_ndbcluster||= $test->{ndb_test};
$need_im||= $test->{component_id} eq 'im';
# Count max number of slaves used by a test case
if ( $test->{slave_num} > $max_slave_num)
{
$max_slave_num= $test->{slave_num};
mtr_error("Too many slaves") if $max_slave_num > 3;
}
$use_innodb||= $test->{'innodb_test'};
}
# Check if cluster can be skipped
if ( !$need_ndbcluster )
{
$opt_skip_ndbcluster= 1;
$opt_skip_ndbcluster_slave= 1;
}
# Check if slave cluster can be skipped
if ($max_slave_num == 0)
{
$opt_skip_ndbcluster_slave= 1;
}
# Check if im can be skipped
if ( ! $need_im )
{
$opt_skip_im= 1;
}
initialize_servers();
if ( $opt_report_features ) {
run_report_features();
}
run_suite($opt_suite, $tests);
}
mtr_exit(0);
}
##############################################################################
#
# Default settings
#
##############################################################################
sub command_line_setup () {
# These are defaults for things that are set on the command line
$opt_suite= "main"; # Special default suite
my $opt_comment;
my $opt_master_myport= 9306;
my $opt_slave_myport= 9308;
$opt_ndbcluster_port= 9310;
$opt_ndbcluster_port_slave= 9311;
my $im_port= 9312;
my $im_mysqld1_port= 9313;
my $im_mysqld2_port= 9314;
#
# To make it easier for different devs to work on the same host,
# an environment variable can be used to control all ports. A small
# number is to be used, 0 - 16 or similar.
#
# Note the MASTER_MYPORT has to be set the same in all 4.x and 5.x
# versions of this script, else a 4.0 test run might conflict with a
# 5.1 test run, even if different MTR_BUILD_THREAD is used. This means
# all port numbers might not be used in this version of the script.
#
# Also note the limiteation of ports we are allowed to hand out. This
# differs between operating systems and configuration, see
# http://www.ncftp.com/ncftpd/doc/misc/ephemeral_ports.html
# But a fairly safe range seems to be 5001 - 32767
if ( $ENV{'MTR_BUILD_THREAD'} )
{
# Up to two masters, up to three slaves
$opt_master_myport= $ENV{'MTR_BUILD_THREAD'} * 10 + 10000; # and 1
$opt_slave_myport= $opt_master_myport + 2; # and 3 4
$opt_ndbcluster_port= $opt_master_myport + 5;
$opt_ndbcluster_port_slave= $opt_master_myport + 6;
$im_port= $opt_master_myport + 7;
$im_mysqld1_port= $opt_master_myport + 8;
$im_mysqld2_port= $opt_master_myport + 9;
}
if ( $opt_master_myport < 5001 or $opt_master_myport + 10 >= 32767 )
{
mtr_error("MTR_BUILD_THREAD number results in a port",
"outside 5001 - 32767",
"($opt_master_myport - $opt_master_myport + 10)");
}
# This is needed for test log evaluation in "gen-build-status-page"
# in all cases where the calling tool does not log the commands
# directly before it executes them, like "make test-force-pl" in RPM builds.
print "Logging: $0 ", join(" ", @ARGV), "\n";
# Read the command line
# Note: Keep list, and the order, in sync with usage at end of this file
Getopt::Long::Configure("pass_through");
GetOptions(
# Control what engine/variation to run
'embedded-server' => \$opt_embedded_server,
'ps-protocol' => \$opt_ps_protocol,
'sp-protocol' => \$opt_sp_protocol,
'view-protocol' => \$opt_view_protocol,
'cursor-protocol' => \$opt_cursor_protocol,
'ssl|with-openssl' => \$opt_ssl,
'skip-ssl' => \$opt_skip_ssl,
'compress' => \$opt_compress,
'bench' => \$opt_bench,
'small-bench' => \$opt_small_bench,
'with-ndbcluster' => \$opt_with_ndbcluster,
'vs-config' => \$opt_vs_config,
# Control what test suites or cases to run
'force' => \$opt_force,
'with-ndbcluster-only' => \$opt_with_ndbcluster_only,
'skip-ndbcluster|skip-ndb' => \$opt_skip_ndbcluster,
'skip-ndbcluster-slave|skip-ndb-slave'
=> \$opt_skip_ndbcluster_slave,
'ndb-extra-test' => \$opt_ndb_extra_test,
'skip-master-binlog' => \$opt_skip_master_binlog,
'skip-slave-binlog' => \$opt_skip_slave_binlog,
'do-test=s' => \$opt_do_test,
'start-from=s' => \$opt_start_from,
'suite=s' => \$opt_suite,
'skip-rpl' => \$opt_skip_rpl,
'skip-im' => \$opt_skip_im,
'skip-test=s' => \$opt_skip_test,
'big-test' => \$opt_big_test,
# Specify ports
'master_port=i' => \$opt_master_myport,
'slave_port=i' => \$opt_slave_myport,
'ndbcluster-port|ndbcluster_port=i' => \$opt_ndbcluster_port,
'ndbcluster-port-slave=i' => \$opt_ndbcluster_port_slave,
'im-port=i' => \$im_port, # Instance Manager port.
'im-mysqld1-port=i' => \$im_mysqld1_port, # Port of mysqld, controlled by IM
'im-mysqld2-port=i' => \$im_mysqld2_port, # Port of mysqld, controlled by IM
# Test case authoring
'record' => \$opt_record,
'check-testcases' => \$opt_check_testcases,
# Extra options used when starting mysqld
'mysqld=s' => \@opt_extra_mysqld_opt,
# Run test on running server
'extern' => \$opt_extern,
'ndb-connectstring=s' => \$opt_ndbconnectstring,
'ndb-connectstring-slave=s' => \$opt_ndbconnectstring_slave,
# Debugging
'gdb' => \$opt_gdb,
'client-gdb' => \$opt_client_gdb,
'manual-gdb' => \$opt_manual_gdb,
'manual-debug' => \$opt_manual_debug,
'ddd' => \$opt_ddd,
'client-ddd' => \$opt_client_ddd,
'debugger=s' => \$opt_debugger,
'client-debugger=s' => \$opt_client_debugger,
'strace-client' => \$opt_strace_client,
'master-binary=s' => \$exe_master_mysqld,
'slave-binary=s' => \$exe_slave_mysqld,
# Coverage, profiling etc
'gcov' => \$opt_gcov,
'gprof' => \$opt_gprof,
'valgrind|valgrind-all' => \$opt_valgrind,
'valgrind-mysqltest' => \$opt_valgrind_mysqltest,
'valgrind-mysqld' => \$opt_valgrind_mysqld,
'valgrind-options=s' => \$opt_valgrind_options,
'valgrind-path=s' => \$opt_valgrind_path,
'callgrind' => \$opt_callgrind,
# Stress testing
'stress' => \$opt_stress,
'stress-suite=s' => \$opt_stress_suite,
'stress-threads=i' => \$opt_stress_threads,
'stress-test-file=s' => \$opt_stress_test_file,
'stress-init-file=s' => \$opt_stress_init_file,
'stress-mode=s' => \$opt_stress_mode,
'stress-loop-count=i' => \$opt_stress_loop_count,
'stress-test-count=i' => \$opt_stress_test_count,
'stress-test-duration=i' => \$opt_stress_test_duration,
# Directories
'tmpdir=s' => \$opt_tmpdir,
'vardir=s' => \$opt_vardir,
'benchdir=s' => \$glob_mysql_bench_dir,
'mem' => \$opt_mem,
# Misc
'report-features' => \$opt_report_features,
'comment=s' => \$opt_comment,
'debug' => \$opt_debug,
'fast' => \$opt_fast,
'reorder' => \$opt_reorder,
'enable-disabled' => \$opt_enable_disabled,
'script-debug' => \$opt_script_debug,
'verbose' => \$opt_verbose,
'sleep=i' => \$opt_sleep,
'socket=s' => \$opt_socket,
'start-dirty' => \$opt_start_dirty,
'start-and-exit' => \$opt_start_and_exit,
'timer!' => \$opt_timer,
'unified-diff|udiff' => \$opt_udiff,
'user=s' => \$opt_user,
'testcase-timeout=i' => \$opt_testcase_timeout,
'suite-timeout=i' => \$opt_suite_timeout,
'warnings|log-warnings' => \$opt_warnings,
'help|h' => \$opt_usage,
) or usage("Can't read options");
usage("") if $opt_usage;
$glob_scriptname= basename($0);
# We require that we are in the "mysql-test" directory
# to run mysql-test-run
if (! -f $glob_scriptname)
{
mtr_error("Can't find the location for the mysql-test-run script\n" .
"Go to to the mysql-test directory and execute the script " .
"as follows:\n./$glob_scriptname");
}
if ( -d "../sql" )
{
$source_dist= 1;
}
$glob_hostname= mtr_short_hostname();
# Find the absolute path to the test directory
$glob_mysql_test_dir= cwd();
if ( $glob_cygwin_perl )
{
# Windows programs like 'mysqld' needs Windows paths
$glob_mysql_test_dir= `cygpath -m "$glob_mysql_test_dir"`;
chomp($glob_mysql_test_dir);
}
# In most cases, the base directory we find everything relative to,
# is the parent directory of the "mysql-test" directory. For source
# distributions, TAR binary distributions and some other packages.
$glob_basedir= dirname($glob_mysql_test_dir);
# In the RPM case, binaries and libraries are installed in the
# default system locations, instead of having our own private base
# directory. And we install "/usr/share/mysql-test". Moving up one
# more directory relative to "mysql-test" gives us a usable base
# directory for RPM installs.
if ( ! $source_dist and ! -d "$glob_basedir/bin" )
{
$glob_basedir= dirname($glob_basedir);
}
# Expect mysql-bench to be located adjacent to the source tree, by default
$glob_mysql_bench_dir= "$glob_basedir/../mysql-bench"
unless defined $glob_mysql_bench_dir;
$glob_mysql_bench_dir= undef
unless -d $glob_mysql_bench_dir;
$path_my_basedir=
$source_dist ? $glob_mysql_test_dir : $glob_basedir;
$glob_timers= mtr_init_timers();
#
# Find the mysqld executable to be able to find the mysqld version
# number as early as possible
#
# Look for the client binaries
$path_client_bindir= mtr_path_exists("$glob_basedir/client_release",
"$glob_basedir/client_debug",
vs_config_dirs('client', ''),
"$glob_basedir/client",
"$glob_basedir/bin");
$exe_mysqld= mtr_exe_exists (vs_config_dirs('sql', 'mysqld'),
"$glob_basedir/sql/mysqld",
"$path_client_bindir/mysqld-max-nt",
"$path_client_bindir/mysqld-max",
"$path_client_bindir/mysqld-nt",
"$path_client_bindir/mysqld",
"$path_client_bindir/mysqld-debug",
"$path_client_bindir/mysqld-max",
"$glob_basedir/libexec/mysqld",
"$glob_basedir/bin/mysqld",
"$glob_basedir/sbin/mysqld");
# Use the mysqld found above to find out what features are available
collect_mysqld_features();
if ( $opt_comment )
{
print "\n";
print '#' x 78, "\n";
print "# $opt_comment\n";
print '#' x 78, "\n\n";
}
foreach my $arg ( @ARGV )
{
if ( $arg =~ /^--skip-/ )
{
push(@opt_extra_mysqld_opt, $arg);
}
elsif ( $arg =~ /^--$/ )
{
# It is an effect of setting 'pass_through' in option processing
# that the lone '--' separating options from arguments survives,
# simply ignore it.
}
elsif ( $arg =~ /^-/ )
{
usage("Invalid option \"$arg\"");
}
else
{
push(@opt_cases, $arg);
}
}
# --------------------------------------------------------------------------
# Find out type of logging that are being used
# --------------------------------------------------------------------------
# NOTE if the default binlog format is changed, this has to be changed
$used_binlog_format= "stmt";
if ( $mysql_version_id >= 50100 )
{
$used_binlog_format= "mixed"; # Default value for binlog format
foreach my $arg ( @opt_extra_mysqld_opt )
{
if ( $arg =~ /binlog-format=(\S+)/ )
{
$used_binlog_format= $1;
}
}
mtr_report("Using binlog format '$used_binlog_format'");
}
# --------------------------------------------------------------------------
# Check if we should speed up tests by trying to run on tmpfs
# --------------------------------------------------------------------------
if ( defined $opt_mem )
{
mtr_error("Can't use --mem and --vardir at the same time ")
if $opt_vardir;
mtr_error("Can't use --mem and --tmpdir at the same time ")
if $opt_tmpdir;
# Search through list of locations that are known
# to be "fast disks" to list to find a suitable location
# Use --mem=
as first location to look.
my @tmpfs_locations= ($opt_mem, "/dev/shm", "/tmp");
foreach my $fs (@tmpfs_locations)
{
if ( -d $fs )
{
mtr_report("Using tmpfs in $fs");
$opt_mem= "$fs/var";
$opt_mem .= $ENV{'MTR_BUILD_THREAD'} if $ENV{'MTR_BUILD_THREAD'};
last;
}
}
}
# --------------------------------------------------------------------------
# Set the "var/" directory, as it is the base for everything else
# --------------------------------------------------------------------------
$default_vardir= "$glob_mysql_test_dir/var";
if ( ! $opt_vardir )
{
$opt_vardir= $default_vardir;
}
elsif ( $mysql_version_id < 50000 and
$opt_vardir ne $default_vardir)
{
# Version 4.1 and --vardir was specified
# Only supported as a symlink from var/
# by setting up $opt_mem that symlink will be created
if ( ! $glob_win32 )
{
# Only platforms that have native symlinks can use the vardir trick
$opt_mem= $opt_vardir;
mtr_report("Using 4.1 vardir trick");
}
$opt_vardir= $default_vardir;
}
$path_vardir_trace= $opt_vardir;
# Chop off any "c:", DBUG likes a unix path ex: c:/src/... => /src/...
$path_vardir_trace=~ s/^\w://;
# We make the path absolute, as the server will do a chdir() before usage
unless ( $opt_vardir =~ m,^/, or
($glob_win32 and $opt_vardir =~ m,^[a-z]:/,i) )
{
# Make absolute path, relative test dir
$opt_vardir= "$glob_mysql_test_dir/$opt_vardir";
}
# Ensure a proper error message
mkpath("$opt_vardir");
unless ( -d $opt_vardir and -w $opt_vardir )
{
mtr_error("Writable 'var' directory is needed, use the '--vardir' option");
}
# --------------------------------------------------------------------------
# Set tmpdir
# --------------------------------------------------------------------------
$opt_tmpdir= "$opt_vardir/tmp" unless $opt_tmpdir;
$opt_tmpdir =~ s,/+$,,; # Remove ending slash if any
# --------------------------------------------------------------------------
# Check im suport
# --------------------------------------------------------------------------
if ( $mysql_version_id < 50000 )
{
# Instance manager is not supported until 5.0
$opt_skip_im= 1;
}
if ( $glob_win32 )
{
mtr_report("Disable Instance manager - not supported on Windows");
$opt_skip_im= 1;
}
# --------------------------------------------------------------------------
# Record flag
# --------------------------------------------------------------------------
if ( $opt_record and ! @opt_cases )
{
mtr_error("Will not run in record mode without a specific test case");
}
# --------------------------------------------------------------------------
# Embedded server flag
# --------------------------------------------------------------------------
if ( $opt_embedded_server )
{
$glob_use_embedded_server= 1;
push(@glob_test_mode, "embedded");
$opt_skip_rpl= 1; # We never run replication with embedded
$opt_skip_ndbcluster= 1; # Turn off use of NDB cluster
$opt_skip_ssl= 1; # Turn off use of SSL
if ( $opt_extern )
{
mtr_error("Can't use --extern with --embedded-server");
}
}
# --------------------------------------------------------------------------
# ps protcol flag
# --------------------------------------------------------------------------
if ( $opt_ps_protocol )
{
push(@glob_test_mode, "ps-protocol");
}
# --------------------------------------------------------------------------
# Ndb cluster flags
# --------------------------------------------------------------------------
if ( $opt_with_ndbcluster and !$opt_bench)
{
mtr_error("Can only use --with-ndbcluster togheter with --bench");
}
if ( $opt_ndbconnectstring )
{
$glob_use_running_ndbcluster= 1;
mtr_error("Can't specify --ndb-connectstring and --skip-ndbcluster")
if $opt_skip_ndbcluster;
mtr_error("Can't specify --ndb-connectstring and --ndbcluster-port")
if $opt_ndbcluster_port;
}
else
{
# Set default connect string
$opt_ndbconnectstring= "host=localhost:$opt_ndbcluster_port";
}
if ( $opt_ndbconnectstring_slave )
{
$glob_use_running_ndbcluster_slave= 1;
mtr_error("Can't specify ndb-connectstring_slave and " .
"--skip-ndbcluster-slave")
if $opt_skip_ndbcluster;
mtr_error("Can't specify --ndb-connectstring-slave and " .
"--ndbcluster-port-slave")
if $opt_ndbcluster_port_slave;
}
else
{
# Set default connect string
$opt_ndbconnectstring_slave= "host=localhost:$opt_ndbcluster_port_slave";
}
# --------------------------------------------------------------------------
# Bench flags
# --------------------------------------------------------------------------
if ( $opt_small_bench )
{
$opt_bench= 1;
}
# --------------------------------------------------------------------------
# Big test flags
# --------------------------------------------------------------------------
if ( $opt_big_test )
{
$ENV{'BIG_TEST'}= 1;
}
# --------------------------------------------------------------------------
# Gcov flag
# --------------------------------------------------------------------------
if ( $opt_gcov and ! $source_dist )
{
mtr_error("Coverage test needs the source - please use source dist");
}
# --------------------------------------------------------------------------
# Check debug related options
# --------------------------------------------------------------------------
if ( $opt_gdb || $opt_client_gdb || $opt_ddd || $opt_client_ddd ||
$opt_manual_gdb || $opt_manual_ddd || $opt_manual_debug ||
$opt_debugger || $opt_client_debugger )
{
# Indicate that we are using debugger
$glob_debugger= 1;
if ( $opt_extern )
{
mtr_error("Can't use --extern when using debugger");
}
}
# --------------------------------------------------------------------------
# Check if special exe was selected for master or slave
# --------------------------------------------------------------------------
$exe_master_mysqld= $exe_master_mysqld || $exe_mysqld;
$exe_slave_mysqld= $exe_slave_mysqld || $exe_mysqld;
# --------------------------------------------------------------------------
# Check valgrind arguments
# --------------------------------------------------------------------------
if ( $opt_valgrind or $opt_valgrind_path or defined $opt_valgrind_options)
{
mtr_report("Turning on valgrind for all executables");
$opt_valgrind= 1;
$opt_valgrind_mysqld= 1;
$opt_valgrind_mysqltest= 1;
}
elsif ( $opt_valgrind_mysqld )
{
mtr_report("Turning on valgrind for mysqld(s) only");
$opt_valgrind= 1;
}
elsif ( $opt_valgrind_mysqltest )
{
mtr_report("Turning on valgrind for mysqltest and mysql_client_test only");
$opt_valgrind= 1;
}
if ( $opt_callgrind )
{
mtr_report("Turning on valgrind with callgrind for mysqld(s)");
$opt_valgrind= 1;
$opt_valgrind_mysqld= 1;
# Set special valgrind options unless options passed on command line
$opt_valgrind_options="--trace-children=yes"
unless defined $opt_valgrind_options;
}
if ( $opt_valgrind )
{
# Set valgrind_options to default unless already defined
$opt_valgrind_options=$default_valgrind_options
unless defined $opt_valgrind_options;
mtr_report("Running valgrind with options \"$opt_valgrind_options\"");
}
if ( ! $opt_testcase_timeout )
{
$opt_testcase_timeout= $default_testcase_timeout;
$opt_testcase_timeout*= 10 if $opt_valgrind;
}
if ( ! $opt_suite_timeout )
{
$opt_suite_timeout= $default_suite_timeout;
$opt_suite_timeout*= 6 if $opt_valgrind;
}
if ( ! $opt_user )
{
if ( $opt_extern )
{
$opt_user= "test";
}
else
{
$opt_user= "root"; # We want to do FLUSH xxx commands
}
}
# On QNX, /tmp/dir/master.sock and /tmp/dir//master.sock seem to be
# considered different, so avoid the extra slash (/) in the socket
# paths.
my $sockdir = $opt_tmpdir;
$sockdir =~ s|/+$||;
# Put this into a hash, will be a C struct
$master->[0]=
{
pid => 0,
type => "master",
idx => 0,
path_myddir => "$opt_vardir/master-data",
path_myerr => "$opt_vardir/log/master.err",
path_mylog => "$opt_vardir/log/master.log",
path_pid => "$opt_vardir/run/master.pid",
path_sock => "$sockdir/master.sock",
port => $opt_master_myport,
start_timeout => 400, # enough time create innodb tables
cluster => 0, # index in clusters list
start_opts => [],
};
$master->[1]=
{
pid => 0,
type => "master",
idx => 1,
path_myddir => "$opt_vardir/master1-data",
path_myerr => "$opt_vardir/log/master1.err",
path_mylog => "$opt_vardir/log/master1.log",
path_pid => "$opt_vardir/run/master1.pid",
path_sock => "$sockdir/master1.sock",
port => $opt_master_myport + 1,
start_timeout => 400, # enough time create innodb tables
cluster => 0, # index in clusters list
start_opts => [],
};
$slave->[0]=
{
pid => 0,
type => "slave",
idx => 0,
path_myddir => "$opt_vardir/slave-data",
path_myerr => "$opt_vardir/log/slave.err",
path_mylog => "$opt_vardir/log/slave.log",
path_pid => "$opt_vardir/run/slave.pid",
path_sock => "$sockdir/slave.sock",
port => $opt_slave_myport,
start_timeout => 400,
cluster => 1, # index in clusters list
start_opts => [],
};
$slave->[1]=
{
pid => 0,
type => "slave",
idx => 1,
path_myddir => "$opt_vardir/slave1-data",
path_myerr => "$opt_vardir/log/slave1.err",
path_mylog => "$opt_vardir/log/slave1.log",
path_pid => "$opt_vardir/run/slave1.pid",
path_sock => "$sockdir/slave1.sock",
port => $opt_slave_myport + 1,
start_timeout => 300,
cluster => -1, # index in clusters list
start_opts => [],
};
$slave->[2]=
{
pid => 0,
type => "slave",
idx => 2,
path_myddir => "$opt_vardir/slave2-data",
path_myerr => "$opt_vardir/log/slave2.err",
path_mylog => "$opt_vardir/log/slave2.log",
path_pid => "$opt_vardir/run/slave2.pid",
path_sock => "$sockdir/slave2.sock",
port => $opt_slave_myport + 2,
start_timeout => 300,
cluster => -1, # index in clusters list
start_opts => [],
};
$instance_manager=
{
path_err => "$opt_vardir/log/im.err",
path_log => "$opt_vardir/log/im.log",
path_pid => "$opt_vardir/run/im.pid",
path_angel_pid => "$opt_vardir/run/im.angel.pid",
path_sock => "$sockdir/im.sock",
port => $im_port,
start_timeout => $master->[0]->{'start_timeout'},
admin_login => 'im_admin',
admin_password => 'im_admin_secret',
admin_sha1 => '*598D51AD2DFF7792045D6DF3DDF9AA1AF737B295',
password_file => "$opt_vardir/im.passwd",
defaults_file => "$opt_vardir/im.cnf",
};
$instance_manager->{'instances'}->[0]=
{
server_id => 1,
port => $im_mysqld1_port,
path_datadir => "$opt_vardir/im_mysqld_1.data",
path_sock => "$sockdir/mysqld_1.sock",
path_pid => "$opt_vardir/run/mysqld_1.pid",
start_timeout => 400, # enough time create innodb tables
old_log_format => 1
};
$instance_manager->{'instances'}->[1]=
{
server_id => 2,
port => $im_mysqld2_port,
path_datadir => "$opt_vardir/im_mysqld_2.data",
path_sock => "$sockdir/mysqld_2.sock",
path_pid => "$opt_vardir/run/mysqld_2.pid",
nonguarded => 1,
start_timeout => 400, # enough time create innodb tables
old_log_format => 1
};
my $data_dir= "$opt_vardir/ndbcluster-$opt_ndbcluster_port";
$clusters->[0]=
{
name => "Master",
nodes => 2,
port => "$opt_ndbcluster_port",
data_dir => "$data_dir",
connect_string => "$opt_ndbconnectstring",
path_pid => "$data_dir/ndb_3.pid", # Nodes + 1
pid => 0, # pid of ndb_mgmd
installed_ok => 0,
};
$data_dir= "$opt_vardir/ndbcluster-$opt_ndbcluster_port_slave";
$clusters->[1]=
{
name => "Slave",
nodes => 1,
port => "$opt_ndbcluster_port_slave",
data_dir => "$data_dir",
connect_string => "$opt_ndbconnectstring_slave",
path_pid => "$data_dir/ndb_2.pid", # Nodes + 1
pid => 0, # pid of ndb_mgmd
installed_ok => 0,
};
# Init pids of ndbd's
foreach my $cluster ( @{$clusters} )
{
for ( my $idx= 0; $idx < $cluster->{'nodes'}; $idx++ )
{
my $nodeid= $idx+1;
$cluster->{'ndbds'}->[$idx]=
{
pid => 0,
nodeid => $nodeid,
path_pid => "$cluster->{'data_dir'}/ndb_${nodeid}.pid",
path_fs => "$cluster->{'data_dir'}/ndb_${nodeid}_fs",
};
}
}
if ( $opt_extern )
{
# Turn off features not supported when running with extern server
$opt_skip_rpl= 1;
# Setup master->[0] with the settings for the extern server
$master->[0]->{'path_sock'}= $opt_socket if $opt_socket;
}
else
{
mtr_error("--socket can only be used in combination with --extern")
if $opt_socket;
}
$path_timefile= "$opt_vardir/log/mysqltest-time";
$path_mysqltest_log= "$opt_vardir/log/mysqltest.log";
$path_current_test_log= "$opt_vardir/log/current_test";
$path_ndb_testrun_log= "$opt_vardir/log/ndb_testrun.log";
$path_snapshot= "$opt_tmpdir/snapshot_$opt_master_myport/";
}
sub datadir_setup () {
# Make a list of all data_dirs
@data_dir_lst = (
$master->[0]->{'path_myddir'},
$master->[1]->{'path_myddir'});
for (my $idx= 0; $idx < $max_slave_num; $idx++)
{
push(@data_dir_lst, $slave->[$idx]->{'path_myddir'});
}
unless ($opt_skip_im)
{
foreach my $instance (@{$instance_manager->{'instances'}})
{
push(@data_dir_lst, $instance->{'path_datadir'});
}
}
}
##############################################################################
#
# Set paths to various executable programs
#
##############################################################################
sub collect_mysqld_features () {
#
# Execute "mysqld --no-defaults --help --verbose", that will
# print out version and a list of all features and settings
#
my $found_variable_list_start= 0;
my $spec_file= "$glob_mysql_test_dir/mysqld.spec.$$";
if ( mtr_run($exe_mysqld,
["--no-defaults",
"--verbose",
"--help"],
"", "$spec_file", "$spec_file", "") != 0 )
{
mtr_error("Failed to get version and list of features from %s",
$exe_mysqld);
}
my $F= IO::File->new($spec_file) or
mtr_error("can't open file \"$spec_file\": $!");
while ( my $line= <$F> )
{
# First look for version
if ( !$mysql_version_id )
{
# Look for version
my $exe_name= basename($exe_mysqld);
mtr_verbose("exe_name: $exe_name");
if ( $line =~ /^\S*$exe_name\s\sVer\s([0-9]*)\.([0-9]*)\.([0-9]*)/ )
{
#print "Major: $1 Minor: $2 Build: $3\n";
$mysql_version_id= $1*10000 + $2*100 + $3;
#print "mysql_version_id: $mysql_version_id\n";
mtr_report("MySQL Version $1.$2.$3");
}
}
else
{
if (!$found_variable_list_start)
{
# Look for start of variables list
if ( $line =~ /[\-]+\s[\-]+/ )
{
$found_variable_list_start= 1;
}
}
else
{
# Put variables into hash
if ( $line =~ /^([\S]+)[ \t]+(.*?)\r?$/ )
{
# print "$1=\"$2\"\n";
$mysqld_variables{$1}= $2;
}
else
{
# The variable list is ended with a blank line
if ( $line =~ /^[\s]*$/ )
{
last;
}
else
{
# Send out a warning, we should fix the variables that has no
# space between variable name and it's value
# or should it be fixed width column parsing? It does not
# look like that in function my_print_variables in my_getopt.c
mtr_warning("Could not parse variable list line : $line");
}
}
}
}
}
unlink($spec_file);
mtr_error("Could not find version of MySQL") unless $mysql_version_id;
mtr_error("Could not find variabes list") unless $found_variable_list_start;
}
sub executable_setup_im () {
# Look for instance manager binary - mysqlmanager
$exe_im=
mtr_exe_maybe_exists(
"$glob_basedir/server-tools/instance-manager/mysqlmanager",
"$glob_basedir/libexec/mysqlmanager",
"$glob_basedir/bin/mysqlmanager",
"$glob_basedir/sbin/mysqlmanager");
return ($exe_im eq "");
}
sub executable_setup_ndb () {
# Look for ndb tols and binaries
my $ndb_path= mtr_file_exists("$glob_basedir/ndb",
"$glob_basedir/storage/ndb",
"$glob_basedir/bin");
$exe_ndbd=
mtr_exe_maybe_exists("$ndb_path/src/kernel/ndbd",
"$ndb_path/ndbd");
$exe_ndb_mgm=
mtr_exe_maybe_exists("$ndb_path/src/mgmclient/ndb_mgm",
"$ndb_path/ndb_mgm");
$exe_ndb_mgmd=
mtr_exe_maybe_exists("$ndb_path/src/mgmsrv/ndb_mgmd",
"$ndb_path/ndb_mgmd");
$exe_ndb_waiter=
mtr_exe_maybe_exists("$ndb_path/tools/ndb_waiter",
"$ndb_path/ndb_waiter");
# May not exist
$path_ndb_tools_dir= mtr_file_exists("$ndb_path/tools",
"$ndb_path");
# May not exist
$path_ndb_examples_dir=
mtr_file_exists("$ndb_path/ndbapi-examples",
"$ndb_path/examples");
# May not exist
$exe_ndb_example=
mtr_file_exists("$path_ndb_examples_dir/ndbapi_simple/ndbapi_simple");
return ( $exe_ndbd eq "" or
$exe_ndb_mgm eq "" or
$exe_ndb_mgmd eq "" or
$exe_ndb_waiter eq "");
}
sub executable_setup () {
#
# Check if libtool is available in this distribution/clone
# we need it when valgrinding or debugging non installed binary
# Otherwise valgrind will valgrind the libtool wrapper or bash
# and gdb will not find the real executable to debug
#
if ( -x "../libtool")
{
$exe_libtool= "../libtool";
if ($opt_valgrind or $glob_debugger)
{
mtr_report("Using \"$exe_libtool\" when running valgrind or debugger");
}
}
# Look for language files and charsetsdir, use same share
my $path_share= mtr_path_exists("$glob_basedir/share/mysql",
"$glob_basedir/sql/share",
"$glob_basedir/share");
$path_language= mtr_path_exists("$path_share/english");
$path_charsetsdir= mtr_path_exists("$path_share/charsets");
# Look for my_print_defaults
$exe_my_print_defaults=
mtr_exe_exists(vs_config_dirs('extra', 'my_print_defaults'),
"$path_client_bindir/my_print_defaults",
"$glob_basedir/extra/my_print_defaults");
# Look for perror
$exe_perror= mtr_exe_exists(vs_config_dirs('extra', 'perror'),
"$glob_basedir/extra/perror",
"$path_client_bindir/perror");
# Look for the client binaries
$exe_mysqlcheck= mtr_exe_exists("$path_client_bindir/mysqlcheck");
$exe_mysqldump= mtr_exe_exists("$path_client_bindir/mysqldump");
$exe_mysqlimport= mtr_exe_exists("$path_client_bindir/mysqlimport");
$exe_mysqlshow= mtr_exe_exists("$path_client_bindir/mysqlshow");
$exe_mysqlbinlog= mtr_exe_exists("$path_client_bindir/mysqlbinlog");
$exe_mysqladmin= mtr_exe_exists("$path_client_bindir/mysqladmin");
$exe_mysql= mtr_exe_exists("$path_client_bindir/mysql");
if ( $mysql_version_id >= 50100 )
{
$exe_mysqlslap= mtr_exe_exists("$path_client_bindir/mysqlslap");
}
if ( $mysql_version_id >= 50000 and !$glob_use_embedded_server )
{
$exe_mysql_upgrade= mtr_exe_exists("$path_client_bindir/mysql_upgrade")
}
else
{
$exe_mysql_upgrade= "";
}
if ( ! $glob_win32 )
{
# Look for mysql_fix_system_table script
$exe_mysql_fix_system_tables=
mtr_script_exists("$glob_basedir/scripts/mysql_fix_privilege_tables",
"$path_client_bindir/mysql_fix_privilege_tables");
}
# Look for mysql_fix_privilege_tables.sql script
$file_mysql_fix_privilege_tables=
mtr_file_exists("$glob_basedir/scripts/mysql_fix_privilege_tables.sql",
"$glob_basedir/share/mysql_fix_privilege_tables.sql");
if ( ! $opt_skip_ndbcluster and executable_setup_ndb())
{
mtr_warning("Could not find all required ndb binaries, " .
"all ndb tests will fail, use --skip-ndbcluster to " .
"skip testing it.");
foreach my $cluster (@{$clusters})
{
$cluster->{"executable_setup_failed"}= 1;
}
}
if ( ! $opt_skip_im and executable_setup_im())
{
mtr_warning("Could not find all required instance manager binaries, " .
"all im tests will fail, use --skip-im to " .
"continue without instance manager");
$instance_manager->{"executable_setup_failed"}= 1;
}
# Look for the udf_example library
$lib_udf_example=
mtr_file_exists(vs_config_dirs('sql', 'udf_example.dll'),
"$glob_basedir/sql/.libs/udf_example.so",);
# Look for mysqltest executable
if ( $glob_use_embedded_server )
{
$exe_mysqltest=
mtr_exe_exists(vs_config_dirs('libmysqld/examples','mysqltest_embedded'),
"$glob_basedir/libmysqld/examples/mysqltest_embedded",
"$path_client_bindir/mysqltest_embedded");
}
else
{
$exe_mysqltest= mtr_exe_exists("$path_client_bindir/mysqltest");
}
# Look for mysql_client_test executable which may _not_ exist in
# some versions, test using it should be skipped
if ( $glob_use_embedded_server )
{
$exe_mysql_client_test=
mtr_exe_maybe_exists(
vs_config_dirs('libmysqld/examples', 'mysql_client_test_embedded'),
"$glob_basedir/libmysqld/examples/mysql_client_test_embedded");
}
else
{
$exe_mysql_client_test=
mtr_exe_maybe_exists(vs_config_dirs('tests', 'mysql_client_test'),
"$glob_basedir/tests/mysql_client_test",
"$glob_basedir/bin/mysql_client_test");
}
}
sub generate_cmdline_mysqldump ($) {
my($mysqld) = @_;
return
"$exe_mysqldump --no-defaults -uroot " .
"--port=$mysqld->{'port'} " .
"--socket=$mysqld->{'path_sock'} --password=";
}
##############################################################################
#
# Set environment to be used by childs of this process for
# things that are constant duting the whole lifetime of mysql-test-run.pl
#
##############################################################################
sub mysql_client_test_arguments()
{
my $exe= $exe_mysql_client_test;
my $args;
mtr_init_args(\$args);
if ( $opt_valgrind_mysqltest )
{
valgrind_arguments($args, \$exe);
}
mtr_add_arg($args, "--no-defaults");
mtr_add_arg($args, "--testcase");
mtr_add_arg($args, "--user=root");
mtr_add_arg($args, "--port=$master->[0]->{'port'}");
mtr_add_arg($args, "--socket=$master->[0]->{'path_sock'}");
if ( $mysql_version_id >= 50000 )
{
mtr_add_arg($args, "--vardir=$opt_vardir")
}
if ( $opt_debug )
{
mtr_add_arg($args,
"--debug=d:t:A,$path_vardir_trace/log/mysql_client_test.trace");
}
if ( $glob_use_embedded_server )
{
mtr_add_arg($args,
" -A --language=$path_language");
mtr_add_arg($args,
" -A --datadir=$slave->[0]->{'path_myddir'}");
mtr_add_arg($args,
" -A --character-sets-dir=$path_charsetsdir");
}
return join(" ", $exe, @$args);
}
sub mysql_upgrade_arguments()
{
my $exe= $exe_mysql_upgrade;
my $args;
mtr_init_args(\$args);
# if ( $opt_valgrind_mysql_ugrade )
# {
# valgrind_arguments($args, \$exe);
# }
mtr_add_arg($args, "--no-defaults");
mtr_add_arg($args, "--user=root");
mtr_add_arg($args, "--port=$master->[0]->{'port'}");
mtr_add_arg($args, "--socket=$master->[0]->{'path_sock'}");
mtr_add_arg($args, "--datadir=$master->[0]->{'path_myddir'}");
mtr_add_arg($args, "--basedir=$glob_basedir");
if ( $opt_debug )
{
mtr_add_arg($args,
"--debug=d:t:A,$path_vardir_trace/log/mysql_upgrade.trace");
}
return join(" ", $exe, @$args);
}
# Note that some env is setup in spawn/run, in "mtr_process.pl"
sub environment_setup () {
umask(022);
my @ld_library_paths;
# --------------------------------------------------------------------------
# Setup LD_LIBRARY_PATH so the libraries from this distro/clone
# are used in favor of the system installed ones
# --------------------------------------------------------------------------
if ( $source_dist )
{
push(@ld_library_paths, "$glob_basedir/libmysql/.libs/",
"$glob_basedir/libmysql_r/.libs/");
}
else
{
push(@ld_library_paths, "$glob_basedir/lib");
}
# --------------------------------------------------------------------------
# Add the path where libndbclient can be found
# --------------------------------------------------------------------------
if ( $glob_ndbcluster_supported )
{
push(@ld_library_paths, "$glob_basedir/storage/ndb/src/.libs");
}
# --------------------------------------------------------------------------
# Add the path where mysqld will find udf_example.so
# --------------------------------------------------------------------------
if ( $lib_udf_example )
{
push(@ld_library_paths, dirname($lib_udf_example));
}
# --------------------------------------------------------------------------
# Valgrind need to be run with debug libraries otherwise it's almost
# impossible to add correct supressions, that means if "/usr/lib/debug"
# is available, it should be added to
# LD_LIBRARY_PATH
#
# But pthread is broken in libc6-dbg on Debian <= 3.1 (see Debian
# bug 399035, http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=399035),
# so don't change LD_LIBRARY_PATH on that platform.
# --------------------------------------------------------------------------
my $debug_libraries_path= "/usr/lib/debug";
my $deb_version;
if ( $opt_valgrind and -d $debug_libraries_path and
(! -e '/etc/debian_version' or
($deb_version= mtr_grab_file('/etc/debian_version')) == 0 or
$deb_version > 3.1 ) )
{
push(@ld_library_paths, $debug_libraries_path);
}
$ENV{'LD_LIBRARY_PATH'}= join(":", @ld_library_paths,
$ENV{'LD_LIBRARY_PATHS'} ?
split(':', $ENV{'LD_LIBRARY_PATH'}) : ());
mtr_debug("LD_LIBRARY_PATH: $ENV{'LD_LIBRARY_PATH'}");
$ENV{'DYLD_LIBRARY_PATH'}= join(":", @ld_library_paths,
$ENV{'DYLD_LIBRARY_PATH'} ?
split(':', $ENV{'DYLD_LIBRARY_PATH'}) : ());
mtr_debug("DYLD_LIBRARY_PATH: $ENV{'DYLD_LIBRARY_PATH'}");
# --------------------------------------------------------------------------
# Also command lines in .opt files may contain env vars
# --------------------------------------------------------------------------
$ENV{'CHARSETSDIR'}= $path_charsetsdir;
$ENV{'UMASK'}= "0660"; # The octal *string*
$ENV{'UMASK_DIR'}= "0770"; # The octal *string*
$ENV{'LC_COLLATE'}= "C";
$ENV{'USE_RUNNING_SERVER'}= $opt_extern;
$ENV{'MYSQL_TEST_DIR'}= $glob_mysql_test_dir;
$ENV{'MYSQLTEST_VARDIR'}= $opt_vardir;
$ENV{'MYSQL_TMP_DIR'}= $opt_tmpdir;
$ENV{'MASTER_MYSOCK'}= $master->[0]->{'path_sock'};
$ENV{'MASTER_MYSOCK1'}= $master->[1]->{'path_sock'};
$ENV{'MASTER_MYPORT'}= $master->[0]->{'port'};
$ENV{'MASTER_MYPORT1'}= $master->[1]->{'port'};
$ENV{'SLAVE_MYSOCK'}= $slave->[0]->{'path_sock'};
$ENV{'SLAVE_MYPORT'}= $slave->[0]->{'port'};
$ENV{'SLAVE_MYPORT1'}= $slave->[1]->{'port'};
$ENV{'SLAVE_MYPORT2'}= $slave->[2]->{'port'};
$ENV{'MYSQL_TCP_PORT'}= $mysqld_variables{'port'};
$ENV{'IM_PATH_SOCK'}= $instance_manager->{path_sock};
$ENV{'IM_USERNAME'}= $instance_manager->{admin_login};
$ENV{'IM_PASSWORD'}= $instance_manager->{admin_password};
$ENV{MTR_BUILD_THREAD}= 0 unless $ENV{MTR_BUILD_THREAD}; # Set if not set
$ENV{'EXE_MYSQL'}= $exe_mysql;
# ----------------------------------------------------
# Setup env for NDB
# ----------------------------------------------------
if ( ! $opt_skip_ndbcluster )
{
$ENV{'NDB_MGM'}= $exe_ndb_mgm;
$ENV{'NDBCLUSTER_PORT'}= $opt_ndbcluster_port;
$ENV{'NDBCLUSTER_PORT_SLAVE'}= $opt_ndbcluster_port_slave;
$ENV{'NDB_EXTRA_TEST'}= $opt_ndb_extra_test;
$ENV{'NDB_BACKUP_DIR'}= $clusters->[0]->{'data_dir'};
$ENV{'NDB_DATA_DIR'}= $clusters->[0]->{'data_dir'};
$ENV{'NDB_TOOLS_DIR'}= $path_ndb_tools_dir;
$ENV{'NDB_TOOLS_OUTPUT'}= $path_ndb_testrun_log;
$ENV{'NDB_CONNECTSTRING'}= $opt_ndbconnectstring;
if ( $mysql_version_id >= 50000 )
{
$ENV{'NDB_EXAMPLES_DIR'}= $path_ndb_examples_dir;
$ENV{'MY_NDB_EXAMPLES_BINARY'}= $exe_ndb_example;
}
$ENV{'NDB_EXAMPLES_OUTPUT'}= $path_ndb_testrun_log;
}
# ----------------------------------------------------
# Setup env for IM
# ----------------------------------------------------
if ( ! $opt_skip_im )
{
$ENV{'IM_EXE'}= $exe_im;
$ENV{'IM_PATH_PID'}= $instance_manager->{path_pid};
$ENV{'IM_PATH_ANGEL_PID'}= $instance_manager->{path_angel_pid};
$ENV{'IM_PORT'}= $instance_manager->{port};
$ENV{'IM_DEFAULTS_PATH'}= $instance_manager->{defaults_file};
$ENV{'IM_PASSWORD_PATH'}= $instance_manager->{password_file};
$ENV{'IM_MYSQLD1_SOCK'}=
$instance_manager->{instances}->[0]->{path_sock};
$ENV{'IM_MYSQLD1_PORT'}=
$instance_manager->{instances}->[0]->{port};
$ENV{'IM_MYSQLD1_PATH_PID'}=
$instance_manager->{instances}->[0]->{path_pid};
$ENV{'IM_MYSQLD2_SOCK'}=
$instance_manager->{instances}->[1]->{path_sock};
$ENV{'IM_MYSQLD2_PORT'}=
$instance_manager->{instances}->[1]->{port};
$ENV{'IM_MYSQLD2_PATH_PID'}=
$instance_manager->{instances}->[1]->{path_pid};
}
# ----------------------------------------------------
# Setup env so childs can execute mysqlcheck
# ----------------------------------------------------
my $cmdline_mysqlcheck=
"$exe_mysqlcheck --no-defaults -uroot " .
"--port=$master->[0]->{'port'} " .
"--socket=$master->[0]->{'path_sock'} --password=";
if ( $opt_debug )
{
$cmdline_mysqlcheck .=
" --debug=d:t:A,$path_vardir_trace/log/mysqlcheck.trace";
}
$ENV{'MYSQL_CHECK'}= $cmdline_mysqlcheck;
# ----------------------------------------------------
# Setup env to childs can execute myqldump
# ----------------------------------------------------
my $cmdline_mysqldump= generate_cmdline_mysqldump($master->[0]);
my $cmdline_mysqldumpslave= generate_cmdline_mysqldump($slave->[0]);
if ( $opt_debug )
{
$cmdline_mysqldump .=
" --debug=d:t:A,$path_vardir_trace/log/mysqldump-master.trace";
$cmdline_mysqldumpslave .=
" --debug=d:t:A,$path_vardir_trace/log/mysqldump-slave.trace";
}
$ENV{'MYSQL_DUMP'}= $cmdline_mysqldump;
$ENV{'MYSQL_DUMP_SLAVE'}= $cmdline_mysqldumpslave;
# ----------------------------------------------------
# Setup env so childs can execute mysqlslap
# ----------------------------------------------------
if ( $exe_mysqlslap )
{
my $cmdline_mysqlslap=
"$exe_mysqlslap -uroot " .
"--port=$master->[0]->{'port'} " .
"--socket=$master->[0]->{'path_sock'} --password= " .
"--lock-directory=$opt_tmpdir";
if ( $opt_debug )
{
$cmdline_mysqlslap .=
" --debug=d:t:A,$path_vardir_trace/log/mysqlslap.trace";
}
$ENV{'MYSQL_SLAP'}= $cmdline_mysqlslap;
}
# ----------------------------------------------------
# Setup env so childs can execute mysqlimport
# ----------------------------------------------------
my $cmdline_mysqlimport=
"$exe_mysqlimport -uroot " .
"--port=$master->[0]->{'port'} " .
"--socket=$master->[0]->{'path_sock'} --password=";
if ( $opt_debug )
{
$cmdline_mysqlimport .=
" --debug=d:t:A,$path_vardir_trace/log/mysqlimport.trace";
}
$ENV{'MYSQL_IMPORT'}= $cmdline_mysqlimport;
# ----------------------------------------------------
# Setup env so childs can execute mysqlshow
# ----------------------------------------------------
my $cmdline_mysqlshow=
"$exe_mysqlshow -uroot " .
"--port=$master->[0]->{'port'} " .
"--socket=$master->[0]->{'path_sock'} --password=";
if ( $opt_debug )
{
$cmdline_mysqlshow .=
" --debug=d:t:A,$path_vardir_trace/log/mysqlshow.trace";
}
$ENV{'MYSQL_SHOW'}= $cmdline_mysqlshow;
# ----------------------------------------------------
# Setup env so childs can execute mysqlbinlog
# ----------------------------------------------------
my $cmdline_mysqlbinlog=
"$exe_mysqlbinlog" .
" --no-defaults --local-load=$opt_tmpdir";
if ( $mysql_version_id >= 50000 )
{
$cmdline_mysqlbinlog .=" --character-sets-dir=$path_charsetsdir";
}
if ( $opt_debug )
{
$cmdline_mysqlbinlog .=
" --debug=d:t:A,$path_vardir_trace/log/mysqlbinlog.trace";
}
$ENV{'MYSQL_BINLOG'}= $cmdline_mysqlbinlog;
# ----------------------------------------------------
# Setup env so childs can execute mysql
# ----------------------------------------------------
my $cmdline_mysql=
"$exe_mysql --no-defaults --host=localhost --user=root --password= " .
"--port=$master->[0]->{'port'} " .
"--socket=$master->[0]->{'path_sock'} ".
"--character-sets-dir=$path_charsetsdir";
$ENV{'MYSQL'}= $cmdline_mysql;
# ----------------------------------------------------
# Setup env so childs can execute mysql_client_test
# ----------------------------------------------------
$ENV{'MYSQL_CLIENT_TEST'}= mysql_client_test_arguments();
# ----------------------------------------------------
# Setup env so childs can execute mysql_upgrade
# ----------------------------------------------------
if ( $mysql_version_id >= 50000 )
{
$ENV{'MYSQL_UPGRADE'}= mysql_upgrade_arguments();
}
# ----------------------------------------------------
# Setup env so childs can execute mysql_fix_system_tables
# ----------------------------------------------------
if ( ! $glob_win32 )
{
my $cmdline_mysql_fix_system_tables=
"$exe_mysql_fix_system_tables --no-defaults --host=localhost " .
"--user=root --password= " .
"--basedir=$glob_basedir --bindir=$path_client_bindir --verbose " .
"--port=$master->[0]->{'port'} " .
"--socket=$master->[0]->{'path_sock'}";
$ENV{'MYSQL_FIX_SYSTEM_TABLES'}= $cmdline_mysql_fix_system_tables;
}
$ENV{'MYSQL_FIX_PRIVILEGE_TABLES'}= $file_mysql_fix_privilege_tables;
# ----------------------------------------------------
# Setup env so childs can execute my_print_defaults
# ----------------------------------------------------
$ENV{'MYSQL_MY_PRINT_DEFAULTS'}= $exe_my_print_defaults;
# ----------------------------------------------------
# Setup env so childs can execute perror
# ----------------------------------------------------
$ENV{'MY_PERROR'}= $exe_perror;
# ----------------------------------------------------
# Add the path where mysqld will find udf_example.so
# ----------------------------------------------------
$ENV{'UDF_EXAMPLE_LIB'}=
($lib_udf_example ? basename($lib_udf_example) : "");
$ENV{'LD_LIBRARY_PATH'}=
($lib_udf_example ? dirname($lib_udf_example) : "") .
($ENV{'LD_LIBRARY_PATH'} ? ":$ENV{'LD_LIBRARY_PATH'}" : "");
# ----------------------------------------------------
# We are nice and report a bit about our settings
# ----------------------------------------------------
if (!$opt_extern)
{
print "Using MTR_BUILD_THREAD = $ENV{MTR_BUILD_THREAD}\n";
print "Using MASTER_MYPORT = $ENV{MASTER_MYPORT}\n";
print "Using MASTER_MYPORT1 = $ENV{MASTER_MYPORT1}\n";
print "Using SLAVE_MYPORT = $ENV{SLAVE_MYPORT}\n";
print "Using SLAVE_MYPORT1 = $ENV{SLAVE_MYPORT1}\n";
print "Using SLAVE_MYPORT2 = $ENV{SLAVE_MYPORT2}\n";
if ( ! $opt_skip_ndbcluster )
{
print "Using NDBCLUSTER_PORT = $ENV{NDBCLUSTER_PORT}\n";
if ( ! $opt_skip_ndbcluster_slave )
{
print "Using NDBCLUSTER_PORT_SLAVE = $ENV{NDBCLUSTER_PORT_SLAVE}\n";
}
}
if ( ! $opt_skip_im )
{
print "Using IM_PORT = $ENV{IM_PORT}\n";
print "Using IM_MYSQLD1_PORT = $ENV{IM_MYSQLD1_PORT}\n";
print "Using IM_MYSQLD2_PORT = $ENV{IM_MYSQLD2_PORT}\n";
}
}
# Create an environment variable to make it possible
# to detect that valgrind is being used from test cases
$ENV{'VALGRIND_TEST'}= $opt_valgrind;
}
##############################################################################
#
# If we get a ^C, we try to clean up before termination
#
##############################################################################
# FIXME check restrictions what to do in a signal handler
sub signal_setup () {
$SIG{INT}= \&handle_int_signal;
}
sub handle_int_signal () {
$SIG{INT}= 'DEFAULT'; # If we get a ^C again, we die...
mtr_warning("got INT signal, cleaning up.....");
stop_all_servers();
mtr_error("We die from ^C signal from user");
}
##############################################################################
#
# Handle left overs from previous runs
#
##############################################################################
sub kill_running_servers () {
if ( $opt_fast or $glob_use_embedded_server )
{
# FIXME is embedded server really using PID files?!
unlink($master->[0]->{'path_pid'});
unlink($master->[1]->{'path_pid'});
unlink($slave->[0]->{'path_pid'});
unlink($slave->[1]->{'path_pid'});
unlink($slave->[2]->{'path_pid'});
}
else
{
# Ensure that no old mysqld test servers are running
# This is different from terminating processes we have
# started from this run of the script, this is terminating
# leftovers from previous runs.
if ( ! -d $opt_vardir )
{
if ( -l $opt_vardir and ! -d readlink($opt_vardir) )
{
mtr_report("Removing $opt_vardir symlink without destination");
unlink($opt_vardir);
}
# The "var" dir does not exist already
# the processes that mtr_kill_leftovers start will write
# their log files to var/log so it should be created
mkpath("$opt_vardir/log");
}
mtr_kill_leftovers();
}
}
sub cleanup_stale_files () {
my $created_by_mem_file= "$glob_mysql_test_dir/var/created_by_mem";
mtr_report("Removing Stale Files");
if ( $opt_vardir eq $default_vardir )
{
#
# Running with "var" in mysql-test dir
#
if ( -l $opt_vardir)
{
# var is a symlink
if (-f $created_by_mem_file)
{
# Remove the directory which the link points at
rmtree(readlink($opt_vardir));
# Remove the entire "var" dir
rmtree("$opt_vardir/");
# Remove the "var" symlink
unlink($opt_vardir);
}
else
{
# Some users creates a soft link in mysql-test/var to another area
# - allow it
mtr_report("WARNING: Using the 'mysql-test/var' symlink");
rmtree("$opt_vardir/log");
rmtree("$opt_vardir/ndbcluster-$opt_ndbcluster_port");
rmtree("$opt_vardir/run");
rmtree("$opt_vardir/tmp");
}
}
else
{
# Remove the entire "var" dir
rmtree("$opt_vardir/");
}
}
else
{
#
# Running with "var" in some other place
#
# Remove the var/ dir in mysql-test dir if any
# this could be an old symlink that shouldn't be there
rmtree($default_vardir);
# Remove the "var" dir
rmtree("$opt_vardir/");
}
if ( $opt_mem )
{
# Runinng with var as a link to some "memory" location, normally tmpfs
rmtree($opt_mem);
mkpath($opt_mem);
mtr_report("Creating symlink from $opt_vardir to $opt_mem");
symlink($opt_mem, $opt_vardir);
# Put a small file to recognize this dir was created by --mem
mtr_tofile($created_by_mem_file, $opt_mem);
}
mkpath("$opt_vardir/log");
mkpath("$opt_vardir/run");
mkpath("$opt_vardir/tmp");
mkpath($opt_tmpdir) if $opt_tmpdir ne "$opt_vardir/tmp";
# Remove old and create new data dirs
foreach my $data_dir (@data_dir_lst)
{
rmtree("$data_dir");
mkpath("$data_dir/mysql");
mkpath("$data_dir/test");
}
# Make a link std_data_ln in var/ that points to std_data
if ( ! $glob_win32 )
{
symlink("$glob_mysql_test_dir/std_data", "$opt_vardir/std_data_ln");
}
else
{
# on windows, copy all files from std_data into var/std_data_ln
mkpath("$opt_vardir/std_data_ln");
opendir(DIR, "$glob_mysql_test_dir/std_data")
or mtr_error("Can't find the std_data directory: $!");
for(readdir(DIR)) {
next if -d "$glob_mysql_test_dir/std_data/$_";
copy("$glob_mysql_test_dir/std_data/$_", "$opt_vardir/std_data_ln/$_");
}
closedir(DIR);
}
}
sub check_running_as_root () {
# Check if running as root
# i.e a file can be read regardless what mode we set it to
my $test_file= "$opt_vardir/test_running_as_root.txt";
mtr_tofile($test_file, "MySQL");
chmod(oct("0000"), $test_file);
my $result="";
if (open(FILE,"<",$test_file))
{
$result= join('', );
close FILE;
}
chmod(oct("0755"), $test_file);
unlink($test_file);
$ENV{'MYSQL_TEST_ROOT'}= "NO";
if ($result eq "MySQL")
{
mtr_warning("running this script as _root_ will cause some " .
"tests to be skipped");
$ENV{'MYSQL_TEST_ROOT'}= "YES";
}
}
sub check_ssl_support ($) {
my $mysqld_variables= shift;
if ($opt_skip_ssl || $opt_extern)
{
mtr_report("Skipping SSL");
$opt_ssl_supported= 0;
$opt_ssl= 0;
return;
}
if ( ! $mysqld_variables->{'ssl'} )
{
if ( $opt_ssl)
{
mtr_error("Couldn't find support for SSL");
return;
}
mtr_report("Skipping SSL, mysqld not compiled with SSL");
$opt_ssl_supported= 0;
$opt_ssl= 0;
return;
}
mtr_report("Setting mysqld to support SSL connections");
$opt_ssl_supported= 1;
}
sub check_debug_support ($) {
my $mysqld_variables= shift;
if ( ! $mysqld_variables->{'debug'} )
{
#mtr_report("Binaries are not debug compiled");
$debug_compiled_binaries= 0;
if ( $opt_debug )
{
mtr_error("Can't use --debug, binaries does not support it");
}
return;
}
mtr_report("Binaries are debug compiled");
$debug_compiled_binaries= 1;
}
##############################################################################
#
# Helper function to handle configuration-based subdirectories which Visual
# Studio uses for storing binaries. If opt_vs_config is set, this returns
# a path based on that setting; if not, it returns paths for the default
# /release/ and /debug/ subdirectories.
#
# $exe can be undefined, if the directory itself will be used
#
###############################################################################
sub vs_config_dirs ($$) {
my ($path_part, $exe) = @_;
$exe = "" if not defined $exe;
if ($opt_vs_config)
{
return ("$glob_basedir/$path_part/$opt_vs_config/$exe");
}
return ("$glob_basedir/$path_part/release/$exe",
"$glob_basedir/$path_part/debug/$exe");
}
##############################################################################
#
# Start the ndb cluster
#
##############################################################################
sub check_ndbcluster_support ($) {
my $mysqld_variables= shift;
if ($opt_skip_ndbcluster)
{
mtr_report("Skipping ndbcluster");
$opt_skip_ndbcluster_slave= 1;
return;
}
if ( ! $mysqld_variables->{'ndb-connectstring'} )
{
mtr_report("Skipping ndbcluster, mysqld not compiled with ndbcluster");
$opt_skip_ndbcluster= 1;
$opt_skip_ndbcluster_slave= 1;
return;
}
$glob_ndbcluster_supported= 1;
mtr_report("Using ndbcluster when necessary, mysqld supports it");
if ( $mysql_version_id < 50100 )
{
# Slave cluster is not supported until 5.1
$opt_skip_ndbcluster_slave= 1;
}
return;
}
sub ndbcluster_start_install ($) {
my $cluster= shift;
mtr_report("Installing $cluster->{'name'} Cluster");
mkdir($cluster->{'data_dir'});
# Create a config file from template
my $ndb_no_ord=512;
my $ndb_no_attr=2048;
my $ndb_con_op=105000;
my $ndb_dmem="80M";
my $ndb_imem="24M";
my $ndb_pbmem="32M";
my $nodes= $cluster->{'nodes'};
my $ndb_host= "localhost";
my $ndb_diskless= 0;
if (!$opt_bench)
{
# Use a smaller configuration
if ( $mysql_version_id < 50100 )
{
# 4.1 and 5.0 is using a "larger" --small configuration
$ndb_no_ord=128;
$ndb_con_op=10000;
$ndb_dmem="40M";
$ndb_imem="12M";
}
else
{
$ndb_no_ord=32;
$ndb_con_op=5000;
$ndb_dmem="20M";
$ndb_imem="1M";
$ndb_pbmem="4M";
}
}
my $config_file_template= "ndb/ndb_config_${nodes}_node.ini";
my $config_file= "$cluster->{'data_dir'}/config.ini";
open(IN, $config_file_template)
or mtr_error("Can't open $config_file_template: $!");
open(OUT, ">", $config_file)
or mtr_error("Can't write to $config_file: $!");
while ()
{
chomp;
s/CHOOSE_MaxNoOfAttributes/$ndb_no_attr/;
s/CHOOSE_MaxNoOfOrderedIndexes/$ndb_no_ord/;
s/CHOOSE_MaxNoOfConcurrentOperations/$ndb_con_op/;
s/CHOOSE_DataMemory/$ndb_dmem/;
s/CHOOSE_IndexMemory/$ndb_imem/;
s/CHOOSE_Diskless/$ndb_diskless/;
s/CHOOSE_HOSTNAME_.*/$ndb_host/;
s/CHOOSE_FILESYSTEM/$cluster->{'data_dir'}/;
s/CHOOSE_PORT_MGM/$cluster->{'port'}/;
if ( $mysql_version_id < 50000 )
{
my $base_port= $cluster->{'port'} + 1;
s/CHOOSE_PORT_TRANSPORTER/$base_port/;
}
s/CHOOSE_DiskPageBufferMemory/$ndb_pbmem/;
print OUT "$_ \n";
}
close OUT;
close IN;
# Start cluster with "--initial"
ndbcluster_start($cluster, "--initial");
return 0;
}
sub ndbcluster_wait_started($$){
my $cluster= shift;
my $ndb_waiter_extra_opt= shift;
my $path_waiter_log= "$cluster->{'data_dir'}/ndb_waiter.log";
my $args;
mtr_init_args(\$args);
mtr_add_arg($args, "--no-defaults");
mtr_add_arg($args, "--core");
mtr_add_arg($args, "--ndb-connectstring=%s", $cluster->{'connect_string'});
mtr_add_arg($args, "--timeout=60");
if ($ndb_waiter_extra_opt)
{
mtr_add_arg($args, "$ndb_waiter_extra_opt");
}
# Start the ndb_waiter which will connect to the ndb_mgmd
# and poll it for state of the ndbd's, will return when
# all nodes in the cluster is started
my $res= mtr_run($exe_ndb_waiter, $args,
"", $path_waiter_log, $path_waiter_log, "");
mtr_verbose("ndbcluster_wait_started, returns: $res") if $res;
return $res;
}
sub mysqld_wait_started($){
my $mysqld= shift;
my $res= sleep_until_file_created($mysqld->{'path_pid'},
$mysqld->{'start_timeout'},
$mysqld->{'pid'});
return $res == 0;
}
sub ndb_mgmd_wait_started($) {
my ($cluster)= @_;
my $retries= 100;
while (ndbcluster_wait_started($cluster, "--no-contact") and
$retries)
{
# Millisceond sleep emulated with select
select(undef, undef, undef, (0.1));
$retries--;
}
return $retries == 0;
}
sub ndb_mgmd_start ($) {
my $cluster= shift;
my $args; # Arg vector
my $pid= -1;
mtr_init_args(\$args);
mtr_add_arg($args, "--no-defaults");
mtr_add_arg($args, "--core");
mtr_add_arg($args, "--nodaemon");
mtr_add_arg($args, "--config-file=%s", "$cluster->{'data_dir'}/config.ini");
my $path_ndb_mgmd_log= "$cluster->{'data_dir'}/\l$cluster->{'name'}_ndb_mgmd.log";
$pid= mtr_spawn($exe_ndb_mgmd, $args, "",
$path_ndb_mgmd_log,
$path_ndb_mgmd_log,
"",
{ append_log_file => 1 });
# FIXME Should not be needed
# Unfortunately the cluster nodes will fail to start
# if ndb_mgmd has not started properly
if (ndb_mgmd_wait_started($cluster))
{
mtr_error("Failed to wait for start of ndb_mgmd");
}
# Remember pid of ndb_mgmd
$cluster->{'pid'}= $pid;
mtr_verbose("ndb_mgmd_start, pid: $pid");
return $pid;
}
sub ndbd_start ($$$) {
my $cluster= shift;
my $idx= shift;
my $extra_args= shift;
my $args; # Arg vector
my $pid= -1;
mtr_init_args(\$args);
mtr_add_arg($args, "--no-defaults");
mtr_add_arg($args, "--core");
mtr_add_arg($args, "--ndb-connectstring=%s", "$cluster->{'connect_string'}");
if ( $mysql_version_id >= 50000)
{
mtr_add_arg($args, "--character-sets-dir=%s", "$path_charsetsdir");
}
mtr_add_arg($args, "--nodaemon");
mtr_add_arg($args, "$extra_args");
my $nodeid= $cluster->{'ndbds'}->[$idx]->{'nodeid'};
my $path_ndbd_log= "$cluster->{'data_dir'}/ndb_${nodeid}.log";
$pid= mtr_spawn($exe_ndbd, $args, "",
$path_ndbd_log,
$path_ndbd_log,
"",
{ append_log_file => 1 });
# Add pid to list of pids for this cluster
$cluster->{'ndbds'}->[$idx]->{'pid'}= $pid;
# Rememeber options used when starting
$cluster->{'ndbds'}->[$idx]->{'start_extra_args'}= $extra_args;
$cluster->{'ndbds'}->[$idx]->{'idx'}= $idx;
mtr_verbose("ndbd_start, pid: $pid");
return $pid;
}
sub ndbcluster_start ($$) {
my $cluster= shift;
my $extra_args= shift;
mtr_verbose("ndbcluster_start '$cluster->{'name'}'");
if ( $glob_use_running_ndbcluster )
{
return 0;
}
if ( $cluster->{'pid'} )
{
mtr_error("Cluster '$cluster->{'name'}' already started");
}
ndb_mgmd_start($cluster);
for ( my $idx= 0; $idx < $cluster->{'nodes'}; $idx++ )
{
ndbd_start($cluster, $idx, $extra_args);
}
return 0;
}
sub rm_ndbcluster_tables ($) {
my $dir= shift;
foreach my $bin ( glob("$dir/cluster/apply_status*"),
glob("$dir/cluster/schema*") )
{
unlink($bin);
}
}
##############################################################################
#
# Run the benchmark suite
#
##############################################################################
sub run_benchmarks ($) {
my $benchmark= shift;
my $args;
if ( ! $glob_use_embedded_server )
{
mysqld_start($master->[0],[],[]);
if ( ! $master->[0]->{'pid'} )
{
mtr_error("Can't start the mysqld server");
}
}
mtr_init_args(\$args);
mtr_add_arg($args, "--socket=%s", $master->[0]->{'path_sock'});
mtr_add_arg($args, "--user=%s", $opt_user);
if ( $opt_small_bench )
{
mtr_add_arg($args, "--small-test");
mtr_add_arg($args, "--small-tables");
}
if ( $opt_with_ndbcluster )
{
mtr_add_arg($args, "--create-options=TYPE=ndb");
}
chdir($glob_mysql_bench_dir)
or mtr_error("Couldn't chdir to '$glob_mysql_bench_dir': $!");
if ( ! $benchmark )
{
mtr_add_arg($args, "--log");
mtr_run("$glob_mysql_bench_dir/run-all-tests", $args, "", "", "", "");
# FIXME check result code?!
}
elsif ( -x $benchmark )
{
mtr_run("$glob_mysql_bench_dir/$benchmark", $args, "", "", "", "");
# FIXME check result code?!
}
else
{
mtr_error("Benchmark $benchmark not found");
}
chdir($glob_mysql_test_dir); # Go back
if ( ! $glob_use_embedded_server )
{
stop_masters();
}
}
##############################################################################
#
# Run the test suite
#
##############################################################################
sub run_suite () {
my ($suite, $tests)= @_;
mtr_print_thick_line();
mtr_timer_start($glob_timers,"suite", 60 * $opt_suite_timeout);
mtr_report("Starting Tests in the '$suite' suite");
mtr_report_tests_not_skipped_though_disabled($tests);
mtr_print_header();
foreach my $tinfo ( @$tests )
{
if (run_testcase_check_skip_test($tinfo))
{
next;
}
mtr_timer_start($glob_timers,"testcase", 60 * $opt_testcase_timeout);
run_testcase($tinfo);
mtr_timer_stop($glob_timers,"testcase");
}
mtr_print_line();
if ( ! $glob_debugger and
! $opt_extern and
! $glob_use_embedded_server )
{
stop_all_servers();
}
if ( $opt_gcov )
{
gcov_collect(); # collect coverage information
}
if ( $opt_gprof )
{
gprof_collect(); # collect coverage information
}
mtr_report_stats($tests);
mtr_timer_stop($glob_timers,"suite");
}
##############################################################################
#
# Initiate the test databases
#
##############################################################################
sub initialize_servers () {
datadir_setup();
if ( ! $opt_extern )
{
kill_running_servers();
if ( ! $opt_start_dirty )
{
cleanup_stale_files();
mysql_install_db();
if ( $opt_force )
{
save_installed_db();
}
}
check_running_as_root();
}
}
sub mysql_install_db () {
install_db('master', $master->[0]->{'path_myddir'});
# FIXME check if testcase really is using second master
copy_install_db('master', $master->[1]->{'path_myddir'});
# Install the number of slave databses needed
for (my $idx= 0; $idx < $max_slave_num; $idx++)
{
copy_install_db("slave".($idx+1), $slave->[$idx]->{'path_myddir'});
}
if ( ! $opt_skip_im )
{
im_prepare_env($instance_manager);
}
my $cluster_started_ok= 1; # Assume it can be started
if ($opt_skip_ndbcluster || $glob_use_running_ndbcluster ||
$clusters->[0]->{executable_setup_failed})
{
# Don't install master cluster
}
elsif (ndbcluster_start_install($clusters->[0]))
{
mtr_warning("Failed to start install of $clusters->[0]->{name}");
$cluster_started_ok= 0;
}
if ($max_slave_num == 0 ||
$opt_skip_ndbcluster_slave || $glob_use_running_ndbcluster_slave ||
$clusters->[1]->{executable_setup_failed})
{
# Don't install slave cluster
}
elsif (ndbcluster_start_install($clusters->[1]))
{
mtr_warning("Failed to start install of $clusters->[1]->{name}");
$cluster_started_ok= 0;
}
foreach my $cluster (@{$clusters})
{
next if !$cluster->{'pid'};
$cluster->{'installed_ok'}= 1; # Assume install suceeds
if (ndbcluster_wait_started($cluster, ""))
{
# failed to install, disable usage and flag that its no ok
mtr_report("ndbcluster_install of $cluster->{'name'} failed");
$cluster->{"installed_ok"}= 0;
$cluster_started_ok= 0;
}
}
if ( ! $cluster_started_ok )
{
if ( $opt_force)
{
# Continue without cluster
}
else
{
mtr_error("To continue, re-run with '--force'.");
}
}
return 0;
}
sub copy_install_db ($$) {
my $type= shift;
my $data_dir= shift;
mtr_report("Installing \u$type Database");
# Just copy the installed db from first master
mtr_copy_dir($master->[0]->{'path_myddir'}, $data_dir);
}
sub install_db ($$) {
my $type= shift;
my $data_dir= shift;
my $init_db_sql= "lib/init_db.sql";
my $init_db_sql_tmp= "/tmp/init_db.sql$$";
my $args;
mtr_report("Installing \u$type Database");
open(IN, $init_db_sql)
or mtr_error("Can't open $init_db_sql: $!");
open(OUT, ">", $init_db_sql_tmp)
or mtr_error("Can't write to $init_db_sql_tmp: $!");
while ()
{
chomp;
s/\@HOSTNAME\@/$glob_hostname/;
if ( /^\s*$/ )
{
print OUT "\n";
}
elsif (/;$/)
{
print OUT "$_\n";
}
else
{
print OUT "$_ ";
}
}
close OUT;
close IN;
mtr_init_args(\$args);
mtr_add_arg($args, "--no-defaults");
mtr_add_arg($args, "--bootstrap");
mtr_add_arg($args, "--console");
mtr_add_arg($args, "--skip-grant-tables");
mtr_add_arg($args, "--basedir=%s", $path_my_basedir);
mtr_add_arg($args, "--datadir=%s", $data_dir);
mtr_add_arg($args, "--skip-innodb");
mtr_add_arg($args, "--skip-ndbcluster");
mtr_add_arg($args, "--tmpdir=.");
mtr_add_arg($args, "--core-file");
if ( $opt_debug )
{
mtr_add_arg($args, "--debug=d:t:i:A,%s/log/bootstrap_%s.trace",
$path_vardir_trace, $type);
}
if ( ! $glob_netware )
{
mtr_add_arg($args, "--language=%s", $path_language);
mtr_add_arg($args, "--character-sets-dir=%s", $path_charsetsdir);
}
# Log bootstrap command
my $path_bootstrap_log= "$opt_vardir/log/bootstrap.log";
mtr_tofile($path_bootstrap_log,
"$exe_mysqld " . join(" ", @$args) . "\n");
if ( mtr_run($exe_mysqld, $args, $init_db_sql_tmp,
$path_bootstrap_log, $path_bootstrap_log,
"", { append_log_file => 1 }) != 0 )
{
unlink($init_db_sql_tmp);
mtr_error("Error executing mysqld --bootstrap\n" .
"Could not install $type test DBs");
}
unlink($init_db_sql_tmp);
}
sub im_prepare_env($) {
my $instance_manager = shift;
im_create_passwd_file($instance_manager);
im_prepare_data_dir($instance_manager);
}
sub im_create_passwd_file($) {
my $instance_manager = shift;
my $pwd_file_path = $instance_manager->{'password_file'};
mtr_report("Creating IM password file ($pwd_file_path)");
open(OUT, ">", $pwd_file_path)
or mtr_error("Can't write to $pwd_file_path: $!");
print OUT $instance_manager->{'admin_login'}, ":",
$instance_manager->{'admin_sha1'}, "\n";
close(OUT);
}
sub im_create_defaults_file($) {
my $instance_manager = shift;
my $defaults_file = $instance_manager->{'defaults_file'};
open(OUT, ">", $defaults_file)
or mtr_error("Can't write to $defaults_file: $!");
print OUT <{path_pid}
angel-pid-file = $instance_manager->{path_angel_pid}
socket = $instance_manager->{path_sock}
port = $instance_manager->{port}
password-file = $instance_manager->{password_file}
default-mysqld-path = $exe_mysqld
EOF
;
foreach my $instance (@{$instance_manager->{'instances'}})
{
my $server_id = $instance->{'server_id'};
print OUT <{path_sock}
pid-file = $instance->{path_pid}
port = $instance->{port}
datadir = $instance->{path_datadir}
log = $instance->{path_datadir}/mysqld$server_id.log
log-error = $instance->{path_datadir}/mysqld$server_id.err.log
log-slow-queries = $instance->{path_datadir}/mysqld$server_id.slow.log
language = $path_language
character-sets-dir = $path_charsetsdir
basedir = $path_my_basedir
server_id = $server_id
skip-stack-trace
skip-innodb
skip-ndbcluster
EOF
;
if ( $mysql_version_id < 50100 )
{
print OUT "skip-bdb\n";
}
print OUT "nonguarded\n" if $instance->{'nonguarded'};
if ( $mysql_version_id >= 50100 )
{
print OUT "log-output=FILE\n" if $instance->{'old_log_format'};
}
print OUT "\n";
}
close(OUT);
}
sub im_prepare_data_dir($) {
my $instance_manager = shift;
foreach my $instance (@{$instance_manager->{'instances'}})
{
copy_install_db(
'im_mysqld_' . $instance->{'server_id'},
$instance->{'path_datadir'});
}
}
#
# Restore snapshot of the installed slave databases
# if the snapshot exists
#
sub restore_slave_databases ($) {
my ($num_slaves)= @_;
if ( -d $path_snapshot)
{
for (my $idx= 0; $idx < $num_slaves; $idx++)
{
my $data_dir= $slave->[$idx]->{'path_myddir'};
my $name= basename($data_dir);
rmtree($data_dir);
mtr_copy_dir("$path_snapshot/$name", $data_dir);
}
}
}
sub run_testcase_check_skip_test($)
{
my ($tinfo)= @_;
# ----------------------------------------------------------------------
# If marked to skip, just print out and return.
# Note that a test case not marked as 'skip' can still be
# skipped later, because of the test case itself in cooperation
# with the mysqltest program tells us so.
# ----------------------------------------------------------------------
if ( $tinfo->{'skip'} )
{
mtr_report_test_name($tinfo);
mtr_report_test_skipped($tinfo);
return 1;
}
if ($tinfo->{'ndb_test'})
{
foreach my $cluster (@{$clusters})
{
last if ($opt_skip_ndbcluster_slave and
$cluster->{'name'} eq 'Slave');
# If test needs this cluster, check binaries was found ok
if ( $cluster->{'executable_setup_failed'} )
{
mtr_report_test_name($tinfo);
$tinfo->{comment}=
"Failed to find cluster binaries";
mtr_report_test_failed($tinfo);
return 1;
}
# If test needs this cluster, check it was installed ok
if ( !$cluster->{'installed_ok'} )
{
mtr_report_test_name($tinfo);
$tinfo->{comment}=
"Cluster $cluster->{'name'} was not installed ok";
mtr_report_test_failed($tinfo);
return 1;
}
}
}
if ( $tinfo->{'component_id'} eq 'im' )
{
# If test needs im, check binaries was found ok
if ( $instance_manager->{'executable_setup_failed'} )
{
mtr_report_test_name($tinfo);
$tinfo->{comment}=
"Failed to find MySQL manager binaries";
mtr_report_test_failed($tinfo);
return 1;
}
}
return 0;
}
sub do_before_run_mysqltest($)
{
my $tinfo= shift;
my $tname= $tinfo->{'name'};
# Remove old files produced by mysqltest
my $result_dir= "r";
if ( $opt_suite ne "main" )
{
$result_dir= "suite/$opt_suite/r";
}
unlink("$result_dir/$tname.reject");
unlink("$result_dir/$tname.progress");
unlink("$result_dir/$tname.log");
unlink("$result_dir/$tname.warnings");
mtr_tonewfile($path_current_test_log,"$tname\n"); # Always tell where we are
# output current test to ndbcluster log file to enable diagnostics
mtr_tofile($path_ndb_testrun_log,"CURRENT TEST $tname\n");
mtr_tofile($master->[0]->{'path_myerr'},"CURRENT_TEST: $tname\n");
if ( $master->[1]->{'pid'} )
{
mtr_tofile($master->[1]->{'path_myerr'},"CURRENT_TEST: $tname\n");
}
if ( $mysql_version_id < 50000 )
{
# Set envirnoment variable NDB_STATUS_OK to 1
# if script decided to run mysqltest cluster _is_ installed ok
$ENV{'NDB_STATUS_OK'} = "1";
}
elsif ( $mysql_version_id < 50100 )
{
# Set envirnoment variable NDB_STATUS_OK to YES
# if script decided to run mysqltest cluster _is_ installed ok
$ENV{'NDB_STATUS_OK'} = "YES";
}
}
sub do_after_run_mysqltest($)
{
my $tinfo= shift;
my $tname= $tinfo->{'name'};
mtr_tofile($path_mysqltest_log,"CURRENT TEST $tname\n");
# Save info from this testcase run to mysqltest.log
mtr_appendfile_to_file($path_timefile, $path_mysqltest_log)
if -f $path_timefile;
# Remove the file that mysqltest writes info to
unlink($path_timefile);
}
sub find_testcase_skipped_reason($)
{
my ($tinfo)= @_;
# Open mysqltest.log
my $F= IO::File->new($path_timefile) or
mtr_error("can't open file \"$path_timefile\": $!");
my $reason;
while ( my $line= <$F> )
{
# Look for "reason: "
if ( $line =~ /reason: (.*)/ )
{
$reason= $1;
}
}
if ( ! $reason )
{
mtr_warning("Could not find reason for skipping test in $path_timefile");
$reason= "Detected by testcase(reason unknown) ";
}
$tinfo->{'comment'}= $reason;
}
sub analyze_testcase_failure_sync_with_master($)
{
my ($tinfo)= @_;
my $args;
mtr_init_args(\$args);
mtr_add_arg($args, "--no-defaults");
mtr_add_arg($args, "--silent");
mtr_add_arg($args, "--skip-safemalloc");
mtr_add_arg($args, "--tmpdir=%s", $opt_tmpdir);
mtr_add_arg($args, "--character-sets-dir=%s", $path_charsetsdir);
mtr_add_arg($args, "--socket=%s", $master->[0]->{'path_sock'});
mtr_add_arg($args, "--port=%d", $master->[0]->{'port'});
mtr_add_arg($args, "--database=test");
mtr_add_arg($args, "--user=%s", $opt_user);
mtr_add_arg($args, "--password=");
# Run the test file and append output to log file
mtr_run_test($exe_mysqltest,$args,
"include/analyze_failure_sync_with_master.test",
"$path_timefile", "$path_timefile","",
{ append_log_file => 1 });
}
sub analyze_testcase_failure($)
{
my ($tinfo)= @_;
# Open mysqltest.log
my $F= IO::File->new($path_timefile) or
mtr_error("can't open file \"$path_timefile\": $!");
while ( my $line= <$F> )
{
# Look for "mysqltest: At line nnn:
if ( $line =~ /mysqltest: At line [0-9]*: (.*)/ )
{
my $error= $1;
# Look for "could not sync with master"
if ( $error =~ /could not sync with master/ )
{
analyze_testcase_failure_sync_with_master($tinfo);
}
}
}
}
##############################################################################
#
# Run a single test case
#
##############################################################################
# When we get here, we have already filtered out test cases that doesn't
# apply to the current setup, for example if we use a running server, test
# cases that restart the server are dropped. So this function should mostly
# be about doing things, not a lot of logic.
# We don't start and kill the servers for each testcase. But some
# testcases needs a restart, because they specify options to start
# mysqld with. After that testcase, we need to restart again, to set
# back the normal options.
sub run_testcase ($) {
my $tinfo= shift;
# -------------------------------------------------------
# Init variables that can change between each test case
# -------------------------------------------------------
$ENV{'TZ'}= $tinfo->{'timezone'};
mtr_verbose("Setting timezone: $tinfo->{'timezone'}");
my $master_restart= run_testcase_need_master_restart($tinfo);
my $slave_restart= run_testcase_need_slave_restart($tinfo);
if ($master_restart or $slave_restart)
{
# Can't restart a running server that may be in use
if ( $opt_extern )
{
mtr_report_test_name($tinfo);
$tinfo->{comment}= "Can't restart a running server";
mtr_report_test_skipped($tinfo);
return;
}
run_testcase_stop_servers($tinfo, $master_restart, $slave_restart);
}
my $died= mtr_record_dead_children();
if ($died or $master_restart or $slave_restart)
{
if (run_testcase_start_servers($tinfo))
{
mtr_report_test_name($tinfo);
report_failure_and_restart($tinfo);
return 1;
}
}
# ----------------------------------------------------------------------
# If --start-and-exit or --start-dirty given, stop here to let user manually
# run tests
# ----------------------------------------------------------------------
if ( $opt_start_and_exit or $opt_start_dirty )
{
mtr_timer_stop_all($glob_timers);
mtr_report("\nServers started, exiting");
exit(0);
}
{
do_before_run_mysqltest($tinfo);
my $res= run_mysqltest($tinfo);
mtr_report_test_name($tinfo);
if ( $res == 0 )
{
mtr_report_test_passed($tinfo);
}
elsif ( $res == 62 )
{
# Testcase itself tell us to skip this one
# Try to get reason from mysqltest.log
find_testcase_skipped_reason($tinfo);
mtr_report_test_skipped($tinfo);
}
elsif ( $res == 63 )
{
$tinfo->{'timeout'}= 1; # Mark as timeout
report_failure_and_restart($tinfo);
}
elsif ( $res == 1 )
{
if ( $opt_force )
{
analyze_testcase_failure($tinfo);
}
# Test case failure reported by mysqltest
report_failure_and_restart($tinfo);
}
else
{
# mysqltest failed, probably crashed
$tinfo->{comment}=
"mysqltest returned unexpected code $res, it has probably crashed";
report_failure_and_restart($tinfo);
}
do_after_run_mysqltest($tinfo);
}
# ----------------------------------------------------------------------
# Stop Instance Manager if we are processing an IM-test case.
# ----------------------------------------------------------------------
if ( $tinfo->{'component_id'} eq 'im' and
!mtr_im_stop($instance_manager, $tinfo->{'name'}) )
{
mtr_error("Failed to stop Instance Manager.")
}
}
#
# Save a snapshot of the installed test db(s)
# I.e take a snapshot of the var/ dir
#
sub save_installed_db () {
mtr_report("Saving snapshot of installed databases");
rmtree($path_snapshot);
foreach my $data_dir (@data_dir_lst)
{
my $name= basename($data_dir);
mtr_copy_dir("$data_dir", "$path_snapshot/$name");
}
}
#
# Save any interesting files in the data_dir
# before the data dir is removed.
#
sub save_files_before_restore($$) {
my $test_name= shift;
my $data_dir= shift;
my $save_name= "$opt_vardir/log/$test_name";
# Look for core files
foreach my $core_file ( glob("$data_dir/core*") )
{
my $core_name= basename($core_file);
mtr_report("Saving $core_name");
mkdir($save_name) if ! -d $save_name;
rename("$core_file", "$save_name/$core_name");
}
}
#
# Restore snapshot of the installed test db(s)
# if the snapshot exists
#
sub restore_installed_db ($) {
my $test_name= shift;
if ( -d $path_snapshot)
{
mtr_report("Restoring snapshot of databases");
foreach my $data_dir (@data_dir_lst)
{
my $name= basename($data_dir);
save_files_before_restore($test_name, $data_dir);
rmtree("$data_dir");
mtr_copy_dir("$path_snapshot/$name", "$data_dir");
}
# Remove the ndb_*_fs dirs for all ndbd nodes
# forcing a clean start of ndb
foreach my $cluster (@{$clusters})
{
foreach my $ndbd (@{$cluster->{'ndbds'}})
{
rmtree("$ndbd->{'path_fs'}" );
}
}
}
else
{
# No snapshot existed
mtr_error("No snapshot existed");
}
}
sub report_failure_and_restart ($) {
my $tinfo= shift;
mtr_report_test_failed($tinfo);
mtr_show_failed_diff($tinfo->{'result_file'});
print "\n";
if ( $opt_force )
{
# Stop all servers that are known to be running
stop_all_servers();
# Restore the snapshot of the installed test db
restore_installed_db($tinfo->{'name'});
print "Resuming Tests\n\n";
return;
}
my $test_mode= join(" ", @::glob_test_mode) || "default";
print "Aborting: $tinfo->{'name'} failed in $test_mode mode. ";
print "To continue, re-run with '--force'.\n";
if ( ! $glob_debugger and
! $opt_extern and
! $glob_use_embedded_server )
{
stop_all_servers();
}
mtr_exit(1);
}
##############################################################################
#
# Start and stop servers
#
##############################################################################
sub do_before_start_master ($) {
my ($tinfo)= @_;
my $tname= $tinfo->{'name'};
my $init_script= $tinfo->{'master_sh'};
# FIXME what about second master.....
foreach my $bin ( glob("$opt_vardir/log/master*-bin*") )
{
unlink($bin);
}
# FIXME only remove the ones that are tied to this master
# Remove old master.info and relay-log.info files
unlink("$master->[0]->{'path_myddir'}/master.info");
unlink("$master->[0]->{'path_myddir'}/relay-log.info");
unlink("$master->[1]->{'path_myddir'}/master.info");
unlink("$master->[1]->{'path_myddir'}/relay-log.info");
# Run master initialization shell script if one exists
if ( $init_script )
{
my $ret= mtr_run("/bin/sh", [$init_script], "", "", "", "");
if ( $ret != 0 )
{
# FIXME rewrite those scripts to return 0 if successful
# mtr_warning("$init_script exited with code $ret");
}
}
}
sub do_before_start_slave ($) {
my ($tinfo)= @_;
my $tname= $tinfo->{'name'};
my $init_script= $tinfo->{'master_sh'};
foreach my $bin ( glob("$opt_vardir/log/slave*-bin*") )
{
unlink($bin);
}
unlink("$slave->[0]->{'path_myddir'}/master.info");
unlink("$slave->[0]->{'path_myddir'}/relay-log.info");
# Run slave initialization shell script if one exists
if ( $init_script )
{
my $ret= mtr_run("/bin/sh", [$init_script], "", "", "", "");
if ( $ret != 0 )
{
# FIXME rewrite those scripts to return 0 if successful
# mtr_warning("$init_script exited with code $ret");
}
}
foreach my $bin ( glob("$slave->[0]->{'path_myddir'}/log.*") )
{
unlink($bin);
}
}
sub mysqld_arguments ($$$$$) {
my $args= shift;
my $type= shift;
my $idx= shift;
my $extra_opt= shift;
my $slave_master_info= shift;
my $sidx= ""; # Index as string, 0 is empty string
if ( $idx > 0 )
{
$sidx= "$idx";
}
my $prefix= ""; # If mysqltest server arg
if ( $glob_use_embedded_server )
{
$prefix= "--server-arg=";
} else {
# We can't pass embedded server --no-defaults
mtr_add_arg($args, "--no-defaults");
}
mtr_add_arg($args, "%s--console", $prefix);
mtr_add_arg($args, "%s--basedir=%s", $prefix, $path_my_basedir);
mtr_add_arg($args, "%s--character-sets-dir=%s", $prefix, $path_charsetsdir);
if ( $mysql_version_id >= 50000 )
{
mtr_add_arg($args, "%s--log-bin-trust-function-creators", $prefix);
}
mtr_add_arg($args, "%s--default-character-set=latin1", $prefix);
mtr_add_arg($args, "%s--language=%s", $prefix, $path_language);
mtr_add_arg($args, "%s--tmpdir=$opt_tmpdir", $prefix);
if ( $opt_valgrind_mysqld )
{
mtr_add_arg($args, "%s--skip-safemalloc", $prefix);
if ( $mysql_version_id < 50100 )
{
mtr_add_arg($args, "%s--skip-bdb", $prefix);
}
}
my $pidfile;
if ( $type eq 'master' )
{
my $id= $idx > 0 ? $idx + 101 : 1;
if (! $opt_skip_master_binlog)
{
mtr_add_arg($args, "%s--log-bin=%s/log/master-bin%s", $prefix,
$opt_vardir, $sidx);
}
mtr_add_arg($args, "%s--pid-file=%s", $prefix,
$master->[$idx]->{'path_pid'});
mtr_add_arg($args, "%s--port=%d", $prefix,
$master->[$idx]->{'port'});
mtr_add_arg($args, "%s--server-id=%d", $prefix, $id);
mtr_add_arg($args, "%s--socket=%s", $prefix,
$master->[$idx]->{'path_sock'});
mtr_add_arg($args, "%s--innodb_data_file_path=ibdata1:10M:autoextend", $prefix);
mtr_add_arg($args, "%s--local-infile", $prefix);
mtr_add_arg($args, "%s--datadir=%s", $prefix,
$master->[$idx]->{'path_myddir'});
if ( $idx > 0 or !$use_innodb)
{
mtr_add_arg($args, "%s--skip-innodb", $prefix);
}
my $cluster= $clusters->[$master->[$idx]->{'cluster'}];
if ( $opt_skip_ndbcluster ||
!$cluster->{'pid'})
{
mtr_add_arg($args, "%s--skip-ndbcluster", $prefix);
}
else
{
mtr_add_arg($args, "%s--ndbcluster", $prefix);
mtr_add_arg($args, "%s--ndb-connectstring=%s", $prefix,
$cluster->{'connect_string'});
if ( $mysql_version_id >= 50100 )
{
mtr_add_arg($args, "%s--ndb-extra-logging", $prefix);
}
}
}
if ( $type eq 'slave' )
{
my $slave_server_id= 2 + $idx;
my $slave_rpl_rank= $slave_server_id;
mtr_add_arg($args, "%s--datadir=%s", $prefix,
$slave->[$idx]->{'path_myddir'});
mtr_add_arg($args, "%s--init-rpl-role=slave", $prefix);
if (! $opt_skip_slave_binlog)
{
mtr_add_arg($args, "%s--log-bin=%s/log/slave%s-bin", $prefix,
$opt_vardir, $sidx); # FIXME use own dir for binlogs
mtr_add_arg($args, "%s--log-slave-updates", $prefix);
}
mtr_add_arg($args, "%s--log=%s", $prefix,
$slave->[$idx]->{'path_mylog'});
mtr_add_arg($args, "%s--master-retry-count=10", $prefix);
mtr_add_arg($args, "%s--pid-file=%s", $prefix,
$slave->[$idx]->{'path_pid'});
mtr_add_arg($args, "%s--port=%d", $prefix,
$slave->[$idx]->{'port'});
mtr_add_arg($args, "%s--relay-log=%s/log/slave%s-relay-bin", $prefix,
$opt_vardir, $sidx);
mtr_add_arg($args, "%s--report-host=127.0.0.1", $prefix);
mtr_add_arg($args, "%s--report-port=%d", $prefix,
$slave->[$idx]->{'port'});
mtr_add_arg($args, "%s--report-user=root", $prefix);
mtr_add_arg($args, "%s--skip-innodb", $prefix);
mtr_add_arg($args, "%s--skip-ndbcluster", $prefix);
mtr_add_arg($args, "%s--skip-slave-start", $prefix);
# Directory where slaves find the dumps generated by "load data"
# on the server. The path need to have constant length otherwise
# test results will vary, thus a relative path is used.
my $slave_load_path= "../tmp";
mtr_add_arg($args, "%s--slave-load-tmpdir=%s", $prefix,
$slave_load_path);
mtr_add_arg($args, "%s--socket=%s", $prefix,
$slave->[$idx]->{'path_sock'});
mtr_add_arg($args, "%s--set-variable=slave_net_timeout=10", $prefix);
if ( @$slave_master_info )
{
foreach my $arg ( @$slave_master_info )
{
mtr_add_arg($args, "%s%s", $prefix, $arg);
}
}
else
{
mtr_add_arg($args, "%s--master-user=root", $prefix);
mtr_add_arg($args, "%s--master-connect-retry=1", $prefix);
mtr_add_arg($args, "%s--master-host=127.0.0.1", $prefix);
mtr_add_arg($args, "%s--master-password=", $prefix);
mtr_add_arg($args, "%s--master-port=%d", $prefix,
$master->[0]->{'port'}); # First master
mtr_add_arg($args, "%s--server-id=%d", $prefix, $slave_server_id);
mtr_add_arg($args, "%s--rpl-recovery-rank=%d", $prefix, $slave_rpl_rank);
}
if ( $opt_skip_ndbcluster_slave ||
$slave->[$idx]->{'cluster'} == -1 ||
!$clusters->[$slave->[$idx]->{'cluster'}]->{'pid'} )
{
mtr_add_arg($args, "%s--skip-ndbcluster", $prefix);
}
else
{
mtr_add_arg($args, "%s--ndbcluster", $prefix);
mtr_add_arg($args, "%s--ndb-connectstring=%s", $prefix,
$clusters->[$slave->[$idx]->{'cluster'}]->{'connect_string'});
if ( $mysql_version_id >= 50100 )
{
mtr_add_arg($args, "%s--ndb-extra-logging", $prefix);
}
}
} # end slave
if ( $opt_debug )
{
if ( $type eq 'master' )
{
mtr_add_arg($args, "%s--debug=d:t:i:A,%s/log/master%s.trace",
$prefix, $path_vardir_trace, $sidx);
}
if ( $type eq 'slave' )
{
mtr_add_arg($args, "%s--debug=d:t:i:A,%s/log/slave%s.trace",
$prefix, $path_vardir_trace, $sidx);
}
}
# FIXME always set nowdays??? SMALL_SERVER
mtr_add_arg($args, "%s--key_buffer_size=1M", $prefix);
mtr_add_arg($args, "%s--sort_buffer=256K", $prefix);
mtr_add_arg($args, "%s--max_heap_table_size=1M", $prefix);
if ( $opt_ssl_supported )
{
mtr_add_arg($args, "%s--ssl-ca=%s/std_data/cacert.pem", $prefix,
$glob_mysql_test_dir);
mtr_add_arg($args, "%s--ssl-cert=%s/std_data/server-cert.pem", $prefix,
$glob_mysql_test_dir);
mtr_add_arg($args, "%s--ssl-key=%s/std_data/server-key.pem", $prefix,
$glob_mysql_test_dir);
}
if ( $opt_warnings )
{
mtr_add_arg($args, "%s--log-warnings", $prefix);
}
# Indicate to "mysqld" it will be debugged in debugger
if ( $glob_debugger )
{
mtr_add_arg($args, "%s--gdb", $prefix);
}
# If we should run all tests cases, we will use a local server for that
if ( -w "/" )
{
# We are running as root; We need to add the --root argument
mtr_add_arg($args, "%s--user=root", $prefix);
}
my $found_skip_core= 0;
foreach my $arg ( @opt_extra_mysqld_opt, @$extra_opt )
{
# Allow --skip-core-file to be set in master.opt file
if ($arg eq "--skip-core-file")
{
$found_skip_core= 1;
}
else
{
mtr_add_arg($args, "%s%s", $prefix, $arg);
}
}
if ( !$found_skip_core )
{
mtr_add_arg($args, "%s%s", $prefix, "--core-file");
}
if ( $opt_bench )
{
mtr_add_arg($args, "%s--rpl-recovery-rank=1", $prefix);
mtr_add_arg($args, "%s--init-rpl-role=master", $prefix);
}
elsif ( $type eq 'master' )
{
mtr_add_arg($args, "%s--open-files-limit=1024", $prefix);
mtr_add_arg($args, "%s--log=%s", $prefix, $master->[0]->{'path_mylog'});
}
return $args;
}
##############################################################################
#
# Start mysqld and return the PID
#
##############################################################################
sub mysqld_start ($$$) {
my $mysqld= shift;
my $extra_opt= shift;
my $slave_master_info= shift;
my $args; # Arg vector
my $exe;
my $pid= -1;
my $wait_for_pid_file= 1;
my $type= $mysqld->{'type'};
my $idx= $mysqld->{'idx'};
mtr_error("Internal error: mysqld should never be started for embedded")
if $glob_use_embedded_server;
if ( $type eq 'master' )
{
$exe= $exe_master_mysqld;
}
elsif ( $type eq 'slave' )
{
$exe= $exe_slave_mysqld;
}
else
{
mtr_error("Unknown 'type' \"$type\" passed to mysqld_start");
}
mtr_init_args(\$args);
if ( $opt_valgrind_mysqld )
{
valgrind_arguments($args, \$exe);
}
mysqld_arguments($args,$type,$idx,$extra_opt,$slave_master_info);
if ( $opt_gdb || $opt_manual_gdb)
{
gdb_arguments(\$args, \$exe, "$type"."_$idx");
}
elsif ( $opt_ddd || $opt_manual_ddd )
{
ddd_arguments(\$args, \$exe, "$type"."_$idx");
}
elsif ( $opt_debugger )
{
debugger_arguments(\$args, \$exe, "$type"."_$idx");
}
elsif ( $opt_manual_debug )
{
print "\nStart $type in your debugger\n" .
"dir: $glob_mysql_test_dir\n" .
"exe: $exe\n" .
"args: " . join(" ", @$args) . "\n\n" .
"Waiting ....\n";
# Indicate the exe should not be started
$exe= undef;
}
else
{
# Default to not wait until pid file has been created
$wait_for_pid_file= 0;
}
if ( defined $exe )
{
$pid= mtr_spawn($exe, $args, "",
$mysqld->{'path_myerr'},
$mysqld->{'path_myerr'},
"",
{ append_log_file => 1 });
}
if ( $wait_for_pid_file && !sleep_until_file_created($mysqld->{'path_pid'},
$mysqld->{'start_timeout'},
$pid))
{
mtr_error("Failed to start mysqld $mysqld->{'type'}");
}
# Remember pid of the started process
$mysqld->{'pid'}= $pid;
# Remember options used when starting
$mysqld->{'start_opts'}= $extra_opt;
$mysqld->{'start_slave_master_info'}= $slave_master_info;
mtr_verbose("mysqld pid: $pid");
return $pid;
}
sub stop_all_servers () {
print "Stopping All Servers\n";
if ( ! $opt_skip_im )
{
print "Shutting-down Instance Manager\n";
unless (mtr_im_stop($instance_manager, "stop_all_servers"))
{
mtr_error("Failed to stop Instance Manager.")
}
}
my %admin_pids; # hash of admin processes that requests shutdown
my @kill_pids; # list of processes to shutdown/kill
my $pid;
# Start shutdown of all started masters
foreach my $mysqld (@{$master}, @{$slave})
{
if ( $mysqld->{'pid'} )
{
$pid= mtr_mysqladmin_start($mysqld, "shutdown", 70);
$admin_pids{$pid}= 1;
push(@kill_pids,{
pid => $mysqld->{'pid'},
pidfile => $mysqld->{'path_pid'},
sockfile => $mysqld->{'path_sock'},
port => $mysqld->{'port'},
});
$mysqld->{'pid'}= 0; # Assume we are done with it
}
}
# Start shutdown of clusters
foreach my $cluster (@{$clusters})
{
if ( $cluster->{'pid'} )
{
$pid= mtr_ndbmgm_start($cluster, "shutdown");
$admin_pids{$pid}= 1;
push(@kill_pids,{
pid => $cluster->{'pid'},
pidfile => $cluster->{'path_pid'}
});
$cluster->{'pid'}= 0; # Assume we are done with it
foreach my $ndbd (@{$cluster->{'ndbds'}})
{
if ( $ndbd->{'pid'} )
{
push(@kill_pids,{
pid => $ndbd->{'pid'},
pidfile => $ndbd->{'path_pid'},
});
$ndbd->{'pid'}= 0;
}
}
}
}
# Wait blocking until all shutdown processes has completed
mtr_wait_blocking(\%admin_pids);
# Make sure that process has shutdown else try to kill them
mtr_check_stop_servers(\@kill_pids);
foreach my $mysqld (@{$master}, @{$slave})
{
rm_ndbcluster_tables($mysqld->{'path_myddir'});
}
}
sub run_testcase_need_master_restart($)
{
my ($tinfo)= @_;
# We try to find out if we are to restart the master(s)
my $do_restart= 0; # Assumes we don't have to
if ( $glob_use_embedded_server )
{
mtr_verbose("Never start or restart for embedded server");
return $do_restart;
}
elsif ( $tinfo->{'master_sh'} )
{
$do_restart= 1; # Always restart if script to run
mtr_verbose("Restart master: Always restart if script to run");
}
if ( $tinfo->{'force_restart'} )
{
$do_restart= 1; # Always restart if --force-restart in -opt file
mtr_verbose("Restart master: Restart forced with --force-restart");
}
elsif ( ! $opt_skip_ndbcluster and
!$tinfo->{'ndb_test'} and
$clusters->[0]->{'pid'} != 0 )
{
$do_restart= 1; # Restart without cluster
mtr_verbose("Restart master: Test does not need cluster");
}
elsif ( ! $opt_skip_ndbcluster and
$tinfo->{'ndb_test'} and
$clusters->[0]->{'pid'} == 0 )
{
$do_restart= 1; # Restart with cluster
mtr_verbose("Restart master: Test need cluster");
}
elsif( $tinfo->{'component_id'} eq 'im' )
{
$do_restart= 1;
mtr_verbose("Restart master: Always restart for im tests");
}
elsif ( $master->[0]->{'running_master_options'} and
$master->[0]->{'running_master_options'}->{'timezone'} ne
$tinfo->{'timezone'})
{
$do_restart= 1;
mtr_verbose("Restart master: Different timezone");
}
# Check that running master was started with same options
# as the current test requires
elsif (! mtr_same_opts($master->[0]->{'start_opts'},
$tinfo->{'master_opt'}) )
{
$do_restart= 1;
mtr_verbose("Restart master: running with different options '" .
join(" ", @{$tinfo->{'master_opt'}}) . "' != '" .
join(" ", @{$master->[0]->{'start_opts'}}) . "'" );
}
elsif( ! $master->[0]->{'pid'} )
{
if ( $opt_extern )
{
$do_restart= 0;
mtr_verbose("No restart: using extern master");
}
else
{
$do_restart= 1;
mtr_verbose("Restart master: master is not started");
}
}
return $do_restart;
}
sub run_testcase_need_slave_restart($)
{
my ($tinfo)= @_;
# We try to find out if we are to restart the slaves
my $do_slave_restart= 0; # Assumes we don't have to
if ( $glob_use_embedded_server )
{
mtr_verbose("Never start or restart for embedded server");
return $do_slave_restart;
}
elsif ( $max_slave_num == 0)
{
mtr_verbose("Skip slave restart: No testcase use slaves");
}
else
{
# Check if any slave is currently started
my $any_slave_started= 0;
foreach my $mysqld (@{$slave})
{
if ( $mysqld->{'pid'} )
{
$any_slave_started= 1;
last;
}
}
if ($any_slave_started)
{
mtr_verbose("Restart slave: Slave is started, always restart");
$do_slave_restart= 1;
}
elsif ( $tinfo->{'slave_num'} )
{
mtr_verbose("Restart slave: Test need slave");
$do_slave_restart= 1;
}
}
return $do_slave_restart;
}
# ----------------------------------------------------------------------
# If not using a running servers we may need to stop and restart.
# We restart in the case we have initiation scripts, server options
# etc to run. But we also restart again after the test first restart
# and test is run, to get back to normal server settings.
#
# To make the code a bit more clean, we actually only stop servers
# here, and mark this to be done. Then a generic "start" part will
# start up the needed servers again.
# ----------------------------------------------------------------------
sub run_testcase_stop_servers($$$) {
my ($tinfo, $do_restart, $do_slave_restart)= @_;
my $pid;
my %admin_pids; # hash of admin processes that requests shutdown
my @kill_pids; # list of processes to shutdown/kill
# Remember if we restarted for this test case (count restarts)
$tinfo->{'restarted'}= $do_restart;
if ( $do_restart )
{
delete $master->[0]->{'running_master_options'}; # Forget history
# Start shutdown of all started masters
foreach my $mysqld (@{$master})
{
if ( $mysqld->{'pid'} )
{
$pid= mtr_mysqladmin_start($mysqld, "shutdown", 70);
$admin_pids{$pid}= 1;
push(@kill_pids,{
pid => $mysqld->{'pid'},
pidfile => $mysqld->{'path_pid'},
sockfile => $mysqld->{'path_sock'},
port => $mysqld->{'port'},
});
$mysqld->{'pid'}= 0; # Assume we are done with it
}
}
# Start shutdown of master cluster
my $cluster= $clusters->[0];
if ( $cluster->{'pid'} )
{
$pid= mtr_ndbmgm_start($cluster, "shutdown");
$admin_pids{$pid}= 1;
push(@kill_pids,{
pid => $cluster->{'pid'},
pidfile => $cluster->{'path_pid'}
});
$cluster->{'pid'}= 0; # Assume we are done with it
foreach my $ndbd (@{$cluster->{'ndbds'}})
{
push(@kill_pids,{
pid => $ndbd->{'pid'},
pidfile => $ndbd->{'path_pid'},
});
$ndbd->{'pid'}= 0; # Assume we are done with it
}
}
}
if ( $do_restart || $do_slave_restart )
{
delete $slave->[0]->{'running_slave_options'}; # Forget history
# Start shutdown of all started slaves
foreach my $mysqld (@{$slave})
{
if ( $mysqld->{'pid'} )
{
$pid= mtr_mysqladmin_start($mysqld, "shutdown", 70);
$admin_pids{$pid}= 1;
push(@kill_pids,{
pid => $mysqld->{'pid'},
pidfile => $mysqld->{'path_pid'},
sockfile => $mysqld->{'path_sock'},
port => $mysqld->{'port'},
});
$mysqld->{'pid'}= 0; # Assume we are done with it
}
}
# Start shutdown of slave cluster
my $cluster= $clusters->[1];
if ( $cluster->{'pid'} )
{
$pid= mtr_ndbmgm_start($cluster, "shutdown");
$admin_pids{$pid}= 1;
push(@kill_pids,{
pid => $cluster->{'pid'},
pidfile => $cluster->{'path_pid'}
});
$cluster->{'pid'}= 0; # Assume we are done with it
foreach my $ndbd (@{$cluster->{'ndbds'}} )
{
push(@kill_pids,{
pid => $ndbd->{'pid'},
pidfile => $ndbd->{'path_pid'},
});
$ndbd->{'pid'}= 0; # Assume we are done with it
}
}
}
# ----------------------------------------------------------------------
# Shutdown has now been started and lists for the shutdown processes
# and the processes to be killed has been created
# ----------------------------------------------------------------------
# Wait blocking until all shutdown processes has completed
mtr_wait_blocking(\%admin_pids);
# Make sure that process has shutdown else try to kill them
mtr_check_stop_servers(\@kill_pids);
foreach my $mysqld (@{$master}, @{$slave})
{
if ( ! $mysqld->{'pid'} )
{
# Remove ndbcluster tables if server is stopped
rm_ndbcluster_tables($mysqld->{'path_myddir'});
}
}
}
#
# run_testcase_start_servers
#
# Start the servers needed by this test case
#
# RETURN
# 0 OK
# 1 Start failed
#
sub run_testcase_start_servers($) {
my $tinfo= shift;
my $tname= $tinfo->{'name'};
if ( $tinfo->{'component_id'} eq 'mysqld' )
{
if ( ! $opt_skip_ndbcluster and
!$clusters->[0]->{'pid'} and
$tinfo->{'ndb_test'} )
{
# Test need cluster, cluster is not started, start it
ndbcluster_start($clusters->[0], "");
}
if ( !$master->[0]->{'pid'} )
{
# Master mysqld is not started
do_before_start_master($tinfo);
mysqld_start($master->[0],$tinfo->{'master_opt'},[]);
}
if ( $clusters->[0]->{'pid'} and ! $master->[1]->{'pid'} )
{
# Test needs cluster, start an extra mysqld connected to cluster
if ( $mysql_version_id >= 50100 )
{
# First wait for first mysql server to have created ndb system
# tables ok FIXME This is a workaround so that only one mysqld
# create the tables
if ( ! sleep_until_file_created(
"$master->[0]->{'path_myddir'}/cluster/apply_status.ndb",
$master->[0]->{'start_timeout'},
$master->[0]->{'pid'}))
{
$tinfo->{'comment'}= "Failed to create 'cluster/apply_status' table";
return 1;
}
}
mtr_tofile($master->[1]->{'path_myerr'},"CURRENT_TEST: $tname\n");
mysqld_start($master->[1],$tinfo->{'master_opt'},[]);
}
# Save this test case information, so next can examine it
$master->[0]->{'running_master_options'}= $tinfo;
}
elsif ( ! $opt_skip_im and $tinfo->{'component_id'} eq 'im' )
{
# We have to create defaults file every time, in order to ensure that it
# will be the same for each test. The problem is that test can change the
# file (by SET/UNSET commands), so w/o recreating the file, execution of
# one test can affect the other.
im_create_defaults_file($instance_manager);
if ( ! mtr_im_start($instance_manager, $tinfo->{im_opts}) )
{
$tinfo->{'comment'}= "Failed to start Instance Manager. ";
return 1;
}
}
# ----------------------------------------------------------------------
# Start slaves - if needed
# ----------------------------------------------------------------------
if ( $tinfo->{'slave_num'} )
{
mtr_tofile($slave->[0]->{'path_myerr'},"CURRENT_TEST: $tname\n");
restore_slave_databases($tinfo->{'slave_num'});
do_before_start_slave($tinfo);
if ( ! $opt_skip_ndbcluster_slave and
!$clusters->[1]->{'pid'} and
$tinfo->{'ndb_test'} )
{
# Test need slave cluster, cluster is not started, start it
ndbcluster_start($clusters->[1], "");
}
for ( my $idx= 0; $idx < $tinfo->{'slave_num'}; $idx++ )
{
if ( ! $slave->[$idx]->{'pid'} )
{
mysqld_start($slave->[$idx],$tinfo->{'slave_opt'},
$tinfo->{'slave_mi'});
}
}
# Save this test case information, so next can examine it
$slave->[0]->{'running_slave_options'}= $tinfo;
}
# Wait for clusters to start
foreach my $cluster (@{$clusters})
{
next if !$cluster->{'pid'};
if (ndbcluster_wait_started($cluster, ""))
{
# failed to start
$tinfo->{'comment'}= "Start of $cluster->{'name'} cluster failed";
return 1;
}
}
# Wait for mysqld's to start
foreach my $mysqld (@{$master},@{$slave})
{
next if !$mysqld->{'pid'};
if (mysqld_wait_started($mysqld))
{
# failed to start
$tinfo->{'comment'}=
"Failed to start $mysqld->{'type'} mysqld $mysqld->{'idx'}";
return 1;
}
}
return 0;
}
#
# Run include/check-testcase.test
# Before a testcase, run in record mode, save result file to var
# After testcase, run and compare with the recorded file, they should be equal!
#
# RETURN VALUE
# 0 OK
# 1 Check failed
#
sub run_check_testcase ($$) {
my $mode= shift;
my $mysqld= shift;
my $name= "check-" . $mysqld->{'type'} . $mysqld->{'idx'};
my $args;
mtr_init_args(\$args);
mtr_add_arg($args, "--no-defaults");
mtr_add_arg($args, "--silent");
mtr_add_arg($args, "--skip-safemalloc");
mtr_add_arg($args, "--tmpdir=%s", $opt_tmpdir);
mtr_add_arg($args, "--character-sets-dir=%s", $path_charsetsdir);
mtr_add_arg($args, "--socket=%s", $mysqld->{'path_sock'});
mtr_add_arg($args, "--port=%d", $mysqld->{'port'});
mtr_add_arg($args, "--database=test");
mtr_add_arg($args, "--user=%s", $opt_user);
mtr_add_arg($args, "--password=");
mtr_add_arg($args, "-R");
mtr_add_arg($args, "$opt_vardir/tmp/$name.result");
if ( $mode eq "before" )
{
mtr_add_arg($args, "--record");
}
my $res = mtr_run_test($exe_mysqltest,$args,
"include/check-testcase.test", "", "", "");
if ( $res == 1 and $mode eq "after")
{
mtr_run("diff",["-u",
"$opt_vardir/tmp/$name.result",
"$opt_vardir/tmp/$name.reject"],
"", "", "", "");
}
elsif ( $res )
{
mtr_error("Could not execute 'check-testcase' $mode testcase");
}
return $res;
}
##############################################################################
#
# Report the features that were compiled in
#
##############################################################################
sub run_report_features () {
my $args;
if ( ! $glob_use_embedded_server )
{
mysqld_start($master->[0],[],[]);
if ( ! $master->[0]->{'pid'} )
{
mtr_error("Can't start the mysqld server");
}
mysqld_wait_started($master->[0]);
}
my $tinfo = {};
$tinfo->{'name'} = 'report features';
$tinfo->{'result_file'} = undef;
$tinfo->{'component_id'} = 'mysqld';
$tinfo->{'path'} = 'include/report-features.test';
$tinfo->{'timezone'}= "GMT-3";
$tinfo->{'slave_num'} = 0;
$tinfo->{'master_opt'} = [];
$tinfo->{'slave_opt'} = [];
$tinfo->{'slave_mi'} = [];
$tinfo->{'comment'} = 'report server features';
run_mysqltest($tinfo);
if ( ! $glob_use_embedded_server )
{
stop_all_servers();
}
}
sub run_mysqltest ($) {
my ($tinfo)= @_;
my $exe= $exe_mysqltest;
my $args;
mtr_init_args(\$args);
mtr_add_arg($args, "--no-defaults");
mtr_add_arg($args, "--silent");
mtr_add_arg($args, "--skip-safemalloc");
mtr_add_arg($args, "--tmpdir=%s", $opt_tmpdir);
mtr_add_arg($args, "--character-sets-dir=%s", $path_charsetsdir);
if ($tinfo->{'component_id'} eq 'im')
{
mtr_add_arg($args, "--socket=%s", $instance_manager->{'path_sock'});
mtr_add_arg($args, "--port=%d", $instance_manager->{'port'});
mtr_add_arg($args, "--user=%s", $instance_manager->{'admin_login'});
mtr_add_arg($args, "--password=%s", $instance_manager->{'admin_password'});
}
else # component_id == mysqld
{
mtr_add_arg($args, "--socket=%s", $master->[0]->{'path_sock'});
mtr_add_arg($args, "--port=%d", $master->[0]->{'port'});
mtr_add_arg($args, "--database=test");
mtr_add_arg($args, "--user=%s", $opt_user);
mtr_add_arg($args, "--password=");
}
if ( $opt_ps_protocol )
{
mtr_add_arg($args, "--ps-protocol");
}
if ( $opt_sp_protocol )
{
mtr_add_arg($args, "--sp-protocol");
}
if ( $opt_view_protocol )
{
mtr_add_arg($args, "--view-protocol");
}
if ( $opt_cursor_protocol )
{
mtr_add_arg($args, "--cursor-protocol");
}
if ( $opt_strace_client )
{
$exe= "strace"; # FIXME there are ktrace, ....
mtr_add_arg($args, "-o");
mtr_add_arg($args, "%s/log/mysqltest.strace", $opt_vardir);
mtr_add_arg($args, "$exe_mysqltest");
}
if ( $opt_timer )
{
mtr_add_arg($args, "--timer-file=%s/log/timer", $opt_vardir);
}
if ( $opt_compress )
{
mtr_add_arg($args, "--compress");
}
if ( $opt_sleep )
{
mtr_add_arg($args, "--sleep=%d", $opt_sleep);
}
if ( $opt_debug )
{
mtr_add_arg($args, "--debug=d:t:A,%s/log/mysqltest.trace",
$path_vardir_trace);
}
if ( $opt_ssl_supported )
{
mtr_add_arg($args, "--ssl-ca=%s/std_data/cacert.pem",
$glob_mysql_test_dir);
mtr_add_arg($args, "--ssl-cert=%s/std_data/client-cert.pem",
$glob_mysql_test_dir);
mtr_add_arg($args, "--ssl-key=%s/std_data/client-key.pem",
$glob_mysql_test_dir);
}
if ( $opt_ssl )
{
# Turn on SSL for _all_ test cases if option --ssl was used
mtr_add_arg($args, "--ssl");
}
elsif ( $opt_ssl_supported )
{
mtr_add_arg($args, "--skip-ssl");
}
# ----------------------------------------------------------------------
# If embedded server, we create server args to give mysqltest to pass on
# ----------------------------------------------------------------------
if ( $glob_use_embedded_server )
{
mysqld_arguments($args,'master',0,$tinfo->{'master_opt'},[]);
}
# ----------------------------------------------------------------------
# export MYSQL_TEST variable containing /mysqltest
# ----------------------------------------------------------------------
$ENV{'MYSQL_TEST'}= "$exe_mysqltest " . join(" ", @$args);
# ----------------------------------------------------------------------
# Add arguments that should not go into the MYSQL_TEST env var
# ----------------------------------------------------------------------
if ( $opt_valgrind_mysqltest )
{
# Prefix the Valgrind options to the argument list.
# We do this here, since we do not want to Valgrind the nested invocations
# of mysqltest; that would mess up the stderr output causing test failure.
my @args_saved = @$args;
mtr_init_args(\$args);
valgrind_arguments($args, \$exe);
mtr_add_arg($args, "%s", $_) for @args_saved;
}
mtr_add_arg($args, "--test-file");
mtr_add_arg($args, $tinfo->{'path'});
if ( defined $tinfo->{'result_file'} ) {
mtr_add_arg($args, "--result-file");
mtr_add_arg($args, $tinfo->{'result_file'});
}
if ( $opt_record )
{
mtr_add_arg($args, "--record");
}
if ( $opt_client_gdb )
{
gdb_arguments(\$args, \$exe, "client");
}
elsif ( $opt_client_ddd )
{
ddd_arguments(\$args, \$exe, "client");
}
elsif ( $opt_client_debugger )
{
debugger_arguments(\$args, \$exe, "client");
}
if ( $opt_check_testcases )
{
foreach my $mysqld (@{$master}, @{$slave})
{
if ($mysqld->{'pid'})
{
run_check_testcase("before", $mysqld);
}
}
}
my $res = mtr_run_test($exe,$args,"","",$path_timefile,"");
if ( $opt_check_testcases )
{
foreach my $mysqld (@{$master}, @{$slave})
{
if ($mysqld->{'pid'})
{
if (run_check_testcase("after", $mysqld))
{
# Check failed, mark the test case with that info
$tinfo->{'check_testcase_failed'}= 1;
}
}
}
}
return $res;
}
#
# Modify the exe and args so that program is run in gdb in xterm
#
sub gdb_arguments {
my $args= shift;
my $exe= shift;
my $type= shift;
# Write $args to gdb init file
my $str= join(" ", @$$args);
my $gdb_init_file= "$opt_tmpdir/gdbinit.$type";
# Remove the old gdbinit file
unlink($gdb_init_file);
if ( $type eq "client" )
{
# write init file for client
mtr_tofile($gdb_init_file,
"set args $str\n" .
"break main\n");
}
else
{
# write init file for mysqld
mtr_tofile($gdb_init_file,
"set args $str\n" .
"break mysql_parse\n" .
"commands 1\n" .
"disable 1\n" .
"end\n" .
"run");
}
if ( $opt_manual_gdb )
{
print "\nTo start gdb for $type, type in another window:\n";
print "cd $glob_mysql_test_dir;\n";
print "gdb -x $gdb_init_file $$exe\n";
# Indicate the exe should not be started
$$exe= undef;
return;
}
$$args= [];
mtr_add_arg($$args, "-title");
mtr_add_arg($$args, "$type");
mtr_add_arg($$args, "-e");
if ( $exe_libtool )
{
mtr_add_arg($$args, $exe_libtool);
mtr_add_arg($$args, "--mode=execute");
}
mtr_add_arg($$args, "gdb");
mtr_add_arg($$args, "-x");
mtr_add_arg($$args, "$gdb_init_file");
mtr_add_arg($$args, "$$exe");
$$exe= "xterm";
}
#
# Modify the exe and args so that program is run in ddd
#
sub ddd_arguments {
my $args= shift;
my $exe= shift;
my $type= shift;
# Write $args to ddd init file
my $str= join(" ", @$$args);
my $gdb_init_file= "$opt_tmpdir/gdbinit.$type";
# Remove the old gdbinit file
unlink($gdb_init_file);
if ( $type eq "client" )
{
# write init file for client
mtr_tofile($gdb_init_file,
"set args $str\n" .
"break main\n");
}
else
{
# write init file for mysqld
mtr_tofile($gdb_init_file,
"file $$exe\n" .
"set args $str\n" .
"break mysql_parse\n" .
"commands 1\n" .
"disable 1\n" .
"end");
}
if ( $opt_manual_ddd )
{
print "\nTo start ddd for $type, type in another window:\n";
print "cd $glob_mysql_test_dir;\n";
print "ddd -x $gdb_init_file $$exe\n";
# Indicate the exe should not be started
$$exe= undef;
return;
}
my $save_exe= $$exe;
$$args= [];
if ( $exe_libtool )
{
$$exe= $exe_libtool;
mtr_add_arg($$args, "--mode=execute");
mtr_add_arg($$args, "ddd");
}
else
{
$$exe= "ddd";
}
mtr_add_arg($$args, "--command=$gdb_init_file");
mtr_add_arg($$args, "$save_exe");
}
#
# Modify the exe and args so that program is run in the selected debugger
#
sub debugger_arguments {
my $args= shift;
my $exe= shift;
my $debugger= $opt_debugger || $opt_client_debugger;
# FIXME Need to change the below "eq"'s to
# "case unsensitive string contains"
if ( $debugger eq "vcexpress" or $debugger eq "vc")
{
# vc[express] /debugexe exe arg1 .. argn
# Add /debugexe and name of the exe before args
unshift(@$$args, "/debugexe");
unshift(@$$args, "$$exe");
}
elsif ( $debugger eq "windbg" )
{
# windbg exe arg1 .. argn
# Add name of the exe before args
unshift(@$$args, "$$exe");
}
else
{
mtr_error("Unknown argument \"$debugger\" passed to --debugger");
}
# Set exe to debuggername
$$exe= $debugger;
}
#
# Modify the exe and args so that program is run in valgrind
#
sub valgrind_arguments {
my $args= shift;
my $exe= shift;
if ( $opt_callgrind)
{
mtr_add_arg($args, "--tool=callgrind");
mtr_add_arg($args, "--base=$opt_vardir/log");
}
else
{
mtr_add_arg($args, "--tool=memcheck"); # From >= 2.1.2 needs this option
mtr_add_arg($args, "--alignment=8");
mtr_add_arg($args, "--leak-check=yes");
mtr_add_arg($args, "--num-callers=16");
mtr_add_arg($args, "--suppressions=%s/valgrind.supp", $glob_mysql_test_dir)
if -f "$glob_mysql_test_dir/valgrind.supp";
}
# Add valgrind options, can be overriden by user
mtr_add_arg($args, '%s', $_) for (split(' ', $opt_valgrind_options));
mtr_add_arg($args, $$exe);
$$exe= $opt_valgrind_path || "valgrind";
if ($exe_libtool)
{
# Add "libtool --mode-execute" before the test to execute
# if running in valgrind(to avoid valgrinding bash)
unshift(@$args, "--mode=execute", $$exe);
$$exe= $exe_libtool;
}
}
##############################################################################
#
# Usage
#
##############################################################################
sub usage ($) {
my $message= shift;
if ( $message )
{
print STDERR "$message \n";
}
print STDERR <