summaryrefslogtreecommitdiff
path: root/mysql-test/mysql-test-run.pl
diff options
context:
space:
mode:
authorRucha Deodhar <rucha.deodhar@mariadb.com>2021-02-08 14:52:04 +0530
committerRucha Deodhar <rucha.deodhar@mariadb.com>2021-06-14 15:10:47 +0530
commit193bfdd831bbbf65e74acd12baf691d4305e3c11 (patch)
tree1bc2114e18e591571745d45a0d22f9c569b26c16 /mysql-test/mysql-test-run.pl
parentcb0cad8156f5c7de3777e465a6b8f64bc440b278 (diff)
downloadmariadb-git-193bfdd831bbbf65e74acd12baf691d4305e3c11.tar.gz
MDEV-22010: use executables MariaDB named in scripts
As a part of this MDEV following changes were made: 1) Mariadb named executables used instead of mysql named executables in scripts 2) renamed mysql-test-run and mysql-stress-test to mariadb-test-run and mariadb-stress-test and created a symlink.
Diffstat (limited to 'mysql-test/mysql-test-run.pl')
-rwxr-xr-xmysql-test/mysql-test-run.pl5942
1 files changed, 0 insertions, 5942 deletions
diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl
deleted file mode 100755
index 13369982daf..00000000000
--- a/mysql-test/mysql-test-run.pl
+++ /dev/null
@@ -1,5942 +0,0 @@
-#!/usr/bin/env perl
-# -*- cperl -*-
-
-# Copyright (c) 2004, 2014, Oracle and/or its affiliates.
-# Copyright (c) 2009, 2021, MariaDB Corporation
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; version 2 of the License.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA
-
-#
-##############################################################################
-#
-# mysql-test-run.pl
-#
-# Tool used for executing a suite of .test files
-#
-# See the "MySQL Test framework manual" for more information
-# https://mariadb.com/kb/en/library/mysqltest/
-#
-#
-##############################################################################
-
-use strict;
-use warnings;
-
-BEGIN {
- # Check that mysql-test-run.pl is started from mysql-test/
- unless ( -f "mysql-test-run.pl" )
- {
- print "**** ERROR **** ",
- "You must start mysql-test-run from the mysql-test/ directory\n";
- exit(1);
- }
- # Check that lib exist
- unless ( -d "lib/" )
- {
- print "**** ERROR **** ",
- "Could not find the lib/ directory \n";
- exit(1);
- }
-
- # Check backward compatibility support
- # By setting the environment variable MTR_VERSION
- # it's possible to use a previous version of
- # mysql-test-run.pl
- my $version= $ENV{MTR_VERSION} || 2;
- if ( $version == 1 )
- {
- print "=======================================================\n";
- print " WARNING: Using mysql-test-run.pl version 1! \n";
- print "=======================================================\n";
- # Should use exec() here on *nix but this appears not to work on Windows
- exit(system($^X, "lib/v1/mysql-test-run.pl", @ARGV) >> 8);
- }
- elsif ( $version == 2 )
- {
- # This is the current version, just continue
- ;
- }
- else
- {
- print "ERROR: Version $version of mysql-test-run does not exist!\n";
- exit(1);
- }
-}
-
-use lib "lib";
-
-use Cwd ;
-use Getopt::Long;
-use My::File::Path; # Patched version of File::Path
-use File::Basename;
-use File::Copy;
-use File::Find;
-use File::Temp qw/tempdir/;
-use File::Spec::Functions qw/splitdir rel2abs/;
-use My::Platform;
-use My::SafeProcess;
-use My::ConfigFactory;
-use My::Options;
-use My::Tee;
-use My::Find;
-use My::SysInfo;
-use My::CoreDump;
-use My::Debugger;
-use mtr_cases;
-use mtr_report;
-use mtr_match;
-use mtr_unique;
-use mtr_results;
-use IO::Socket::INET;
-use IO::Select;
-use Time::HiRes qw(gettimeofday);
-
-sub realpath($) { (IS_WINDOWS) ? $_[0] : Cwd::realpath($_[0]) }
-
-require "mtr_process.pl";
-require "mtr_io.pl";
-require "mtr_gprof.pl";
-require "mtr_misc.pl";
-
-my $opt_valgrind;
-my $valgrind_reports= 0;
-
-$SIG{INT}= sub { mtr_error("Got ^C signal"); };
-$SIG{HUP}= sub { mtr_error("Hangup detected on controlling terminal"); };
-
-our $mysql_version_id;
-my $mysql_version_extra;
-our $glob_mysql_test_dir;
-our $basedir;
-our $bindir;
-
-our $path_charsetsdir;
-our $path_client_bindir;
-our $path_client_libdir;
-our $path_language;
-
-our $path_current_testlog;
-our $path_testlog;
-
-our $default_vardir;
-our $opt_vardir; # Path to use for var/ dir
-our $plugindir;
-our $opt_xml_report; # XML output
-our $client_plugindir;
-my $path_vardir_trace; # unix formatted opt_vardir for trace files
-my $opt_tmpdir; # Path to use for tmp/ dir
-my $opt_tmpdir_pid;
-
-my $opt_start;
-my $opt_start_dirty;
-my $opt_start_exit;
-my $start_only;
-my $file_wsrep_provider;
-
-our @global_suppressions;
-
-END {
- if ( defined $opt_tmpdir_pid and $opt_tmpdir_pid == $$ )
- {
- if (!$opt_start_exit)
- {
- # Remove the tempdir this process has created
- mtr_verbose("Removing tmpdir $opt_tmpdir");
- rmtree($opt_tmpdir);
- }
- else
- {
- mtr_warning("tmpdir $opt_tmpdir should be removed after the server has finished");
- }
- }
-}
-
-sub env_or_val($$) { defined $ENV{$_[0]} ? $ENV{$_[0]} : $_[1] }
-
-my $path_config_file; # The generated config file, var/my.cnf
-
-# 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'};
-
-my @DEFAULT_SUITES= qw(
- main-
- archive-
- atomic-
- binlog-
- binlog_encryption-
- client-
- csv-
- compat/oracle-
- compat/mssql-
- compat/maxdb-
- encryption-
- federated-
- funcs_1-
- funcs_2-
- gcol-
- handler-
- heap-
- innodb-
- innodb_fts-
- innodb_gis-
- innodb_i_s-
- innodb_zip-
- json-
- maria-
- mariabackup-
- multi_source-
- optimizer_unfixed_bugs-
- parts-
- perfschema-
- plugins-
- roles-
- rpl-
- stress-
- sys_vars-
- sql_sequence-
- unit-
- vcol-
- versioning-
- period-
- sysschema-
- );
-my $opt_suites;
-
-our $opt_verbose= 0; # Verbose output, enable with --verbose
-our $exe_patch;
-our $exe_mysql;
-our $exe_mysql_plugin;
-our $exe_mysqladmin;
-our $exe_mysqltest;
-our $exe_libtool;
-our $exe_mysql_embedded;
-our $exe_mariadb_conv;
-
-our $opt_big_test= 0;
-our $opt_staging_run= 0;
-
-our @opt_combinations;
-
-our @opt_extra_mysqld_opt;
-our @opt_mysqld_envs;
-
-my $opt_stress;
-my $opt_tail_lines= 20;
-
-my $opt_dry_run;
-
-my $opt_compress;
-my $opt_ssl;
-my $opt_skip_ssl;
-my @opt_skip_test_list;
-our $opt_ssl_supported;
-my $opt_ps_protocol;
-my $opt_sp_protocol;
-my $opt_cursor_protocol;
-my $opt_view_protocol;
-my $opt_non_blocking_api;
-
-our $opt_debug;
-my $debug_d= "d,*";
-my $opt_debug_common;
-our $opt_debug_server;
-our @opt_cases; # The test cases names in argv
-our $opt_embedded_server;
-
-# Options used when connecting to an already running server
-my %opts_extern;
-sub using_extern { return (keys %opts_extern > 0);};
-
-our $opt_fast= 0;
-our $opt_force= 0;
-our $opt_mem= $ENV{'MTR_MEM'};
-our $opt_clean_vardir= $ENV{'MTR_CLEAN_VARDIR'};
-
-our $opt_gcov;
-our $opt_gprof;
-our %gprof_dirs;
-
-my $config; # The currently running config
-my $current_config_name; # The currently running config file template
-
-our @opt_experimentals;
-our $experimental_test_cases= [];
-
-our $baseport;
-# $opt_build_thread may later be set from $opt_port_base
-my $opt_build_thread= $ENV{'MTR_BUILD_THREAD'} || "auto";
-my $opt_port_base= $ENV{'MTR_PORT_BASE'} || "auto";
-my $build_thread= 0;
-
-my $opt_record;
-
-our $opt_resfile= $ENV{'MTR_RESULT_FILE'} || 0;
-
-my $opt_skip_core;
-
-our $opt_check_testcases= 1;
-my $opt_mark_progress;
-my $opt_max_connections;
-our $opt_report_times= 0;
-
-my $opt_sleep;
-
-our $opt_retry= 1;
-our $opt_retry_failure= env_or_val(MTR_RETRY_FAILURE => 2);
-our $opt_testcase_timeout= $ENV{MTR_TESTCASE_TIMEOUT} || 15; # minutes
-our $opt_suite_timeout = $ENV{MTR_SUITE_TIMEOUT} || 360; # minutes
-our $opt_shutdown_timeout= $ENV{MTR_SHUTDOWN_TIMEOUT} || 10; # seconds
-our $opt_start_timeout = $ENV{MTR_START_TIMEOUT} || 180; # seconds
-
-sub suite_timeout { return $opt_suite_timeout * 60; };
-
-my $opt_wait_all;
-my $opt_user_args;
-my $opt_repeat= 1;
-my $opt_reorder= 1;
-my $opt_force_restart= 0;
-
-our $opt_user = "root";
-
-my %mysqld_logs;
-my $opt_debug_sync_timeout= 300; # Default timeout for WAIT_FOR actions.
-my $warn_seconds = 60;
-
-my $rebootstrap_re= '--innodb[-_](?:page[-_]size|checksum[-_]algorithm|undo[-_]tablespaces|log[-_]group[-_]home[-_]dir|data[-_]home[-_]dir)|data[-_]file[-_]path|force_rebootstrap';
-
-sub testcase_timeout ($) { return $opt_testcase_timeout * 60; }
-sub check_timeout ($) { return testcase_timeout($_[0]); }
-
-our $opt_warnings= 1;
-
-our %mysqld_variables;
-our @optional_plugins;
-
-my $source_dist= -d "../sql";
-
-my $opt_max_save_core= env_or_val(MTR_MAX_SAVE_CORE => 5);
-my $opt_max_save_datadir= env_or_val(MTR_MAX_SAVE_DATADIR => 20);
-my $opt_max_test_fail= env_or_val(MTR_MAX_TEST_FAIL => 10);
-my $opt_core_on_failure= 0;
-
-my $opt_parallel= $ENV{MTR_PARALLEL} || 1;
-my $opt_port_group_size = $ENV{MTR_PORT_GROUP_SIZE} || 20;
-
-# lock file to stop tests
-my $opt_stop_file= $ENV{MTR_STOP_FILE};
-# print messages when test suite is stopped (for buildbot)
-my $opt_stop_keep_alive= $ENV{MTR_STOP_KEEP_ALIVE};
-
-select(STDOUT);
-$| = 1; # Automatically flush STDOUT
-
-main();
-
-sub main {
- $ENV{MTR_PERL}=$^X;
-
- # Default, verbosity on
- report_option('verbose', 0);
-
- # 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.
- mtr_report("Logging: $0 ", join(" ", @ARGV));
-
- command_line_setup();
-
- # --help will not reach here, so now it's safe to assume we have binaries
- My::SafeProcess::find_bin();
-
- print "vardir: $opt_vardir\n";
- initialize_servers();
- init_timers();
-
- unless (IS_WINDOWS) {
- binmode(STDOUT,":via(My::Tee)") or die "binmode(STDOUT, :via(My::Tee)):$!";
- binmode(STDERR,":via(My::Tee)") or die "binmode(STDERR, :via(My::Tee)):$!";
- }
-
- mtr_report("Checking supported features...");
-
- executable_setup();
-
- # --debug[-common] implies we run debug server
- $opt_debug_server= 1 if $opt_debug || $opt_debug_common;
-
- if (using_extern())
- {
- # Connect to the running mysqld and find out what it supports
- collect_mysqld_features_from_running_server();
- }
- else
- {
- # Run the mysqld to find out what features are available
- collect_mysqld_features();
- }
- check_ssl_support();
- check_debug_support();
- environment_setup();
-
- if (!$opt_suites) {
- $opt_suites= join ',', collect_default_suites(@DEFAULT_SUITES);
- }
- mtr_report("Using suites: $opt_suites") unless @opt_cases;
-
- mtr_report("Collecting tests...");
- my $tests= collect_test_cases($opt_reorder, $opt_suites, \@opt_cases, \@opt_skip_test_list);
- mark_time_used('collect');
-
- mysql_install_db(default_mysqld(), "$opt_vardir/install.db") unless using_extern();
-
- if ($opt_dry_run)
- {
- for (@$tests) {
- print $_->fullname(), "\n";
- }
- exit 0;
- }
-
- if ($opt_gcov) {
- system './dgcov.pl --purge';
- }
-
- #######################################################################
- my $num_tests= $mtr_report::tests_total= @$tests;
- if ( $opt_parallel eq "auto" ) {
- # Try to find a suitable value for number of workers
- if (IS_WINDOWS)
- {
- $opt_parallel= $ENV{NUMBER_OF_PROCESSORS} || 1;
- }
- else
- {
- my $sys_info= My::SysInfo->new();
- $opt_parallel= $sys_info->num_cpus()+int($sys_info->min_bogomips()/500)-4;
- }
- my $max_par= $ENV{MTR_MAX_PARALLEL} || 8;
- $opt_parallel= $max_par if ($opt_parallel > $max_par);
- $opt_parallel= $num_tests if ($opt_parallel > $num_tests);
- $opt_parallel= 1 if ($opt_parallel < 1);
- mtr_report("Using parallel: $opt_parallel");
- }
- $ENV{MTR_PARALLEL} = $opt_parallel;
-
- if ($opt_parallel > 1 && ($opt_start_exit || $opt_stress)) {
- mtr_warning("Parallel cannot be used with --start-and-exit or --stress\n" .
- "Setting parallel to 1");
- $opt_parallel= 1;
- }
-
- # Create server socket on any free port
- my $server = new IO::Socket::INET
- (
- LocalAddr => 'localhost',
- Proto => 'tcp',
- Listen => $opt_parallel,
- );
- mtr_error("Could not create testcase server port: $!") unless $server;
- my $server_port = $server->sockport();
-
- if ($opt_resfile) {
- resfile_init("$opt_vardir/mtr-results.txt");
- print_global_resfile();
- }
-
- # Create child processes
- my %children;
- for my $child_num (1..$opt_parallel){
- my $child_pid= My::SafeProcess::Base::_safe_fork();
- if ($child_pid == 0){
- $server= undef; # Close the server port in child
- $tests= {}; # Don't need the tests list in child
-
- # Use subdir of var and tmp unless only one worker
- if ($opt_parallel > 1) {
- set_vardir("$opt_vardir/$child_num");
- $opt_tmpdir= "$opt_tmpdir/$child_num";
- }
-
- init_timers();
- run_worker($server_port, $child_num);
- exit(1);
- }
-
- $children{$child_pid}= 1;
- }
- #######################################################################
-
- mtr_report();
- mtr_print_thick_line();
- mtr_print_header($opt_parallel > 1);
-
- mark_time_used('init');
-
- my ($prefix, $fail, $completed, $extra_warnings)=
- run_test_server($server, $tests, $opt_parallel);
-
- exit(0) if $opt_start_exit;
-
- # Send Ctrl-C to any children still running
- kill("INT", keys(%children));
-
- if (!IS_WINDOWS) {
- # Wait for children to exit
- foreach my $pid (keys %children)
- {
- my $ret_pid= waitpid($pid, 0);
- if ($ret_pid != $pid){
- mtr_report("Unknown process $ret_pid exited");
- }
- else {
- delete $children{$ret_pid};
- }
- }
- }
-
- if ( not @$completed ) {
- my $test_name= mtr_grab_file($path_current_testlog);
- $test_name =~ s/^CURRENT_TEST:\s//;
- my $tinfo = My::Test->new(name => $test_name);
- $tinfo->{result}= 'MTR_RES_FAILED';
- $tinfo->{logfile}=$path_current_testlog;
- mtr_report_test($tinfo);
- mtr_error("Test suite aborted");
- }
-
- if ( @$completed != $num_tests){
-
- # Not all tests completed, failure
- mtr_report();
- mtr_report("Only ", int(@$completed), " of $num_tests completed.");
- }
-
- if ($opt_valgrind) {
- # Create minimalistic "test" for the reporting
- my $tinfo = My::Test->new
- (
- suite => { name => 'valgrind', },
- name => 'valgrind_report',
- );
- # Set dummy worker id to align report with normal tests
- $tinfo->{worker} = 0 if $opt_parallel > 1;
- if ($valgrind_reports) {
- $tinfo->{result}= 'MTR_RES_FAILED';
- $tinfo->{comment}= "Valgrind reported failures at shutdown, see above";
- $tinfo->{failures}= 1;
- } else {
- $tinfo->{result}= 'MTR_RES_PASSED';
- }
- mtr_report_test($tinfo);
- push @$completed, $tinfo;
- ++$num_tests
- }
-
- mtr_print_line();
-
- print_total_times($opt_parallel) if $opt_report_times;
- mtr_report_stats($prefix, $fail, $completed, $extra_warnings);
-
- if ($opt_gcov) {
- mtr_report("Running dgcov");
- system "./dgcov.pl --generate > $opt_vardir/last_changes.dgcov";
- }
-
- if ( @$completed != $num_tests)
- {
- mtr_error("Not all tests completed (only ". scalar(@$completed) .
- " of $num_tests)");
- }
-
- remove_vardir_subs() if $opt_clean_vardir;
-
- exit(0);
-}
-
-
-sub run_test_server ($$$) {
- my ($server, $tests, $childs) = @_;
-
- my $num_saved_cores= 0; # Number of core files saved in vardir/log/ so far.
- my $num_saved_datadir= 0; # Number of datadirs saved in vardir/log/ so far.
- my $num_failed_test= 0; # Number of tests failed so far
- my $test_failure= 0; # Set true if test suite failed
- my $extra_warnings= []; # Warnings found during server shutdowns
-
- my $completed= [];
- my %running;
- my $result;
- my $exe_mysqld= find_mysqld($bindir) || ""; # Used as hint to CoreDump
-
- my $suite_timeout= start_timer(suite_timeout());
-
- my $s= IO::Select->new();
- $s->add($server);
- while (1) {
- if ($opt_stop_file)
- {
- if (mtr_wait_lock_file($opt_stop_file, $opt_stop_keep_alive))
- {
- # We were waiting so restart timer process
- my $suite_timeout= start_timer(suite_timeout());
- }
- }
-
- mark_time_used('admin');
- my @ready = $s->can_read(1); # Wake up once every second
- mark_time_idle();
- foreach my $sock (@ready) {
- if ($sock == $server) {
- # New client connected
- my $child= $sock->accept();
- mtr_verbose("Client connected");
- $s->add($child);
- print $child "HELLO\n";
- }
- else {
- my $line= <$sock>;
- if (!defined $line) {
- # Client disconnected
- mtr_verbose("Child closed socket");
- $s->remove($sock);
- $sock->close;
- if (--$childs == 0){
- return ("Completed", $test_failure, $completed, $extra_warnings);
- }
- next;
- }
- chomp($line);
-
- if ($line eq 'TESTRESULT'){
- $result= My::Test::read_test($sock);
-
- # Report test status
- mtr_report_test($result);
-
- if ( $result->is_failed() ) {
-
- # Save the workers "savedir" in var/log
- my $worker_savedir= $result->{savedir};
- my $worker_savename= basename($worker_savedir);
- my $savedir= "$opt_vardir/log/$worker_savename";
-
- # Move any core files from e.g. mysqltest
- foreach my $coref (glob("core*"), glob("*.dmp"))
- {
- mtr_report(" - found '$coref', moving it to '$worker_savedir'");
- move($coref, $worker_savedir);
- }
-
- find(
- {
- no_chdir => 1,
- wanted => sub
- {
- my $core_file= $File::Find::name;
- my $core_name= basename($core_file);
-
- # Name beginning with core, not ending in .gz
- if (($core_name =~ /^core/ and $core_name !~ /\.gz$/)
- or (IS_WINDOWS and $core_name =~ /\.dmp$/))
- {
- # Ending with .dmp
- mtr_report(" - found '$core_name'",
- "($num_saved_cores/$opt_max_save_core)");
-
- My::CoreDump->show($core_file, $exe_mysqld, $opt_parallel);
-
- # Limit number of core files saved
- if ($num_saved_cores >= $opt_max_save_core)
- {
- mtr_report(" - deleting it, already saved",
- "$opt_max_save_core");
- unlink("$core_file");
- }
- else
- {
- mtr_compress_file($core_file) unless @opt_cases;
- ++$num_saved_cores;
- }
- }
- }
- },
- $worker_savedir);
-
- if ($num_saved_datadir >= $opt_max_save_datadir)
- {
- mtr_report(" - skipping '$worker_savedir/'");
- rmtree($worker_savedir);
- }
- else
- {
- mtr_report(" - saving '$worker_savedir/' to '$savedir/'");
- rename($worker_savedir, $savedir);
- $num_saved_datadir++;
- }
- resfile_print_test();
- $num_failed_test++ unless ($result->{retries} ||
- $result->{exp_fail});
-
- $test_failure= 1;
- if ( !$opt_force ) {
- # Test has failed, force is off
- push(@$completed, $result);
- if ($result->{'dont_kill_server'})
- {
- print $sock "BYE\n";
- next;
- }
- return ("Failure", 1, $completed, $extra_warnings);
- }
- elsif ($opt_max_test_fail > 0 and
- $num_failed_test >= $opt_max_test_fail) {
- push(@$completed, $result);
- mtr_report("Too many tests($num_failed_test) failed!",
- "Terminating...");
- return ("Too many failed", 1, $completed, $extra_warnings);
- }
- }
-
- resfile_print_test();
- # Retry test run after test failure
- my $retries= $result->{retries} || 2;
- my $test_has_failed= $result->{failures} || 0;
- if ($test_has_failed and $retries <= $opt_retry){
- # Test should be run one more time unless it has failed
- # too many times already
- my $tname= $result->{name};
- my $failures= $result->{failures};
- if ($opt_retry > 1 and $failures >= $opt_retry_failure){
- mtr_report("\nTest $tname has failed $failures times,",
- "no more retries!\n");
- }
- else {
- mtr_report("\nRetrying test $tname, ".
- "attempt($retries/$opt_retry)...\n");
- #saving the log file as filename.failed in case of retry
- if ( $result->is_failed() ) {
- my $worker_logdir= $result->{savedir};
- my $log_file_name=dirname($worker_logdir)."/".$result->{shortname}.".log";
-
- if (-e $log_file_name) {
- $result->{'logfile-failed'} = mtr_lastlinesfromfile($log_file_name, 20);
- } else {
- $result->{'logfile-failed'} = "";
- }
-
- rename $log_file_name, $log_file_name.".failed";
- }
- {
- local @$result{'retries', 'result'};
- delete $result->{result};
- $result->{retries}= $retries+1;
- $result->write_test($sock, 'TESTCASE');
- }
- push(@$completed, $result);
- next;
- }
- }
-
- # Repeat test $opt_repeat number of times
- my $repeat= $result->{repeat} || 1;
- if ($repeat < $opt_repeat)
- {
- $result->{retries}= 0;
- $result->{rep_failures}++ if $result->{failures};
- $result->{failures}= 0;
- delete($result->{result});
- $result->{repeat}= $repeat+1;
- $result->write_test($sock, 'TESTCASE');
- next;
- }
-
- # Remove from list of running
- mtr_error("'", $result->{name},"' is not known to be running")
- unless delete $running{$result->key()};
-
- # Save result in completed list
- push(@$completed, $result);
-
- }
- elsif ($line eq 'START'){
- ; # Send first test
- }
- elsif ($line eq 'WARNINGS'){
- my $fake_test= My::Test::read_test($sock);
- my $test_list= join (" ", @{$fake_test->{testnames}});
- push @$extra_warnings, $test_list;
- my $report= $fake_test->{'warnings'};
- mtr_report("***Warnings generated in error logs during shutdown ".
- "after running tests: $test_list\n\n$report");
- $test_failure= 1;
- if ( !$opt_force ) {
- # Test failure due to warnings, force is off
- return ("Warnings in log", 1, $completed, $extra_warnings);
- }
- next;
- }
- elsif ($line =~ /^SPENT/) {
- add_total_times($line);
- }
- elsif ($line eq 'VALGREP' && $opt_valgrind) {
- $valgrind_reports= 1;
- }
- else {
- mtr_error("Unknown response: '$line' from client");
- }
-
- # Find next test to schedule
- # - Try to use same configuration as worker used last time
-
- my $next;
- my $second_best;
- for(my $i= 0; $i <= @$tests; $i++)
- {
- my $t= $tests->[$i];
-
- last unless defined $t;
-
- if (run_testcase_check_skip_test($t)){
- # Move the test to completed list
- #mtr_report("skip - Moving test $i to completed");
- push(@$completed, splice(@$tests, $i, 1));
-
- # Since the test at pos $i was taken away, next
- # test will also be at $i -> redo
- redo;
- }
-
- # From secondary choices, we prefer to pick a 'long-running' test if
- # possible; this helps avoid getting stuck with a few of those at the
- # end of high --parallel runs, with most workers being idle.
- if (!defined $second_best ||
- ($t->{'long_test'} && !($tests->[$second_best]{'long_test'}))){
- #mtr_report("Setting second_best to $i");
- $second_best= $i;
- }
-
- # Smart allocation of next test within this thread.
-
- if ($opt_reorder and $opt_parallel > 1 and defined $result)
- {
- my $wid= $result->{worker};
- # Reserved for other thread, try next
- next if (defined $t->{reserved} and $t->{reserved} != $wid);
- if (! defined $t->{reserved})
- {
- # Force-restart not relevant when comparing *next* test
- $t->{criteria} =~ s/force-restart$/no-restart/;
- my $criteria= $t->{criteria};
- # Reserve similar tests for this worker, but not too many
- my $maxres= (@$tests - $i) / $opt_parallel + 1;
- for (my $j= $i+1; $j <= $i + $maxres; $j++)
- {
- my $tt= $tests->[$j];
- last unless defined $tt;
- last if $tt->{criteria} ne $criteria;
- $tt->{reserved}= $wid;
- }
- }
- }
-
- # At this point we have found next suitable test
- $next= splice(@$tests, $i, 1);
- last;
- }
-
- # Use second best choice if no other test has been found
- if (!$next and defined $second_best){
- #mtr_report("Take second best choice $second_best");
- mtr_error("Internal error, second best too large($second_best)")
- if $second_best > $#$tests;
- $next= splice(@$tests, $second_best, 1);
- delete $next->{reserved};
- }
-
- if ($next) {
- # We don't need this any more
- delete $next->{criteria};
- $next->write_test($sock, 'TESTCASE');
- $running{$next->key()}= $next;
- }
- else {
- # No more test, tell child to exit
- #mtr_report("Saying BYE to child");
- print $sock "BYE\n";
- }
- }
- }
-
- # ----------------------------------------------------
- # Check if test suite timer expired
- # ----------------------------------------------------
- if ( has_expired($suite_timeout) )
- {
- mtr_report("Test suite timeout! Terminating...");
- return ("Timeout", 1, $completed, $extra_warnings);
- }
- }
-}
-
-
-sub run_worker ($) {
- my ($server_port, $thread_num)= @_;
-
- $SIG{INT}= sub { exit(1); };
- $SIG{HUP}= sub { exit(1); };
-
- # Connect to server
- my $server = new IO::Socket::INET
- (
- PeerAddr => 'localhost',
- PeerPort => $server_port,
- Proto => 'tcp'
- );
- mtr_error("Could not connect to server at port $server_port: $!")
- unless $server;
-
- # --------------------------------------------------------------------------
- # Set worker name
- # --------------------------------------------------------------------------
- report_option('name',"worker[$thread_num]");
-
- # --------------------------------------------------------------------------
- # Set different ports per thread
- # --------------------------------------------------------------------------
- set_build_thread_ports($thread_num);
-
- # --------------------------------------------------------------------------
- # Turn off verbosity in workers, unless explicitly specified
- # --------------------------------------------------------------------------
- report_option('verbose', undef) if ($opt_verbose == 0);
-
- environment_setup();
-
- # Read hello from server which it will send when shared
- # resources have been setup
- my $hello= <$server>;
-
- setup_vardir();
- check_running_as_root();
-
- if ( using_extern() ) {
- create_config_file_for_extern(%opts_extern);
- }
-
- # Ask server for first test
- print $server "START\n";
-
- mark_time_used('init');
-
- while (my $line= <$server>){
- chomp($line);
- if ($line eq 'TESTCASE'){
- my $test= My::Test::read_test($server);
-
- # Clear comment and logfile, to avoid
- # reusing them from previous test
- delete($test->{'comment'});
- delete($test->{'logfile'});
-
- # A sanity check. Should this happen often we need to look at it.
- if (defined $test->{reserved} && $test->{reserved} != $thread_num) {
- my $tres= $test->{reserved};
- mtr_warning("Test reserved for w$tres picked up by w$thread_num");
- }
- $test->{worker} = $thread_num if $opt_parallel > 1;
-
- run_testcase($test, $server);
- #$test->{result}= 'MTR_RES_PASSED';
- # Send it back, now with results set
- $test->write_test($server, 'TESTRESULT');
- mark_time_used('restart');
- }
- elsif ($line eq 'BYE'){
- mtr_report("Server said BYE");
- # We need to gracefully shut down the servers to see any
- # Valgrind memory leak errors etc. since last server restart.
- if ($opt_warnings) {
- stop_servers(reverse all_servers());
- if(check_warnings_post_shutdown($server)) {
- # Warnings appeared in log file(s) during final server shutdown.
- exit(1);
- }
- }
- else {
- stop_all_servers($opt_shutdown_timeout);
- }
- mark_time_used('restart');
- my $valgrind_reports= 0;
- if ($opt_valgrind) {
- $valgrind_reports= valgrind_exit_reports();
- print $server "VALGREP\n" if $valgrind_reports;
- }
- if ( $opt_gprof ) {
- gprof_collect (find_mysqld($bindir), keys %gprof_dirs);
- }
- mark_time_used('admin');
- print_times_used($server, $thread_num);
- exit($valgrind_reports);
- }
- else {
- mtr_error("Could not understand server, '$line'");
- }
- }
-
- stop_all_servers();
-
- exit(1);
-}
-
-
-sub ignore_option {
- my ($opt, $value)= @_;
- mtr_report("Ignoring option '$opt'");
-}
-
-
-
-# Setup any paths that are $opt_vardir related
-sub set_vardir {
- ($opt_vardir)= @_;
-
- $path_vardir_trace= $opt_vardir;
- # Chop off any "c:", DBUG likes a unix path ex: c:/src/... => /src/...
- $path_vardir_trace=~ s/^\w://;
-
- # Location of my.cnf that all clients use
- $path_config_file= "$opt_vardir/my.cnf";
-
- $path_testlog= "$opt_vardir/log/mysqltest.log";
- $path_current_testlog= "$opt_vardir/log/current_test";
-
-}
-
-
-sub print_global_resfile {
- resfile_global("start_time", isotime $^T);
- resfile_global("user_id", $<);
- resfile_global("embedded-server", $opt_embedded_server ? 1 : 0);
- resfile_global("ps-protocol", $opt_ps_protocol ? 1 : 0);
- resfile_global("sp-protocol", $opt_sp_protocol ? 1 : 0);
- resfile_global("view-protocol", $opt_view_protocol ? 1 : 0);
- resfile_global("cursor-protocol", $opt_cursor_protocol ? 1 : 0);
- resfile_global("ssl", $opt_ssl ? 1 : 0);
- resfile_global("compress", $opt_compress ? 1 : 0);
- resfile_global("parallel", $opt_parallel);
- resfile_global("check-testcases", $opt_check_testcases ? 1 : 0);
- resfile_global("mariadbd", \@opt_extra_mysqld_opt);
- resfile_global("debug", $opt_debug ? 1 : 0);
- resfile_global("gcov", $opt_gcov ? 1 : 0);
- resfile_global("gprof", $opt_gprof ? 1 : 0);
- resfile_global("mem", $opt_mem);
- resfile_global("tmpdir", $opt_tmpdir);
- resfile_global("vardir", $opt_vardir);
- resfile_global("fast", $opt_fast ? 1 : 0);
- resfile_global("force-restart", $opt_force_restart ? 1 : 0);
- resfile_global("reorder", $opt_reorder ? 1 : 0);
- resfile_global("sleep", $opt_sleep);
- resfile_global("repeat", $opt_repeat);
- resfile_global("user", $opt_user);
- resfile_global("testcase-timeout", $opt_testcase_timeout);
- resfile_global("suite-timeout", $opt_suite_timeout);
- resfile_global("shutdown-timeout", $opt_shutdown_timeout ? 1 : 0);
- resfile_global("warnings", $opt_warnings ? 1 : 0);
- resfile_global("max-connections", $opt_max_connections);
- resfile_global("product", "MariaDB");
- resfile_global("xml-report", $opt_xml_report);
- # Somewhat hacky code to convert numeric version back to dot notation
- my $v1= int($mysql_version_id / 10000);
- my $v2= int(($mysql_version_id % 10000)/100);
- my $v3= $mysql_version_id % 100;
- resfile_global("version", "$v1.$v2.$v3");
-}
-
-
-
-sub command_line_setup {
- my $opt_comment;
- my $opt_usage;
- my $opt_list_options;
-
- # Read the command line options
- # Note: Keep list in sync with usage at end of this file
- Getopt::Long::Configure("pass_through");
- my %options=(
- # 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,
- 'non-blocking-api' => \$opt_non_blocking_api,
- 'ssl|with-openssl' => \$opt_ssl,
- 'skip-ssl' => \$opt_skip_ssl,
- 'compress' => \$opt_compress,
- 'vs-config=s' => \$opt_vs_config,
-
- # Max number of parallel threads to use
- 'parallel=s' => \$opt_parallel,
-
- # Config file to use as template for all tests
- 'defaults-file=s' => \&collect_option,
- # Extra config file to append to all generated configs
- 'defaults-extra-file=s' => \&collect_option,
-
- # Control what test suites or cases to run
- 'force+' => \$opt_force,
- 'suite|suites=s' => \$opt_suites,
- 'skip-rpl' => \&collect_option,
- 'skip-test=s' => \&collect_option,
- 'do-test=s' => \&collect_option,
- 'start-from=s' => \&collect_option,
- 'big-test+' => \$opt_big_test,
- 'combination=s' => \@opt_combinations,
- 'experimental=s' => \@opt_experimentals,
- # skip-im is deprecated and silently ignored
- 'skip-im' => \&ignore_option,
- 'staging-run' => \$opt_staging_run,
-
- # Specify ports
- 'build-thread|mtr-build-thread=i' => \$opt_build_thread,
- 'port-base|mtr-port-base=i' => \$opt_port_base,
- 'port-group-size=s' => \$opt_port_group_size,
-
- # Test case authoring
- 'record' => \$opt_record,
- 'check-testcases!' => \$opt_check_testcases,
- 'mark-progress' => \$opt_mark_progress,
-
- # Extra options used when starting mariadbd
- 'mariadbd=s' => \@opt_extra_mysqld_opt,
- 'mariadbd-env=s' => \@opt_mysqld_envs,
- # mysqld is an alias for mariadbd
- 'mysqld=s' => \@opt_extra_mysqld_opt,
- 'mysqld-env=s' => \@opt_mysqld_envs,
-
- # Run test on running server
- 'extern=s' => \%opts_extern, # Append to hash
-
- # Debugging
- 'debug' => \$opt_debug,
- 'debug-common' => \$opt_debug_common,
- 'debug-server' => \$opt_debug_server,
- 'max-save-core=i' => \$opt_max_save_core,
- 'max-save-datadir=i' => \$opt_max_save_datadir,
- 'max-test-fail=i' => \$opt_max_test_fail,
- 'core-on-failure' => \$opt_core_on_failure,
-
- # Coverage, profiling etc
- 'gcov' => \$opt_gcov,
- 'gprof' => \$opt_gprof,
- 'debug-sync-timeout=i' => \$opt_debug_sync_timeout,
-
- # Directories
- 'tmpdir=s' => \$opt_tmpdir,
- 'vardir=s' => \$opt_vardir,
- 'mem' => \$opt_mem,
- 'clean-vardir' => \$opt_clean_vardir,
- 'client-bindir=s' => \$path_client_bindir,
- 'client-libdir=s' => \$path_client_libdir,
-
- # Misc
- 'comment=s' => \$opt_comment,
- 'fast' => \$opt_fast,
- 'force-restart' => \$opt_force_restart,
- 'reorder!' => \$opt_reorder,
- 'enable-disabled' => \&collect_option,
- 'verbose+' => \$opt_verbose,
- 'verbose-restart' => \&report_option,
- 'sleep=i' => \$opt_sleep,
- 'start-dirty' => \$opt_start_dirty,
- 'start-and-exit' => \$opt_start_exit,
- 'start' => \$opt_start,
- 'user-args' => \$opt_user_args,
- 'wait-all' => \$opt_wait_all,
- 'print-testcases' => \&collect_option,
- 'repeat=i' => \$opt_repeat,
- 'retry=i' => \$opt_retry,
- 'retry-failure=i' => \$opt_retry_failure,
- 'timer!' => \&report_option,
- 'user=s' => \$opt_user,
- 'testcase-timeout=i' => \$opt_testcase_timeout,
- 'suite-timeout=i' => \$opt_suite_timeout,
- 'shutdown-timeout=i' => \$opt_shutdown_timeout,
- 'warnings!' => \$opt_warnings,
- 'timestamp' => \&report_option,
- 'timediff' => \&report_option,
- 'stop-file=s' => \$opt_stop_file,
- 'stop-keep-alive=i' => \$opt_stop_keep_alive,
- 'max-connections=i' => \$opt_max_connections,
- 'report-times' => \$opt_report_times,
- 'result-file' => \$opt_resfile,
- 'stress=s' => \$opt_stress,
- 'tail-lines=i' => \$opt_tail_lines,
- 'dry-run' => \$opt_dry_run,
-
- 'help|h' => \$opt_usage,
- # list-options is internal, not listed in help
- 'list-options' => \$opt_list_options,
- 'skip-test-list=s' => \@opt_skip_test_list,
- 'xml-report=s' => \$opt_xml_report,
-
- My::Debugger::options()
- );
-
- # fix options (that take an optional argument and *only* after = sign
- @ARGV = My::Debugger::fix_options(@ARGV);
- GetOptions(%options) or usage("Can't read options");
- usage("") if $opt_usage;
- list_options(\%options) if $opt_list_options;
-
- # --------------------------------------------------------------------------
- # Setup verbosity
- # --------------------------------------------------------------------------
- if ($opt_verbose != 0){
- report_option('verbose', $opt_verbose);
- }
-
- # Negative values aren't meaningful on integer options
- foreach(grep(/=i$/, keys %options))
- {
- if (defined ${$options{$_}} &&
- do { no warnings "numeric"; int ${$options{$_}} < 0})
- {
- my $v= (split /=/)[0];
- die("$v doesn't accept a negative value:");
- }
- }
-
- # Find the absolute path to the test directory
- $glob_mysql_test_dir= cwd();
- if ($glob_mysql_test_dir =~ / /)
- {
- die("Working directory \"$glob_mysql_test_dir\" contains space\n".
- "Bailing out, cannot function properly with space in path");
- }
- if (IS_CYGWIN)
- {
- # Use mixed path format i.e c:/path/to/
- $glob_mysql_test_dir= mixed_path($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.
- $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 "$basedir/bin" )
- {
- $basedir= dirname($basedir);
- }
- # For .deb, it's like RPM, but installed in /usr/share/mysql/mysql-test.
- # So move up one more directory level yet.
- if ( ! $source_dist and ! -d "$basedir/bin" )
- {
- $basedir= dirname($basedir);
- }
-
- # Respect MTR_BINDIR variable, which is typically set in to the
- # build directory in out-of-source builds.
- $bindir=$ENV{MTR_BINDIR}||$basedir;
-
- fix_vs_config_dir();
-
- # Look for the client binaries directory
- if ($path_client_bindir)
- {
- # --client-bindir=path set on command line, check that the path exists
- $path_client_bindir= mtr_path_exists($path_client_bindir);
- }
- else
- {
- $path_client_bindir= mtr_path_exists("$bindir/client_release",
- "$bindir/client_debug",
- "$bindir/client$opt_vs_config",
- "$bindir/client",
- "$bindir/bin");
- }
-
- # Look for language files and charsetsdir, use same share
- $path_language= mtr_path_exists("$bindir/share/mariadb",
- "$bindir/share/mysql",
- "$bindir/sql/share",
- "$bindir/share");
- my $path_share= $path_language;
- $path_charsetsdir = mtr_path_exists("$basedir/share/mariadb/charsets",
- "$basedir/share/mysql/charsets",
- "$basedir/sql/share/charsets",
- "$basedir/share/charsets");
- if ( $opt_comment )
- {
- mtr_report();
- mtr_print_thick_line('#');
- mtr_report("# $opt_comment");
- mtr_print_thick_line('#');
- }
-
- if ( @opt_experimentals )
- {
- # $^O on Windows considered not generic enough
- my $plat= (IS_WINDOWS) ? 'windows' : $^O;
-
- # read the list of experimental test cases from the files specified on
- # the command line
- $experimental_test_cases = [];
- foreach my $exp_file (@opt_experimentals)
- {
- open(FILE, "<", $exp_file)
- or mtr_error("Can't read experimental file: $exp_file");
- mtr_report("Using experimental file: $exp_file");
- while(<FILE>) {
- chomp;
- # remove comments (# foo) at the beginning of the line, or after a
- # blank at the end of the line
- s/(\s+|^)#.*$//;
- # If @ platform specifier given, use this entry only if it contains
- # @<platform> or @!<xxx> where xxx != platform
- if (/\@.*/)
- {
- next if (/\@!$plat/);
- next unless (/\@$plat/ or /\@!/);
- # Then remove @ and everything after it
- s/\@.*$//;
- }
- # remove whitespace
- s/^\s+//;
- s/\s+$//;
- # if nothing left, don't need to remember this line
- if ( $_ eq "" ) {
- next;
- }
- # remember what is left as the name of another test case that should be
- # treated as experimental
- print " - $_\n";
- push @$experimental_test_cases, $_;
- }
- close FILE;
- }
- }
-
- 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);
- }
- }
-
- if ( @opt_cases )
- {
- # Run big tests if explicitly specified on command line
- $opt_big_test= 1;
- }
-
- # --------------------------------------------------------------------------
- # Find out type of logging that are being used
- # --------------------------------------------------------------------------
- foreach my $arg ( @opt_extra_mysqld_opt )
- {
- if ( $arg =~ /binlog[-_]format=(\S+)/ )
- {
- # Save this for collect phase
- collect_option('binlog-format', $1);
- mtr_report("Using binlog format '$1'");
- }
- }
-
-
- # --------------------------------------------------------------------------
- # Find out default storage engine being used(if any)
- # --------------------------------------------------------------------------
- foreach my $arg ( @opt_extra_mysqld_opt )
- {
- if ( $arg =~ /default-storage-engine=(\S+)/ )
- {
- # Save this for collect phase
- collect_option('default-storage-engine', $1);
- mtr_report("Using default engine '$1'")
- }
- }
-
- if (IS_WINDOWS and defined $opt_mem) {
- mtr_report("--mem not supported on Windows, ignored");
- $opt_mem= undef;
- }
-
- if ($opt_port_base ne "auto")
- {
- if (my $rem= $opt_port_base % 10)
- {
- mtr_warning ("Port base $opt_port_base rounded down to multiple of 10");
- $opt_port_base-= $rem;
- }
- $opt_build_thread= $opt_port_base / 10 - 1000;
- }
-
- # --------------------------------------------------------------------------
- # 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 find a suitable location
- my @tmpfs_locations= ("/run/shm", "/dev/shm", "/tmp");
-
- # Use $ENV{'MTR_MEM'} as first location to look (if defined)
- unshift(@tmpfs_locations, $ENV{'MTR_MEM'}) if defined $ENV{'MTR_MEM'};
-
- foreach my $fs (@tmpfs_locations)
- {
- if ( -d $fs && ! -l $fs && -w $fs )
- {
- my $template= "var_${opt_build_thread}_XXXX";
- $opt_mem= tempdir( $template, DIR => $fs, CLEANUP => 0);
- last;
- }
- }
- }
-
- # --------------------------------------------------------------------------
- # Set the "var/" directory, the base for everything else
- # --------------------------------------------------------------------------
- my $vardir_location= (defined $ENV{MTR_BINDIR}
- ? "$ENV{MTR_BINDIR}/mysql-test"
- : $glob_mysql_test_dir);
- $vardir_location= realpath $vardir_location;
- $default_vardir= "$vardir_location/var";
-
- if ( ! $opt_vardir )
- {
- $opt_vardir= $default_vardir;
- }
-
- # We make the path absolute, as the server will do a chdir() before usage
- unless ( $opt_vardir =~ m,^/, or
- (IS_WINDOWS and $opt_vardir =~ m,^[a-z]:[/\\],i) )
- {
- # Make absolute path, relative test dir
- $opt_vardir= "$glob_mysql_test_dir/$opt_vardir";
- }
-
- set_vardir($opt_vardir);
-
- # --------------------------------------------------------------------------
- # Set the "tmp" directory
- # --------------------------------------------------------------------------
- if ( ! $opt_tmpdir )
- {
- $opt_tmpdir= "$opt_vardir/tmp" unless $opt_tmpdir;
-
- if (check_socket_path_length("$opt_tmpdir/mysql_testsocket.sock"))
- {
- mtr_report("Too long tmpdir path '$opt_tmpdir'",
- " creating a shorter one...");
-
- # Create temporary directory in standard location for temporary files
- $opt_tmpdir= tempdir( TMPDIR => 1, CLEANUP => 0 );
- mtr_report(" - using tmpdir: '$opt_tmpdir'\n");
-
- # Remember pid that created dir so it's removed by correct process
- $opt_tmpdir_pid= $$;
- }
- }
- $opt_tmpdir =~ s,/+$,,; # Remove ending slash if any
-
- # --------------------------------------------------------------------------
- # fast option
- # --------------------------------------------------------------------------
- if ($opt_fast){
- $opt_shutdown_timeout= 0; # Kill processes instead of nice shutdown
- }
-
- # --------------------------------------------------------------------------
- # Check parallel value
- # --------------------------------------------------------------------------
- if ($opt_parallel ne "auto" && $opt_parallel < 1)
- {
- mtr_error("0 or negative parallel value makes no sense, use 'auto' or positive number");
- }
-
- # --------------------------------------------------------------------------
- # Record flag
- # --------------------------------------------------------------------------
- if ( $opt_record and ! @opt_cases )
- {
- mtr_error("Will not run in record mode without a specific test case");
- }
-
- if ( $opt_record ) {
- # Use only one worker with --record
- $opt_parallel= 1;
- }
-
- # --------------------------------------------------------------------------
- # Embedded server flag
- # --------------------------------------------------------------------------
- if ( $opt_embedded_server )
- {
- $opt_skip_ssl= 1; # Turn off use of SSL
-
- # Turn off use of bin log
- push(@opt_extra_mysqld_opt, "--skip-log-bin");
-
- if ( using_extern() )
- {
- mtr_error("Can't use --extern with --embedded-server");
- }
- }
-
- # --------------------------------------------------------------------------
- # Big test and staging_run flags
- # --------------------------------------------------------------------------
- if ( $opt_big_test )
- {
- $ENV{'BIG_TEST'}= 1;
- }
- $ENV{'STAGING_RUN'}= $opt_staging_run;
-
- # --------------------------------------------------------------------------
- # Gcov flag
- # --------------------------------------------------------------------------
- if ( ($opt_gcov or $opt_gprof) and ! $source_dist )
- {
- mtr_error("Coverage test needs the source - please use source dist");
- }
-
- $ENV{ASAN_OPTIONS}= "abort_on_error=1:" . ($ENV{ASAN_OPTIONS} || '');
- $ENV{ASAN_OPTIONS}= "suppressions=${glob_mysql_test_dir}/asan.supp:" .
- $ENV{ASAN_OPTIONS}
- if -f "$glob_mysql_test_dir/asan.supp" and not IS_WINDOWS;
- # The following can be useful when a test fails without any asan report
- # on stderr like with openssl_1.test
- # $ENV{ASAN_OPTIONS}= "log_path=${opt_vardir}/log/asan:" . $ENV{ASAN_OPTIONS};
-
- # Add leak suppressions
- $ENV{LSAN_OPTIONS}= "suppressions=${glob_mysql_test_dir}/lsan.supp:print_suppressions=0"
- if -f "$glob_mysql_test_dir/lsan.supp" and not IS_WINDOWS;
-
- mtr_verbose("ASAN_OPTIONS=$ENV{ASAN_OPTIONS}");
-
- # --------------------------------------------------------------------------
- # Modified behavior with --start options
- # --------------------------------------------------------------------------
- if ($opt_start or $opt_start_dirty or $opt_start_exit) {
- collect_option ('quick-collect', 1);
- $start_only= 1;
- }
- if ($opt_debug)
- {
- $opt_testcase_timeout= 7 * 24 * 60;
- $opt_suite_timeout= 7 * 24 * 60;
- $opt_retry= 1;
- $opt_retry_failure= 1;
- }
-
- # --------------------------------------------------------------------------
- # Check use of user-args
- # --------------------------------------------------------------------------
-
- if ($opt_user_args) {
- mtr_error("--user-args only valid with --start options")
- unless $start_only;
- mtr_error("--user-args cannot be combined with named suites or tests")
- if $opt_suites || @opt_cases;
- }
-
- # --------------------------------------------------------------------------
- # Check use of wait-all
- # --------------------------------------------------------------------------
-
- if ($opt_wait_all && ! $start_only)
- {
- mtr_error("--wait-all can only be used with --start options");
- }
-
- # --------------------------------------------------------------------------
- # Gather stress-test options and modify behavior
- # --------------------------------------------------------------------------
-
- if ($opt_stress)
- {
- $opt_stress=~ s/,/ /g;
- $opt_user_args= 1;
- mtr_error("--stress cannot be combined with named ordinary suites or tests")
- if $opt_suites || @opt_cases;
- $opt_suites="stress";
- @opt_cases= ("wrapper");
- $ENV{MST_OPTIONS}= $opt_stress;
- }
-
- # --------------------------------------------------------------------------
- # Check timeout arguments
- # --------------------------------------------------------------------------
-
- mtr_error("Invalid value '$opt_testcase_timeout' supplied ".
- "for option --testcase-timeout")
- if ($opt_testcase_timeout <= 0);
- mtr_error("Invalid value '$opt_suite_timeout' supplied ".
- "for option --testsuite-timeout")
- if ($opt_suite_timeout <= 0);
-
- if ($opt_debug_common)
- {
- $opt_debug= 1;
- $debug_d= "d,query,info,error,enter,exit";
- }
-}
-
-
-#
-# 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 limitation 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
-#
-sub set_build_thread_ports($) {
- my $thread= shift || 0;
-
- if ( lc($opt_build_thread) eq 'auto' ) {
- my $found_free = 0;
- $build_thread = 300; # Start attempts from here
- my $build_thread_upper = $build_thread + ($opt_parallel > 1500
- ? 3000
- : 2 * $opt_parallel) + 300;
- while (! $found_free)
- {
- $build_thread= mtr_get_unique_id($build_thread, $build_thread_upper);
- if ( !defined $build_thread ) {
- mtr_error("Could not get a unique build thread id");
- }
- $found_free= check_ports_free($build_thread);
- # If not free, release and try from next number
- if (! $found_free) {
- mtr_release_unique_id();
- $build_thread++;
- }
- }
- }
- else
- {
- $build_thread = $opt_build_thread + $thread - 1;
- if (! check_ports_free($build_thread)) {
- # Some port was not free(which one has already been printed)
- mtr_error("Some port(s) was not free")
- }
- }
- $ENV{MTR_BUILD_THREAD}= $build_thread;
-
- # Calculate baseport
- $baseport= $build_thread * $opt_port_group_size + 10000;
- if ( $baseport < 5001 or $baseport + $opt_port_group_size >= 32767 )
- {
- mtr_error("MTR_BUILD_THREAD number results in a port",
- "outside 5001 - 32767",
- "($baseport - $baseport + $opt_port_group_size)");
- }
-
- mtr_report("Using MTR_BUILD_THREAD $build_thread,",
- "with reserved ports $baseport..".($baseport+($opt_port_group_size-1)));
-
-}
-
-
-sub collect_mysqld_features {
- #
- # Execute "mysqld --no-defaults --help --verbose" to get a
- # list of all features and settings
- #
- # --no-defaults and --skip-grant-tables are to avoid loading
- # system-wide configs and plugins
- #
- # --datadir must exist, mysqld will chdir into it
- #
- my $args;
- mtr_init_args(\$args);
- mtr_add_arg($args, "--no-defaults");
- mtr_add_arg($args, "--datadir=.");
- mtr_add_arg($args, "--basedir=%s", $basedir);
- mtr_add_arg($args, "--lc-messages-dir=%s", $path_language);
- mtr_add_arg($args, "--skip-grant-tables");
- mtr_add_arg($args, "--log-warnings=0");
- mtr_add_arg($args, "--log-slow-admin-statements=0");
- mtr_add_arg($args, "--log-queries-not-using-indexes=0");
- mtr_add_arg($args, "--log-slow-slave-statements=0");
- mtr_add_arg($args, "--verbose");
- mtr_add_arg($args, "--help");
-
- my $exe_mysqld= find_mysqld($bindir);
- my $cmd= join(" ", $exe_mysqld, @$args);
-
- mtr_verbose("cmd: $cmd");
-
- my $list= `$cmd`;
-
- # to simplify the parsing, we'll merge all nicely formatted --help texts
- $list =~ s/\n {22}(\S)/ $1/g;
-
- my @list= split '\n', $list;
-
- $mysql_version_id= 0;
- while (defined(my $line = shift @list)){
- if ($line =~ /^\Q$exe_mysqld\E\s+Ver\s(\d+)\.(\d+)\.(\d+)(\S*)/ ) {
- $mysql_version_id= $1*10000 + $2*100 + $3;
- mtr_report("MariaDB Version $1.$2.$3$4");
- last;
- }
- }
- mtr_error("Could not find version of MariaDB")
- unless $mysql_version_id > 0;
-
- for (@list)
- {
- # first part of the help - command-line options.
- if (/Copyright/ .. /^-{30,}/) {
- # here we want to detect all not mandatory plugins
- # they are listed in the --help output as
- # --archive[=name]
- # Enable or disable ARCHIVE plugin. Possible values are ON, OFF,
- # FORCE (don't start if the plugin fails to load),
- # FORCE_PLUS_PERMANENT (like FORCE, but the plugin can not be uninstalled).
- # For Innodb I_S plugins that are referenced in sys schema
- # do not make them optional, to prevent diffs in tests.
- push @optional_plugins, $1
- if /^ --([-a-z0-9]+)\[=name\] +Enable or disable \w+ plugin. One of: ON, OFF, FORCE/
- and $1 ne "innodb-metrics"
- and $1 ne "innodb-buffer-page"
- and $1 ne "innodb-lock-waits"
- and $1 ne "innodb-locks"
- and $1 ne "innodb-trx";
- next;
- }
-
- last if /^$/; # then goes a list of variables, it ends with an empty line
-
- # Put a variable into hash
- /^([\S]+)[ \t]+(.*?)\r?$/ or die "Could not parse mysqld --help: $_\n";
- $mysqld_variables{$1}= $2;
- }
- mtr_error("Could not find variabes list") unless %mysqld_variables;
-}
-
-
-sub collect_mysqld_features_from_running_server ()
-{
- my $mysql= mtr_exe_exists("$path_client_bindir/mysql");
-
- my $args;
- mtr_init_args(\$args);
-
- mtr_add_arg($args, "--no-defaults");
- mtr_add_arg($args, "--user=%s", $opt_user);
-
- while (my ($option, $value)= each( %opts_extern )) {
- mtr_add_arg($args, "--$option=$value");
- }
-
- mtr_add_arg($args, "--silent"); # Tab separated output
- mtr_add_arg($args, "-e '%s'", "use mysql; SHOW VARIABLES");
- my $cmd= "$mysql " . join(' ', @$args);
- mtr_verbose("cmd: $cmd");
-
- my $list = `$cmd` or
- mtr_error("Could not connect to extern server using command: '$cmd'");
- foreach my $line (split('\n', $list ))
- {
- # Put variables into hash
- if ( $line =~ /^([\S]+)[ \t]+(.*?)\r?$/ )
- {
- my $name= $1;
- my $value=$2;
- $name =~ s/_/-/g;
- # print "$name=\"$value\"\n";
- $mysqld_variables{$name}= $value;
- }
- }
-
- # Parse version
- my $version_str= $mysqld_variables{'version'};
- if ( $version_str =~ /^([0-9]*)\.([0-9]*)\.([0-9]*)([^\s]*)/ )
- {
- #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("MariaDB Version $1.$2.$3");
- $mysql_version_extra= $4;
- }
- mtr_error("Could not find version of MariaDBL") unless $mysql_version_id;
-}
-
-sub find_mysqld {
-
- my ($mysqld_basedir)= $ENV{MTR_BINDIR}|| @_;
-
- my @mysqld_names= ("mariadbd", "mysqld", "mysqld-max-nt", "mysqld-max",
- "mysqld-nt");
-
- if ( $opt_debug_server ){
- # Put mysqld-debug first in the list of binaries to look for
- mtr_verbose("Adding mysqld-debug first in list of binaries to look for");
- unshift(@mysqld_names, "mysqld-debug");
- }
-
- return my_find_bin($bindir,
- ["sql", "libexec", "sbin", "bin"],
- [@mysqld_names]);
-}
-
-
-sub executable_setup () {
-
- $exe_patch='patch' if `patch -v`;
-
- # Look for the client binaries
- $exe_mysqladmin= mtr_exe_exists("$path_client_bindir/mysqladmin");
- $exe_mysql= mtr_exe_exists("$path_client_bindir/mysql");
- $exe_mysql_plugin= mtr_exe_exists("$path_client_bindir/mysql_plugin");
- $exe_mariadb_conv= mtr_exe_exists("$path_client_bindir/mariadb-conv");
-
- $exe_mysql_embedded= mtr_exe_maybe_exists("$basedir/libmysqld/examples/mysql_embedded");
-
- # Look for mysqltest executable
- if ( $opt_embedded_server )
- {
- $exe_mysqltest=
- mtr_exe_exists("$bindir/libmysqld/examples$opt_vs_config/mysqltest_embedded",
- "$path_client_bindir/mysqltest_embedded");
- }
- else
- {
- if ( defined $ENV{'MYSQL_TEST'} )
- {
- $exe_mysqltest=$ENV{'MYSQL_TEST'};
- print "===========================================================\n";
- print "WARNING:The mysqltest binary is fetched from $exe_mysqltest\n";
- print "===========================================================\n";
- }
- else
- {
- $exe_mysqltest= mtr_exe_exists("$path_client_bindir/mysqltest");
- }
- }
-
-}
-
-
-sub client_debug_arg($$) {
- my ($args, $client_name)= @_;
-
- # Workaround for Bug #50627: drop any debug opt
- return if $client_name =~ /^mysqlbinlog/;
-
- if ( $opt_debug ) {
- mtr_add_arg($args,
- "--loose-debug=$debug_d:t:A,%s/log/%s.trace",
- $path_vardir_trace, $client_name)
- }
-}
-
-
-sub client_arguments ($;$) {
- my $client_name= shift;
- my $group_suffix= shift;
- my $client_exe= mtr_exe_exists("$path_client_bindir/$client_name");
-
- my $args;
- mtr_init_args(\$args);
- mtr_add_arg($args, "--defaults-file=%s", $path_config_file);
- if (defined($group_suffix)) {
- mtr_add_arg($args, "--defaults-group-suffix=%s", $group_suffix);
- client_debug_arg($args, "$client_name-$group_suffix");
- }
- else
- {
- client_debug_arg($args, $client_name);
- }
- return mtr_args2str($client_exe, @$args);
-}
-
-
-sub mysqlbinlog_arguments () {
- my $exe= mtr_exe_exists("$path_client_bindir/mysqlbinlog");
-
- my $args;
- mtr_init_args(\$args);
- mtr_add_arg($args, "--defaults-file=%s", $path_config_file);
- mtr_add_arg($args, "--local-load=%s", $opt_tmpdir);
- client_debug_arg($args, "mysqlbinlog");
- return mtr_args2str($exe, @$args);
-}
-
-
-sub mysqlslap_arguments () {
- my $exe= mtr_exe_maybe_exists("$path_client_bindir/mysqlslap");
- if ( $exe eq "" ) {
- # mysqlap was not found
-
- if (defined $mysql_version_id and $mysql_version_id >= 50100 ) {
- mtr_error("Could not find the mysqlslap binary");
- }
- return ""; # Don't care about mysqlslap
- }
-
- my $args;
- mtr_init_args(\$args);
- mtr_add_arg($args, "--defaults-file=%s", $path_config_file);
- client_debug_arg($args, "mysqlslap");
- return mtr_args2str($exe, @$args);
-}
-
-
-sub mysqldump_arguments ($) {
- my($group_suffix) = @_;
- my $exe= mtr_exe_exists("$path_client_bindir/mysqldump");
-
- my $args;
- mtr_init_args(\$args);
- mtr_add_arg($args, "--defaults-file=%s", $path_config_file);
- mtr_add_arg($args, "--defaults-group-suffix=%s", $group_suffix);
- client_debug_arg($args, "mysqldump-$group_suffix");
- return mtr_args2str($exe, @$args);
-}
-
-
-sub mysql_client_test_arguments(){
- my $exe;
- # mysql_client_test executable may _not_ exist
- if ( $opt_embedded_server ) {
- $exe= mtr_exe_maybe_exists(
- "$bindir/libmysqld/examples$opt_vs_config/mysql_client_test_embedded",
- "$bindir/bin/mysql_client_test_embedded");
- } else {
- $exe= mtr_exe_maybe_exists("$bindir/tests$opt_vs_config/mysql_client_test",
- "$bindir/bin/mysql_client_test");
- }
-
- my $args;
- mtr_init_args(\$args);
- mtr_add_arg($args, "--defaults-file=%s", $path_config_file);
- mtr_add_arg($args, "--testcase");
- mtr_add_arg($args, "--vardir=$opt_vardir");
- client_debug_arg($args,"mysql_client_test");
- my $ret=mtr_args2str($exe, @$args);
- return $ret;
-}
-
-sub tool_arguments ($$) {
- my($sedir, $tool_name) = @_;
- my $exe= my_find_bin($bindir,
- [$sedir, "bin"],
- $tool_name);
-
- my $args;
- mtr_init_args(\$args);
- client_debug_arg($args, $tool_name);
- return mtr_args2str($exe, @$args);
-}
-
-# This is not used to actually start a mysqld server, just to allow test
-# scripts to run the mysqld binary to test invalid server startup options.
-sub mysqld_client_arguments () {
- my $default_mysqld= default_mysqld();
- my $exe = find_mysqld($bindir);
- my $args;
- mtr_init_args(\$args);
- mtr_add_arg($args, "--no-defaults");
- mtr_add_arg($args, "--basedir=%s", $basedir);
- mtr_add_arg($args, "--character-sets-dir=%s", $default_mysqld->value("character-sets-dir"));
- mtr_add_arg($args, "--language=%s", $default_mysqld->value("language"));
- return mtr_args2str($exe, @$args);
-}
-
-
-sub have_maria_support () {
- my $maria_var= $mysqld_variables{'aria-recover-options'};
- return defined $maria_var;
-}
-
-
-sub environment_setup {
-
- umask(022);
-
- $ENV{'USE_RUNNING_SERVER'}= using_extern();
-
- my @ld_library_paths;
-
- if ($path_client_libdir)
- {
- # Use the --client-libdir passed on commandline
- push(@ld_library_paths, "$path_client_libdir");
- }
- else
- {
- # 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, "$basedir/libmysql/.libs/",
- "$basedir/libmysql_r/.libs/",
- "$basedir/zlib/.libs/");
- if ($^O eq "darwin")
- {
- # it is MAC OS and we have to add dynamic libraries paths
- push @ld_library_paths, grep {<$_/*.dylib>}
- (<$bindir/storage/*/.libs/>,<$bindir/plugin/*/.libs/>,
- <$bindir/plugin/*/*/.libs/>,<$bindir/storage/*/*/.libs>);
- }
- }
- else
- {
- push(@ld_library_paths, "$basedir/lib", "$basedir/lib/mysql");
- }
- }
-
- $ENV{'LD_LIBRARY_PATH'}= join(":", @ld_library_paths,
- $ENV{'LD_LIBRARY_PATH'} ?
- split(':', $ENV{'LD_LIBRARY_PATH'}) : ());
-
- My::Debugger::pre_setup();
-
- 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'}");
-
- # The environment variable used for shared libs on AIX
- $ENV{'SHLIB_PATH'}= join(":", @ld_library_paths,
- $ENV{'SHLIB_PATH'} ?
- split(':', $ENV{'SHLIB_PATH'}) : ());
- mtr_debug("SHLIB_PATH: $ENV{'SHLIB_PATH'}");
-
- # The environment variable used for shared libs on hp-ux
- $ENV{'LIBPATH'}= join(":", @ld_library_paths,
- $ENV{'LIBPATH'} ?
- split(':', $ENV{'LIBPATH'}) : ());
- mtr_debug("LIBPATH: $ENV{'LIBPATH'}");
-
- $ENV{'UMASK'}= "0660"; # The octal *string*
- $ENV{'UMASK_DIR'}= "0770"; # The octal *string*
-
- #
- # MariaDB tests can produce output in various character sets
- # (especially, ctype_xxx.test). To avoid confusing Perl
- # with output which is incompatible with the current locale
- # settings, we reset the current values of LC_ALL and LC_CTYPE to "C".
- # For details, please see
- # Bug#27636 tests fails if LC_* variables set to *_*.UTF-8
- #
- $ENV{'LC_ALL'}= "C";
- $ENV{'LC_CTYPE'}= "C";
- $ENV{'LC_COLLATE'}= "C";
-
- $ENV{'OPENSSL_CONF'}= $mysqld_variables{'version-ssl-library'} gt 'OpenSSL 1.1.1'
- ? "$glob_mysql_test_dir/lib/openssl.cnf" : '/dev/null';
-
- $ENV{'MYSQL_TEST_DIR'}= $glob_mysql_test_dir;
- $ENV{'DEFAULT_MASTER_PORT'}= $mysqld_variables{'port'};
- $ENV{'MYSQL_TMP_DIR'}= $opt_tmpdir;
- $ENV{'MYSQLTEST_VARDIR'}= $opt_vardir;
- $ENV{'MYSQLTEST_REAL_VARDIR'}= realpath $opt_vardir;
- $ENV{'MYSQL_BINDIR'}= $bindir;
- $ENV{'MYSQL_SHAREDIR'}= $path_language;
- $ENV{'MYSQL_CHARSETSDIR'}= $path_charsetsdir;
-
- if (IS_WINDOWS)
- {
- $ENV{'SECURE_LOAD_PATH'}= $glob_mysql_test_dir."\\std_data";
- }
- else
- {
- $ENV{'SECURE_LOAD_PATH'}= $glob_mysql_test_dir."/std_data";
- }
-
- #
- # Some stupid^H^H^H^H^H^Hignorant network providers set up "wildcard DNS"
- # servers that return some given web server address for any lookup of a
- # non-existent host name. This confuses test cases that want to test the
- # behaviour when connecting to a non-existing host, so we need to be able
- # to disable those tests when DNS is broken.
- #
- $ENV{HAVE_BROKEN_DNS}= defined(gethostbyname('invalid_hostname'));
-
- # ----------------------------------------------------
- # mysql clients
- # ----------------------------------------------------
- $ENV{'MYSQL_CHECK'}= client_arguments("mysqlcheck");
- $ENV{'MYSQL_DUMP'}= mysqldump_arguments(".1");
- $ENV{'MYSQL_DUMP_SLAVE'}= mysqldump_arguments(".2");
- $ENV{'MYSQL_SLAP'}= mysqlslap_arguments();
- $ENV{'MYSQL_IMPORT'}= client_arguments("mysqlimport");
- $ENV{'MYSQL_SHOW'}= client_arguments("mysqlshow");
- $ENV{'MYSQL_BINLOG'}= mysqlbinlog_arguments();
- $ENV{'MYSQL'}= client_arguments("mysql");
- $ENV{'MYSQL_SLAVE'}= client_arguments("mysql", ".2");
- $ENV{'MYSQL_UPGRADE'}= client_arguments("mysql_upgrade");
- $ENV{'MYSQLADMIN'}= client_arguments("mysqladmin");
- $ENV{'MYSQL_CLIENT_TEST'}= mysql_client_test_arguments();
- $ENV{'EXE_MYSQL'}= $exe_mysql;
- $ENV{'MYSQL_PLUGIN'}= $exe_mysql_plugin;
- $ENV{'MYSQL_EMBEDDED'}= $exe_mysql_embedded;
- $ENV{'MARIADB_CONV'}= "$exe_mariadb_conv --character-sets-dir=$path_charsetsdir";
- if(IS_WINDOWS)
- {
- $ENV{'MYSQL_INSTALL_DB_EXE'}= mtr_exe_exists("$bindir/sql$opt_vs_config/mysql_install_db",
- "$bindir/bin/mysql_install_db");
- }
-
- my $client_config_exe=
- mtr_exe_maybe_exists(
- "$bindir/libmariadb/mariadb_config$opt_vs_config/mariadb_config",
- "$bindir/bin/mariadb_config");
- if ($client_config_exe)
- {
- my $tls_info= `$client_config_exe --tlsinfo`;
- ($ENV{CLIENT_TLS_LIBRARY},$ENV{CLIENT_TLS_LIBRARY_VERSION})=
- split(/ /, $tls_info, 2);
- }
- my $exe_mysqld= find_mysqld($basedir);
- $ENV{'MYSQLD'}= $exe_mysqld;
- my $extra_opts= join (" ", @opt_extra_mysqld_opt);
- $ENV{'MYSQLD_CMD'}= "$exe_mysqld --defaults-group-suffix=.1 ".
- "--defaults-file=$path_config_file $extra_opts";
-
- # ----------------------------------------------------
- # bug25714 executable may _not_ exist in
- # some versions, test using it should be skipped
- # ----------------------------------------------------
- my $exe_bug25714=
- mtr_exe_maybe_exists("$bindir/tests$opt_vs_config/bug25714");
- $ENV{'MYSQL_BUG25714'}= native_path($exe_bug25714);
-
- # ----------------------------------------------------
- # mysql_fix_privilege_tables.sql
- # ----------------------------------------------------
- my $file_mysql_fix_privilege_tables=
- mtr_file_exists("$bindir/scripts/mysql_fix_privilege_tables.sql",
- "$bindir/share/mysql_fix_privilege_tables.sql",
- "$bindir/share/mariadb/mysql_fix_privilege_tables.sql",
- "$bindir/share/mysql/mysql_fix_privilege_tables.sql");
- $ENV{'MYSQL_FIX_PRIVILEGE_TABLES'}= $file_mysql_fix_privilege_tables;
-
- # ----------------------------------------------------
- # my_print_defaults
- # ----------------------------------------------------
- my $exe_my_print_defaults=
- mtr_exe_exists("$bindir/extra$opt_vs_config/my_print_defaults",
- "$path_client_bindir/my_print_defaults");
- $ENV{'MYSQL_MY_PRINT_DEFAULTS'}= native_path($exe_my_print_defaults);
-
- # ----------------------------------------------------
- # myisam tools
- # ----------------------------------------------------
- $ENV{'MYISAMLOG'}= tool_arguments("storage/myisam", "myisamlog", );
- $ENV{'MYISAMCHK'}= tool_arguments("storage/myisam", "myisamchk");
- $ENV{'MYISAMPACK'}= tool_arguments("storage/myisam", "myisampack");
- $ENV{'MYISAM_FTDUMP'}= tool_arguments("storage/myisam", "myisam_ftdump");
-
- # ----------------------------------------------------
- # aria tools
- # ----------------------------------------------------
- if (have_maria_support())
- {
- $ENV{'MARIA_CHK'}= tool_arguments("storage/maria", "aria_chk");
- $ENV{'MARIA_PACK'}= tool_arguments("storage/maria", "aria_pack");
- }
-
- # ----------------------------------------------------
- # mysqlhotcopy
- # ----------------------------------------------------
- my $mysqlhotcopy=
- mtr_pl_maybe_exists("$bindir/scripts/mysqlhotcopy") ||
- mtr_pl_maybe_exists("$path_client_bindir/mysqlhotcopy");
- if ($mysqlhotcopy)
- {
- $ENV{'MYSQLHOTCOPY'}= $mysqlhotcopy;
- }
-
- # ----------------------------------------------------
- # perror
- # ----------------------------------------------------
- my $exe_perror= mtr_exe_exists("$bindir/extra$opt_vs_config/perror",
- "$path_client_bindir/perror");
- $ENV{'MY_PERROR'}= native_path($exe_perror);
-
- # ----------------------------------------------------
- # mysql_tzinfo_to_sql
- # ----------------------------------------------------
- my $exe_mysql_tzinfo_to_sql= mtr_exe_exists("$basedir/sql$opt_vs_config/mysql_tzinfo_to_sql",
- "$path_client_bindir/mysql_tzinfo_to_sql",
- "$bindir/sql$opt_vs_config/mysql_tzinfo_to_sql");
- $ENV{'MYSQL_TZINFO_TO_SQL'}= native_path($exe_mysql_tzinfo_to_sql);
-
- # ----------------------------------------------------
- # replace
- # ----------------------------------------------------
- my $exe_replace= mtr_exe_exists(vs_config_dirs('extra', 'replace'),
- "$basedir/extra/replace",
- "$bindir/extra$opt_vs_config/replace",
- "$path_client_bindir/replace");
- $ENV{'REPLACE'}= native_path($exe_replace);
-
- # ----------------------------------------------------
- # innochecksum
- # ----------------------------------------------------
- my $exe_innochecksum=
- mtr_exe_maybe_exists("$bindir/extra$opt_vs_config/innochecksum",
- "$path_client_bindir/innochecksum");
- $ENV{'INNOCHECKSUM'}= native_path($exe_innochecksum) if $exe_innochecksum;
-
- # ----------------------------------------------------
- # mariabackup
- # ----------------------------------------------------
- my $exe_mariabackup= mtr_exe_maybe_exists(
- "$bindir/extra/mariabackup$opt_vs_config/mariabackup",
- "$path_client_bindir/mariabackup");
-
- $ENV{XTRABACKUP}= native_path($exe_mariabackup) if $exe_mariabackup;
-
- my $exe_xbstream= mtr_exe_maybe_exists(
- "$bindir/extra/mariabackup/$opt_vs_config/mbstream",
- "$path_client_bindir/mbstream");
- $ENV{XBSTREAM}= native_path($exe_xbstream) if $exe_xbstream;
-
- $ENV{INNOBACKUPEX}= "$exe_mariabackup --innobackupex";
-
- # Add dir of this perl to aid mysqltest in finding perl
- my $perldir= dirname($^X);
- my $pathsep= ":";
- $pathsep= ";" if IS_WINDOWS && ! IS_CYGWIN;
- $ENV{'PATH'}= "$ENV{'PATH'}".$pathsep.$perldir;
-}
-
-
-sub remove_vardir_subs() {
- foreach my $sdir ( glob("$opt_vardir/*") ) {
- mtr_verbose("Removing subdir $sdir");
- rmtree($sdir);
- }
-}
-
-#
-# Remove var and any directories in var/ created by previous
-# tests
-#
-sub remove_stale_vardir () {
-
- mtr_report("Removing old var directory...");
-
- # Safety!
- mtr_error("No, don't remove the vardir when running with --extern")
- if using_extern();
-
- mtr_verbose("opt_vardir: $opt_vardir");
- if ( $opt_vardir eq $default_vardir )
- {
- #
- # Running with "var" in mysql-test dir
- #
- if ( -l $opt_vardir)
- {
- # var is a symlink
-
- if ( $opt_mem )
- {
- # Remove the directory which the link points at
- mtr_verbose("Removing " . readlink($opt_vardir));
- rmtree(readlink($opt_vardir));
-
- # Remove the "var" symlink
- mtr_verbose("unlink($opt_vardir)");
- unlink($opt_vardir);
- }
- else
- {
- # Some users creates a soft link in mysql-test/var to another area
- # - allow it, but remove all files in it
-
- mtr_report(" - WARNING: Using the 'mysql-test/var' symlink");
-
- # Make sure the directory where it points exist
- if (! -d readlink($opt_vardir))
- {
- mtr_report("The destination for symlink $opt_vardir does not exist; Removing it and creating a new var directory");
- unlink($opt_vardir);
- }
- remove_vardir_subs();
- }
- }
- else
- {
- # Remove the entire "var" dir
- mtr_verbose("Removing $opt_vardir/");
- rmtree("$opt_vardir/");
- }
-
- if ( $opt_mem )
- {
- # A symlink from var/ to $opt_mem will be set up
- # remove the $opt_mem dir to assure the symlink
- # won't point at an old directory
- mtr_verbose("Removing $opt_mem");
- rmtree($opt_mem);
- }
-
- }
- else
- {
- #
- # Running with "var" in some other place
- #
-
- # Don't remove the var/ dir in mysql-test dir as it may be in
- # use by another mysql-test-run run with --vardir
- # mtr_verbose("Removing $default_vardir");
- # rmtree($default_vardir);
-
- # Remove the "var" dir
- mtr_verbose("Removing $opt_vardir/");
- rmtree("$opt_vardir/");
- }
- # Remove the "tmp" dir
- mtr_verbose("Removing $opt_tmpdir/");
- rmtree("$opt_tmpdir/");
-}
-
-sub set_plugin_var($) {
- local $_ = $_[0];
- s/\.\w+$//;
- $ENV{"\U${_}_SO"} = $_[0];
-}
-
-#
-# Create var and the directories needed in var
-#
-sub setup_vardir() {
- mtr_report("Creating var directory '$opt_vardir'...");
-
- if ( $opt_vardir eq $default_vardir )
- {
- #
- # Running with "var" in mysql-test dir
- #
- if ( -l $opt_vardir )
- {
- # it's a symlink
-
- # Make sure the directory where it points exist
- if (! -d readlink($opt_vardir))
- {
- mtr_report("The destination for symlink $opt_vardir does not exist; Removing it and creating a new var directory");
- unlink($opt_vardir);
- }
- }
- elsif ( $opt_mem )
- {
- # Runinng with "var" as a link to some "memory" location, normally tmpfs
- mtr_verbose("Creating $opt_mem");
- mkpath($opt_mem);
-
- mtr_report(" - symlinking 'var' to '$opt_mem'");
- symlink($opt_mem, $opt_vardir);
- }
- }
-
- if ( ! -d $opt_vardir )
- {
- mtr_verbose("Creating $opt_vardir");
- mkpath($opt_vardir);
- }
-
- # Ensure a proper error message if vardir couldn't be created
- unless ( -d $opt_vardir and -w $opt_vardir )
- {
- mtr_error("Writable 'var' directory is needed, use the " .
- "'--vardir=<path>' option");
- }
-
- mkpath("$opt_vardir/log");
- mkpath("$opt_vardir/run");
-
- # Create var/tmp and tmp - they might be different
- mkpath("$opt_vardir/tmp");
- mkpath($opt_tmpdir) if ($opt_tmpdir ne "$opt_vardir/tmp");
-
- # On some operating systems, there is a limit to the length of a
- # UNIX domain socket's path far below PATH_MAX.
- # Don't allow that to happen
- if (check_socket_path_length("$opt_tmpdir/testsocket.sock")){
- mtr_error("Socket path '$opt_tmpdir' too long, it would be ",
- "truncated and thus not possible to use for connection to ",
- "MariaDB Server. Set a shorter with --tmpdir=<path> option");
- }
-
- # copy all files from std_data into var/std_data
- # and make them world readable
- copytree("$glob_mysql_test_dir/std_data", "$opt_vardir/std_data", "0022");
-
- unless($plugindir)
- {
- # create a plugin dir and copy or symlink plugins into it
- if ($source_dist)
- {
- $plugindir="$opt_vardir/plugins";
- # Source builds collect both client plugins and server plugins in the
- # same directory.
- $client_plugindir= $plugindir;
- mkpath($plugindir);
- if (IS_WINDOWS)
- {
- if (!$opt_embedded_server)
- {
- for (<$bindir/storage/*$opt_vs_config/*.dll>,
- <$bindir/plugin/*$opt_vs_config/*.dll>,
- <$bindir/libmariadb$opt_vs_config/*.dll>,
- <$bindir/sql$opt_vs_config/*.dll>)
- {
- my $pname=basename($_);
- copy rel2abs($_), "$plugindir/$pname";
- set_plugin_var($pname);
- }
- }
- }
- else
- {
- my $opt_use_copy= 1;
- if (symlink "$opt_vardir/run", "$plugindir/symlink_test")
- {
- $opt_use_copy= 0;
- unlink "$plugindir/symlink_test";
- }
-
- for (<$bindir/storage/*/*.so>,
- <$bindir/plugin/*/*.so>,
- <$bindir/plugin/*/auth_pam_tool_dir>,
- <$bindir/libmariadb/plugins/*/*.so>,
- <$bindir/libmariadb/*.so>,
- <$bindir/sql/*.so>)
- {
- my $pname=basename($_);
- if ($opt_use_copy)
- {
- copy rel2abs($_), "$plugindir/$pname";
- }
- else
- {
- symlink rel2abs($_), "$plugindir/$pname";
- }
- set_plugin_var($pname);
- }
- }
- }
- else
- {
- # hm, what paths work for debs and for rpms ?
- for (<$bindir/lib64/mysql/plugin/*.so>,
- <$bindir/lib/mysql/plugin/*.so>,
- <$bindir/lib64/mariadb/plugin/*.so>,
- <$bindir/lib/mariadb/plugin/*.so>,
- <$bindir/lib/plugin/*.so>, # bintar
- <$bindir/lib/plugin/*.dll>)
- {
- my $pname= basename($_);
- set_plugin_var($pname);
- $plugindir= dirname($_) unless $plugindir;
- }
-
- # Note: client plugins can be installed separately from server plugins,
- # as is the case for Debian packaging.
- for (<$bindir/lib/*/libmariadb3/plugin>)
- {
- $client_plugindir= $_ if <$_/*.so>;
- }
- $client_plugindir= $plugindir unless $client_plugindir;
- }
- }
-
- # Remove old log files
- foreach my $name (glob("r/*.progress r/*.log r/*.warnings"))
- {
- unlink($name);
- }
-}
-
-
-#
-# Check if running as root
-# i.e a file can be read regardless what mode we set it to
-#
-sub check_running_as_root () {
- 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('', <FILE>);
- close FILE;
- }
-
- # Some filesystems( for example CIFS) allows reading a file
- # although mode was set to 0000, but in that case a stat on
- # the file will not return 0000
- my $file_mode= (stat($test_file))[2] & 07777;
-
- mtr_verbose("result: $result, file_mode: $file_mode");
- if ($result eq "MySQL" && $file_mode == 0)
- {
- mtr_warning("running this script as _root_ will cause some " .
- "tests to be skipped");
- $ENV{'MYSQL_TEST_ROOT'}= "1";
- }
-
- chmod(oct("0755"), $test_file);
- unlink($test_file);
-}
-
-
-sub check_ssl_support {
- if ($opt_skip_ssl)
- {
- 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(" - SSL connections supported");
- $opt_ssl_supported= 1;
-}
-
-sub check_debug_support {
- if (defined $mysqld_variables{'debug-dbug'})
- {
- mtr_report(" - binaries are debug compiled");
- }
- elsif ($opt_debug_server)
- {
- mtr_error("Can't use --debug[-server], binary does not support it");
- }
-}
-
-
-#
-# Helper function to find the correct value for the opt_vs_config
-# if it was not set explicitly.
-#
-# the configuration with the most recent build dir in sql/ is selected.
-#
-# note: looking for all BuildLog.htm files everywhere in the tree with the
-# help of File::Find would be possibly more precise, but it is also
-# many times slower. Thus we are only looking at the server, client
-# executables, and plugins - that is, something that can affect the test suite
-#
-sub fix_vs_config_dir () {
- return $opt_vs_config="" unless IS_WINDOWS;
- return $opt_vs_config="/$opt_vs_config" if $opt_vs_config;
-
- my $modified = 1e30;
- $opt_vs_config="";
-
-
- for (<$bindir/sql/*/mysqld.exe>) { #/
- if (-M $_ < $modified)
- {
- $modified = -M _;
- $opt_vs_config = basename(dirname($_));
- }
- }
-
- mtr_report("VS config: $opt_vs_config");
- $opt_vs_config="/$opt_vs_config" if $opt_vs_config;
-}
-
-
-#
-# 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;
-
- # Don't look in these dirs when not on windows
- return () unless IS_WINDOWS;
-
- if ($opt_vs_config)
- {
- return ("$basedir/$path_part/$opt_vs_config/$exe");
- }
-
- return ("$basedir/$path_part/release/$exe",
- "$basedir/$path_part/relwithdebinfo/$exe",
- "$basedir/$path_part/debug/$exe");
-}
-
-sub mysql_server_start($) {
- my ($mysqld, $tinfo) = @_;
-
- if ( $mysqld->{proc} )
- {
- # Already started
-
- # Write start of testcase to log file
- mark_log($mysqld->value('log-error'), $tinfo);
-
- return;
- }
-
- my $datadir= $mysqld->value('datadir');
- if (not $opt_start_dirty)
- {
-
- my @options= ('log-bin', 'relay-log');
- foreach my $option_name ( @options ) {
- next unless $mysqld->option($option_name);
-
- my $file_name= $mysqld->value($option_name);
- next unless
- defined $file_name and
- -e $file_name;
-
- mtr_debug(" -removing '$file_name'");
- unlink($file_name) or die ("unable to remove file '$file_name'");
- }
-
- if (-d $datadir ) {
- mtr_verbose(" - removing '$datadir'");
- rmtree($datadir);
- }
- }
-
- my $mysqld_basedir= $mysqld->value('basedir');
- my $extra_opts= get_extra_opts($mysqld, $tinfo);
-
- if ( $basedir eq $mysqld_basedir )
- {
- if (! $opt_start_dirty) # If dirty, keep possibly grown system db
- {
- # Some InnoDB options are incompatible with the default bootstrap.
- # If they are used, re-bootstrap
- my @rebootstrap_opts;
- @rebootstrap_opts = grep {/$rebootstrap_re/o} @$extra_opts if $extra_opts;
- if (@rebootstrap_opts)
- {
- mtr_verbose("Re-bootstrap with @rebootstrap_opts");
- mysql_install_db($mysqld, undef, \@rebootstrap_opts);
- }
- else {
- # Copy datadir from installed system db
- my $path= ($opt_parallel == 1) ? "$opt_vardir" : "$opt_vardir/..";
- my $install_db= "$path/install.db";
- copytree($install_db, $datadir) if -d $install_db;
- mtr_error("Failed to copy system db to '$datadir'") unless -d $datadir;
- }
- }
- }
- else
- {
- mysql_install_db($mysqld); # For versional testing
-
- mtr_error("Failed to install system db to '$datadir'")
- unless -d $datadir;
-
- }
-
- # Create the servers tmpdir
- my $tmpdir= $mysqld->value('tmpdir');
- mkpath($tmpdir) unless -d $tmpdir;
-
- # Write start of testcase to log file
- mark_log($mysqld->value('log-error'), $tinfo);
-
- # Run <tname>-master.sh
- if ($mysqld->option('#!run-master-sh') and
- defined $tinfo->{master_sh} and
- run_system('/bin/sh ' . $tinfo->{master_sh}) )
- {
- $tinfo->{'comment'}= "Failed to execute '$tinfo->{master_sh}'";
- return 1;
- }
-
- # Run <tname>-slave.sh
- if ($mysqld->option('#!run-slave-sh') and
- defined $tinfo->{slave_sh} and
- run_system('/bin/sh ' . $tinfo->{slave_sh}))
- {
- $tinfo->{'comment'}= "Failed to execute '$tinfo->{slave_sh}'";
- return 1;
- }
-
- if (!$opt_embedded_server)
- {
- mysqld_start($mysqld,$extra_opts);
-
- # Save this test case information, so next can examine it
- $mysqld->{'started_tinfo'}= $tinfo;
- }
-
- # If wsrep is on, we need to wait until the first
- # server starts and bootstraps the cluster before
- # starting other servers. The bootsrap server in the
- # configuration should always be the first which has
- # wsrep_on=ON
- if (wsrep_on($mysqld) && wsrep_is_bootstrap_server($mysqld))
- {
- mtr_verbose("Waiting for wsrep bootstrap server to start");
- if ($mysqld->{WAIT}->($mysqld))
- {
- return 1;
- }
- }
-}
-
-sub mysql_server_wait {
- my ($mysqld, $tinfo) = @_;
-
- if (!sleep_until_file_created($mysqld->value('pid-file'),
- $opt_start_timeout,
- $mysqld->{'proc'},
- $warn_seconds))
- {
- $tinfo->{comment}= "Failed to start ".$mysqld->name() . "\n";
- return 1;
- }
-
- if (wsrep_on($mysqld))
- {
- mtr_verbose("Waiting for wsrep server " . $mysqld->name() . " to be ready");
- if (!wait_wsrep_ready($tinfo, $mysqld))
- {
- return 1;
- }
- }
-
- return 0;
-}
-
-sub create_config_file_for_extern {
- my %opts=
- (
- socket => '/tmp/mysqld.sock',
- port => 3306,
- user => $opt_user,
- password => '',
- @_
- );
-
- mtr_report("Creating my.cnf file for extern server...");
- my $F= IO::File->new($path_config_file, "w")
- or mtr_error("Can't write to $path_config_file: $!");
-
- print $F "[client]\n";
- while (my ($option, $value)= each( %opts )) {
- print $F "$option= $value\n";
- mtr_report(" $option= $value");
- }
-
- print $F <<EOF
-
-# binlog reads from [client] and [mysqlbinlog]
-[mysqlbinlog]
-character-sets-dir= $path_charsetsdir
-local-load= $opt_tmpdir
-
-EOF
-;
-
- $F= undef; # Close file
-}
-
-
-#
-# Kill processes left from previous runs, normally
-# there should be none so make sure to warn
-# if there is one
-#
-sub kill_leftovers ($) {
- my $rundir= shift;
- return unless ( -d $rundir );
-
- mtr_report("Checking leftover processes...");
-
- # Scan the "run" directory for process id's to kill
- opendir(RUNDIR, $rundir)
- or mtr_error("kill_leftovers, can't open dir \"$rundir\": $!");
- while ( my $elem= readdir(RUNDIR) )
- {
- # Only read pid from files that end with .pid
- if ( $elem =~ /.*[.]pid$/ )
- {
- my $pidfile= "$rundir/$elem";
- next unless -f $pidfile;
- my $pid= mtr_fromfile($pidfile);
- unlink($pidfile);
- unless ($pid=~ /^(\d+)/){
- # The pid was not a valid number
- mtr_warning("Got invalid pid '$pid' from '$elem'");
- next;
- }
- mtr_report(" - found old pid $pid in '$elem', killing it...");
-
- my $ret= kill("KILL", $pid);
- if ($ret == 0) {
- mtr_report(" process did not exist!");
- next;
- }
-
- my $check_counter= 100;
- while ($ret > 0 and $check_counter--) {
- mtr_milli_sleep(100);
- $ret= kill(0, $pid);
- }
- mtr_report($check_counter ? " ok!" : " failed!");
- }
- else
- {
- mtr_warning("Found non pid file '$elem' in '$rundir'")
- if -f "$rundir/$elem";
- }
- }
- closedir(RUNDIR);
-}
-
-#
-# Check that all the ports that are going to
-# be used are free
-#
-sub check_ports_free ($)
-{
- my $bthread= shift;
- my $portbase = $bthread * $opt_port_group_size + 10000;
- for ($portbase..$portbase+($opt_port_group_size-1)){
- if (mtr_ping_port($_)){
- mtr_report(" - 'localhost:$_' was not free");
- return 0; # One port was not free
- }
- }
-
- return 1; # All ports free
-}
-
-
-sub initialize_servers {
-
- if ( using_extern() )
- {
- # Running against an already started server, if the specified
- # vardir does not already exist it should be created
- if ( ! -d $opt_vardir )
- {
- setup_vardir();
- }
- else
- {
- mtr_verbose("No need to create '$opt_vardir' it already exists");
- }
- }
- else
- {
- # Kill leftovers from previous run
- # using any pidfiles found in var/run
- kill_leftovers("$opt_vardir/run");
-
- if ( ! $opt_start_dirty )
- {
- remove_stale_vardir();
- setup_vardir();
- }
- }
-}
-
-
-#
-# Remove all newline characters expect after semicolon
-#
-sub sql_to_bootstrap {
- my ($sql) = @_;
- my @lines= split(/\n/, $sql);
- my $result= "\n";
- my $delimiter= ';';
-
- foreach my $line (@lines) {
-
- # Change current delimiter if line starts with "delimiter"
- if ( $line =~ /^delimiter (.*)/ ) {
- my $new= $1;
- # Remove old delimiter from end of new
- $new=~ s/\Q$delimiter\E$//;
- $delimiter = $new;
- mtr_debug("changed delimiter to $delimiter");
- # No need to add the delimiter to result
- next;
- }
-
- # Add newline if line ends with $delimiter
- # and convert the current delimiter to semicolon
- if ( $line =~ /\Q$delimiter\E$/ ){
- $line =~ s/\Q$delimiter\E$/;/;
- $result.= "$line\n";
- mtr_debug("Added default delimiter");
- next;
- }
-
- # Remove comments starting with --
- if ( $line =~ /^\s*--/ ) {
- mtr_debug("Discarded $line");
- next;
- }
-
- # Replace @HOSTNAME with localhost
- $line=~ s/\'\@HOSTNAME\@\'/localhost/;
-
- # Default, just add the line without newline
- # but with a space as separator
- $result.= "$line ";
-
- }
- return $result;
-}
-
-
-sub default_mysqld {
- # Generate new config file from template
- environment_setup();
- my $config= My::ConfigFactory->new_config
- ( {
- basedir => $basedir,
- testdir => $glob_mysql_test_dir,
- template_path => "include/default_my.cnf",
- vardir => $opt_vardir,
- tmpdir => $opt_tmpdir,
- baseport => 0,
- user => $opt_user,
- password => '',
- }
- );
-
- my $mysqld= $config->group('mysqld.1')
- or mtr_error("Couldn't find mysqld.1 in default config");
- return $mysqld;
-}
-
-
-sub mysql_install_db {
- my ($mysqld, $datadir, $extra_opts)= @_;
-
- my $install_datadir= $datadir || $mysqld->value('datadir');
- my $install_basedir= $mysqld->value('basedir');
- my $install_lang= $mysqld->value('lc-messages-dir');
- my $install_chsdir= $mysqld->value('character-sets-dir');
-
- mtr_report("Installing system database...");
-
- my $args;
- mtr_init_args(\$args);
- mtr_add_arg($args, "--no-defaults");
- mtr_add_arg($args, "--disable-getopt-prefix-matching");
- mtr_add_arg($args, "--bootstrap");
- mtr_add_arg($args, "--basedir=%s", $install_basedir);
- mtr_add_arg($args, "--datadir=%s", $install_datadir);
- mtr_add_arg($args, "--plugin-dir=%s", $plugindir);
- mtr_add_arg($args, "--default-storage-engine=myisam");
- mtr_add_arg($args, "--loose-skip-plugin-$_") for @optional_plugins;
- # starting from 10.0 bootstrap scripts require InnoDB
- mtr_add_arg($args, "--loose-innodb");
- mtr_add_arg($args, "--loose-innodb-log-file-size=10M");
- mtr_add_arg($args, "--disable-sync-frm");
- mtr_add_arg($args, "--tmpdir=%s", "$opt_vardir/tmp/");
- mtr_add_arg($args, "--core-file");
- mtr_add_arg($args, "--console");
- mtr_add_arg($args, "--character-set-server=latin1");
-
- if ( $opt_debug )
- {
- mtr_add_arg($args, "--debug-dbug=$debug_d:t:i:A,%s/log/bootstrap.trace",
- $path_vardir_trace);
- }
-
- mtr_add_arg($args, "--lc-messages-dir=%s", $install_lang);
- mtr_add_arg($args, "--character-sets-dir=%s", $install_chsdir);
-
- # InnoDB arguments that affect file location and sizes may
- # need to be given to the bootstrap process as well as the
- # server process.
- foreach my $extra_opt ( @opt_extra_mysqld_opt ) {
- if ($extra_opt =~ /--innodb/) {
- mtr_add_arg($args, $extra_opt);
- }
- }
-
- # If DISABLE_GRANT_OPTIONS is defined when the server is compiled (e.g.,
- # configure --disable-grant-options), mysqld will not recognize the
- # --bootstrap or --skip-grant-tables options. The user can set
- # MYSQLD_BOOTSTRAP to the full path to a mysqld which does accept
- # --bootstrap, to accommodate this.
- my $exe_mysqld_bootstrap =
- $ENV{'MYSQLD_BOOTSTRAP'} || find_mysqld($install_basedir);
-
- # ----------------------------------------------------------------------
- # export MYSQLD_BOOTSTRAP_CMD variable containing <path>/mysqld <args>
- # ----------------------------------------------------------------------
- $ENV{'MYSQLD_BOOTSTRAP_CMD'}= "$exe_mysqld_bootstrap " . join(" ", @$args)
- unless defined $ENV{'MYSQLD_BOOTSTRAP_CMD'};
-
- # Extra options can come not only from the command line, but also
- # from option files or combinations. We want them on a command line
- # that is executed now, because otherwise the datadir might be
- # incompatible with the test settings, but not on the general
- # $MYSQLD_BOOTSTRAP_CMD line
- foreach my $extra_opt ( @$extra_opts ) {
- mtr_add_arg($args, $extra_opt);
- }
-
- # ----------------------------------------------------------------------
- # Create the bootstrap.sql file
- # ----------------------------------------------------------------------
- my $bootstrap_sql_file= "$opt_vardir/log/bootstrap.sql";
- $ENV{'MYSQL_BOOTSTRAP_SQL_FILE'}= $bootstrap_sql_file;
-
- if (! -e $bootstrap_sql_file)
- {
- My::Debugger::setup_boot_args(\$args, \$exe_mysqld_bootstrap, $bootstrap_sql_file);
-
- my $path_sql= my_find_file($install_basedir,
- ["mysql", "sql/share", "share/mariadb",
- "share/mysql", "share", "scripts"],
- "mysql_system_tables.sql",
- NOT_REQUIRED);
-
- if (-f $path_sql )
- {
- my $sql_dir= dirname($path_sql);
- # Use the mysql database for system tables
- mtr_tofile($bootstrap_sql_file, "use mysql;\n");
-
- # Add the offical mysql system tables
- # for a production system
- mtr_appendfile_to_file("$sql_dir/mysql_system_tables.sql",
- $bootstrap_sql_file);
-
- my $gis_sp_path = $source_dist ? "$bindir/scripts" : $sql_dir;
- mtr_appendfile_to_file("$gis_sp_path/maria_add_gis_sp_bootstrap.sql",
- $bootstrap_sql_file);
-
- # Add the performance tables
- # for a production system
- mtr_appendfile_to_file("$sql_dir/mysql_performance_tables.sql",
- $bootstrap_sql_file);
-
- # Add the mysql system tables initial data
- # for a production system
- mtr_appendfile_to_file("$sql_dir/mysql_system_tables_data.sql",
- $bootstrap_sql_file);
-
- # Add test data for timezone - this is just a subset, on a real
- # system these tables will be populated either by mysql_tzinfo_to_sql
- # or by downloading the timezone table package from our website
- mtr_appendfile_to_file("$sql_dir/mysql_test_data_timezone.sql",
- $bootstrap_sql_file);
-
- # Fill help tables, just an empty file when running from bk repo
- # but will be replaced by a real fill_help_tables.sql when
- # building the source dist
- mtr_appendfile_to_file("$sql_dir/fill_help_tables.sql",
- $bootstrap_sql_file);
-
- # Append sys schema
- mtr_appendfile_to_file("$gis_sp_path/mysql_sys_schema.sql",
- $bootstrap_sql_file);
- # Create test database
- mtr_appendfile_to_file("$sql_dir/mysql_test_db.sql",
- $bootstrap_sql_file);
-
- # mysql.gtid_slave_pos was created in InnoDB, but many tests
- # run without InnoDB. Alter it to Aria now
- mtr_tofile($bootstrap_sql_file, "ALTER TABLE gtid_slave_pos ENGINE=Aria transactional=0;\n");
- }
- else
- {
- # Install db from init_db.sql that exist in early 5.1 and 5.0
- # versions of MySQL
- my $init_file= "$install_basedir/mysql-test/lib/init_db.sql";
- mtr_report(" - from '$init_file'");
- my $text= mtr_grab_file($init_file) or
- mtr_error("Can't open '$init_file': $!");
-
- mtr_tofile($bootstrap_sql_file,
- sql_to_bootstrap($text));
- }
-
- # Remove anonymous users
- mtr_tofile($bootstrap_sql_file,
- "DELETE FROM mysql.global_priv where user= '';\n");
-
- # Create mtr database
- mtr_tofile($bootstrap_sql_file,
- "CREATE DATABASE mtr CHARSET=latin1;\n");
-
- # Add help tables and data for warning detection and supression
- mtr_tofile($bootstrap_sql_file,
- sql_to_bootstrap(mtr_grab_file("include/mtr_warnings.sql")));
-
- # Add procedures for checking server is restored after testcase
- mtr_tofile($bootstrap_sql_file,
- sql_to_bootstrap(mtr_grab_file("include/mtr_check.sql")));
- }
-
- # Log bootstrap command
- my $path_bootstrap_log= "$opt_vardir/log/bootstrap.log";
- mtr_tofile($path_bootstrap_log,
- "$exe_mysqld_bootstrap " . join(" ", @$args) . "\n");
-
- # Create directories mysql
- mkpath("$install_datadir/mysql");
-
- my $realtime= gettimeofday();
- if ( My::SafeProcess->run
- (
- name => "bootstrap",
- path => $exe_mysqld_bootstrap,
- args => \$args,
- input => $bootstrap_sql_file,
- output => $path_bootstrap_log,
- error => $path_bootstrap_log,
- append => 1,
- verbose => $opt_verbose,
- ) != 0)
- {
- my $data= mtr_grab_file($path_bootstrap_log);
- mtr_error("Error executing mariadbd --bootstrap\n" .
- "Could not install system database from $bootstrap_sql_file\n" .
- "The $path_bootstrap_log file contains:\n$data\n");
- }
- else
- {
- mtr_verbose("Spent " . sprintf("%.3f", (gettimeofday() - $realtime)) . " seconds in bootstrap");
- }
-}
-
-
-sub run_testcase_check_skip_test($)
-{
- my ($tinfo)= @_;
-
- # ----------------------------------------------------------------------
- # Skip some tests silently
- # ----------------------------------------------------------------------
-
- my $start_from= $mtr_cases::start_from;
- if ( $start_from )
- {
- if ($tinfo->{'name'} eq $start_from ||
- $tinfo->{'shortname'} eq $start_from)
- {
- ## Found parting test. Run this test and all tests after this one
- $mtr_cases::start_from= "";
- }
- else
- {
- $tinfo->{'result'}= 'MTR_RES_SKIPPED';
- return 1;
- }
- }
-
- # ----------------------------------------------------------------------
- # 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_skipped($tinfo) unless $start_only;
- return 1;
- }
-
- return 0;
-}
-
-
-sub run_query {
- my ($tinfo, $mysqld, $query)= @_;
-
- my $args;
- mtr_init_args(\$args);
- mtr_add_arg($args, "--defaults-file=%s", $path_config_file);
- mtr_add_arg($args, "--defaults-group-suffix=%s", $mysqld->after('mysqld'));
-
- mtr_add_arg($args, "-e %s", $query);
-
- my $res= My::SafeProcess->run
- (
- name => "run_query -> ".$mysqld->name(),
- path => $exe_mysql,
- args => \$args,
- output => '/dev/null',
- error => '/dev/null'
- );
-
- return $res
-}
-
-
-sub do_before_run_mysqltest($)
-{
- my $tinfo= shift;
- my $resfile= $tinfo->{result_file};
- return unless defined $resfile;
-
- # Remove old files produced by mysqltest
- die "unsupported result file name $resfile, stoping" unless
- $resfile =~ /^(.*?)((?:,\w+)*)\.(rdiff|result|result~)$/;
- my ($base_file, $suites, $ext)= ($1, $2, $3);
- # if the result file is a diff, make a proper result file
- if ($ext eq 'rdiff') {
- my $base_result = $tinfo->{base_result};
- my $resdir= dirname($resfile);
- # we'll use a separate extension for generated result files
- # to be able to distinguish them from manually created
- # version-controlled results, and to ignore them in git.
- my $dest = "$base_file$suites.result~";
- my @cmd = ($exe_patch);
- if ($^O eq "MSWin32") {
- push @cmd, '--binary';
- }
- push @cmd, (qw/-r - -f -s -o/, $dest, $base_result, $resfile);
- if (-w $resdir) {
- # don't rebuild a file if it's up to date
- unless (-e $dest and -M $dest < -M $resfile
- and -M $dest < -M $base_result) {
- run_system(@cmd);
- }
- } else {
- $cmd[-3] = $dest = $opt_tmpdir . '/' . basename($dest);
- run_system(@cmd);
- }
- $tinfo->{result_file} = $dest;
- }
-
- unlink("$base_file.reject");
- unlink("$base_file.progress");
- unlink("$base_file.log");
- unlink("$base_file.warnings");
-}
-
-
-#
-# Check all server for sideffects
-#
-# RETURN VALUE
-# 0 ok
-# 1 Check failed
-# >1 Fatal errro
-
-sub check_testcase($$)
-{
- my ($tinfo, $mode)= @_;
- my $tname= $tinfo->{name};
-
- # Start the mysqltest processes in parallel to save time
- # also makes it possible to wait for any process to exit during the check
- my %started;
- foreach my $mysqld ( mysqlds() )
- {
- # Skip if server has been restarted with additional options
- if ( defined $mysqld->{'proc'} && ! exists $mysqld->{'restart_opts'} )
- {
- my $proc= start_check_testcase($tinfo, $mode, $mysqld);
- $started{$proc->pid()}= $proc;
- }
- }
-
- # Return immediately if no check proceess was started
- return 0 unless ( keys %started );
-
- my $timeout= start_timer(check_timeout($tinfo));
-
- while (1){
- my $result;
- my $proc= My::SafeProcess->wait_any_timeout($timeout);
- mtr_report("Got $proc");
-
- if ( delete $started{$proc->pid()} ) {
-
- my $err_file= $proc->user_data();
- my $base_file= mtr_match_extension($err_file, "err"); # Trim extension
-
- # One check testcase process returned
- my $res= $proc->exit_status();
-
- if ( $res == 0){
- # Check completed without problem
-
- # Remove the .err file the check generated
- unlink($err_file);
-
- # Remove the .result file the check generated
- if ( $mode eq 'after' ){
- unlink("$base_file.result");
- }
-
- if ( keys(%started) == 0){
- # All checks completed
- mark_time_used('check');
- return 0;
- }
- # Wait for next process to exit
- next;
- }
- else
- {
- if ( $mode eq "after" and $res == 1 )
- {
- # Test failed, grab the report mysqltest has created
- my $report= mtr_grab_file($err_file);
- $tinfo->{check}.=
- "\nMTR's internal check of the test case '$tname' failed.
-This means that the test case does not preserve the state that existed
-before the test case was executed. Most likely the test case did not
-do a proper clean-up. It could also be caused by the previous test run
-by this thread, if the server wasn't restarted.
-This is the diff of the states of the servers before and after the
-test case was executed:\n";
- $tinfo->{check}.= $report;
-
- # Check failed, mark the test case with that info
- $tinfo->{'check_testcase_failed'}= 1;
- $result= 1;
- }
- elsif ( $res )
- {
- my $report= mtr_grab_file($err_file);
- $tinfo->{comment}.=
- "Could not execute 'check-testcase' $mode ".
- "testcase '$tname' (res: $res):\n";
- $tinfo->{comment}.= $report;
-
- $result= 2;
- }
- else
- {
- # Remove the .result file the check generated
- unlink("$base_file.result");
- }
- # Remove the .err file the check generated
- unlink($err_file);
-
- }
- }
- elsif ( $proc->{timeout} ) {
- $tinfo->{comment}.= "Timeout for 'check-testcase' expired after "
- .check_timeout($tinfo)." seconds";
- $result= 4;
- }
- else {
- # Unknown process returned, most likley a crash, abort everything
- $tinfo->{comment}=
- "The server $proc crashed while running ".
- "'check testcase $mode test'".
- get_log_from_proc($proc, $tinfo->{name});
- $result= 3;
- }
-
- # Kill any check processes still running
- map($_->kill(), values(%started));
-
- mtr_warning("Check-testcase failed, this could also be caused by the" .
- " previous test run by this worker thread")
- if $result > 1 && $mode eq "before";
- mark_time_used('check');
-
- return $result;
- }
-
- mtr_error("INTERNAL_ERROR: check_testcase");
-}
-
-
-# Start run mysqltest on one server
-#
-# RETURN VALUE
-# 0 OK
-# 1 Check failed
-#
-sub start_run_one ($$) {
- my ($mysqld, $run)= @_;
-
- my $name= "$run-".$mysqld->name();
-
- my $args;
- mtr_init_args(\$args);
-
- mtr_add_arg($args, "--defaults-file=%s", $path_config_file);
- mtr_add_arg($args, "--defaults-group-suffix=%s", $mysqld->after('mysqld'));
-
- mtr_add_arg($args, "--silent");
- mtr_add_arg($args, "--test-file=%s", "include/$run.test");
-
- my $errfile= "$opt_vardir/tmp/$name.err";
- my $proc= My::SafeProcess->new
- (
- name => $name,
- path => $exe_mysqltest,
- error => $errfile,
- output => $errfile,
- args => \$args,
- user_data => $errfile,
- verbose => $opt_verbose,
- );
- mtr_verbose("Started $proc");
- return $proc;
-}
-
-
-#
-# Run script on all servers, collect results
-#
-# RETURN VALUE
-# 0 ok
-# 1 Failure
-
-sub run_on_all($$)
-{
- my ($tinfo, $run)= @_;
-
- # Start the mysqltest processes in parallel to save time
- # also makes it possible to wait for any process to exit during the check
- # and to have a timeout process
- my %started;
- foreach my $mysqld ( mysqlds() )
- {
- if ( defined $mysqld->{'proc'} )
- {
- my $proc= start_run_one($mysqld, $run);
- $started{$proc->pid()}= $proc;
- }
- }
-
- # Return immediately if no check proceess was started
- return 0 unless ( keys %started );
-
- my $timeout= start_timer(check_timeout($tinfo));
-
- while (1){
- my $result;
- my $proc= My::SafeProcess->wait_any_timeout($timeout);
- mtr_report("Got $proc");
-
- if ( delete $started{$proc->pid()} ) {
-
- # One mysqltest process returned
- my $err_file= $proc->user_data();
- my $res= $proc->exit_status();
-
- # Append the report from .err file
- $tinfo->{comment}.= " == $err_file ==\n";
- $tinfo->{comment}.= mtr_grab_file($err_file);
- $tinfo->{comment}.= "\n";
-
- # Remove the .err file
- unlink($err_file);
-
- if ( keys(%started) == 0){
- # All completed
- return 0;
- }
-
- # Wait for next process to exit
- next;
- }
- elsif ($proc->{timeout}) {
- $tinfo->{comment}.= "Timeout for '$run' expired after "
- .check_timeout($tinfo)." seconds";
- }
- else {
- # Unknown process returned, most likley a crash, abort everything
- $tinfo->{comment}.=
- "The server $proc crashed while running '$run'".
- get_log_from_proc($proc, $tinfo->{name});
- }
-
- # Kill any check processes still running
- map($_->kill(), values(%started));
-
- return 1;
- }
- mtr_error("INTERNAL_ERROR: run_on_all");
-}
-
-
-sub mark_log {
- my ($log, $tinfo)= @_;
- my $log_msg= "CURRENT_TEST: $tinfo->{name}\n";
- pre_write_errorlog($log, $tinfo->{name});
- mtr_tofile($log, $log_msg);
-}
-
-
-sub find_testcase_skipped_reason($)
-{
- my ($tinfo)= @_;
-
- # Set default message
- $tinfo->{'comment'}= "Detected by testcase(no log file)";
-
- # Open the test log file
- my $F= IO::File->new($path_current_testlog)
- or return;
- my $reason;
-
- while ( my $line= <$F> )
- {
- # Look for "reason: <reason for skipping test>"
- if ( $line =~ /reason: (.*)/ )
- {
- $reason= $1;
- }
- }
-
- if ( ! $reason )
- {
- mtr_warning("Could not find reason for skipping test in $path_current_testlog");
- $reason= "Detected by testcase(reason unknown) ";
- }
- $tinfo->{'comment'}= $reason;
-}
-
-
-sub find_analyze_request
-{
- # Open the test log file
- my $F= IO::File->new($path_current_testlog)
- or return;
- my $analyze;
-
- while ( my $line= <$F> )
- {
- # Look for "reason: <reason for skipping test>"
- if ( $line =~ /analyze: (.*)/ )
- {
- $analyze= $1;
- }
- }
-
- return $analyze;
-}
-
-# The test can leave a file in var/tmp/ to signal
-# that all servers should be restarted
-sub restart_forced_by_test($)
-{
- my $file = shift;
- my $restart = 0;
- foreach my $mysqld ( mysqlds() )
- {
- my $datadir = $mysqld->value('datadir');
- my $force_restart_file = "$datadir/mtr/$file";
- if ( -f $force_restart_file )
- {
- mtr_verbose("Restart of servers forced by test");
- $restart = 1;
- last;
- }
- }
- return $restart;
-}
-
-# Return timezone value of tinfo or default value
-sub timezone {
- my ($tinfo)= @_;
- local $_ = $tinfo->{timezone};
- return 'DEFAULT' unless defined $_;
- no warnings 'uninitialized';
- s/\$\{(\w+)\}/$ENV{$1}/ge;
- s/\$(\w+)/$ENV{$1}/ge;
- $_;
-}
-
-sub mycnf_create {
- my ($config) = @_;
- my $res;
-
- foreach my $group ($config->option_groups()) {
- $res .= "[$group->{name}]\n";
-
- foreach my $option ($group->options()) {
- $res .= $option->name();
- my $value= $option->value();
- if (defined $value) {
- $res .= "=$value";
- }
- $res .= "\n";
- }
- $res .= "\n";
- }
- $res;
-}
-
-sub config_files($) {
- my ($tinfo) = @_;
- (
- 'my.cnf' => \&mycnf_create,
- $tinfo->{suite}->config_files()
- );
-}
-
-sub _like { return $config ? $config->like($_[0]) : (); }
-sub mysqlds { return _like('mysqld\.'); }
-
-sub fix_servers($) {
- my ($tinfo) = @_;
- return () unless $config;
- my %servers = (
- qr/mysqld\./ => {
- SORT => 300,
- START => \&mysql_server_start,
- WAIT => \&mysql_server_wait,
- },
- $tinfo->{suite}->servers()
- );
- for ($config->groups()) {
- while (my ($re,$prop) = each %servers) {
- @$_{keys %$prop} = values %$prop if $_->{name} =~ /^$re/;
- }
- }
-}
-
-sub all_servers {
- return unless $config;
- ( sort { $a->{SORT} <=> $b->{SORT} }
- grep { defined $_->{SORT} } $config->groups() );
-}
-
-# Storage for changed environment variables
-our %old_env;
-
-sub resfile_report_test ($) {
- my $tinfo= shift;
-
- resfile_new_test();
-
- resfile_test_info("name", $tinfo->{name});
- resfile_test_info("variation", $tinfo->{combination})
- if $tinfo->{combination};
- resfile_test_info("start_time", isotime time);
-}
-
-
-#
-# Run a single test case
-#
-# RETURN VALUE
-# 0 OK
-# > 0 failure
-#
-
-sub run_testcase ($$) {
- my ($tinfo, $server_socket)= @_;
- my $print_freq=20;
-
- mtr_verbose("Running test:", $tinfo->{name});
- $ENV{'MTR_TEST_NAME'} = $tinfo->{name};
- resfile_report_test($tinfo) if $opt_resfile;
-
- for my $key (grep { /^MTR_COMBINATION/ } keys %ENV)
- {
- delete $ENV{$key};
- }
-
- if (ref $tinfo->{combinations} eq 'ARRAY')
- {
- for (my $i = 0; $i < @{$tinfo->{combinations}}; ++$i )
- {
- my $combination = $tinfo->{combinations}->[$i];
- # Allow only alphanumerics plus _ - + . in combination names,
- # or anything beginning with -- (the latter comes from --combination)
- if ($combination && $combination !~ /^\w[-\w\.\+]*$/
- && $combination !~ /^--/)
- {
- mtr_error("Combination '$combination' contains illegal characters");
- }
- $ENV{"MTR_COMBINATION_". uc(${combination})} = 1;
- }
- $ENV{"MTR_COMBINATIONS"} = join(',', @{$tinfo->{combinations}});
- }
- elsif (exists $tinfo->{combinations})
- {
- die 'Unexpected type of $tinfo->{combinations}';
- }
-
- # -------------------------------------------------------
- # Init variables that can change between each test case
- # -------------------------------------------------------
- my $timezone= timezone($tinfo);
- if ($timezone ne 'DEFAULT') {
- $ENV{'TZ'}= $timezone;
- } else {
- delete($ENV{'TZ'});
- }
- $ENV{MTR_SUITE_DIR} = $tinfo->{suite}->{dir};
- mtr_verbose("Setting timezone: $timezone");
-
- if ( ! using_extern() )
- {
- my @restart= servers_need_restart($tinfo);
- if ( @restart != 0) {
- # Remember that we restarted for this test case (count restarts)
- $tinfo->{'restarted'}= 1;
- stop_servers(reverse @restart);
- if ($opt_warnings) {
- check_warnings_post_shutdown($server_socket);
- }
- }
-
- if ( started(all_servers()) == 0 )
- {
-
- # Remove old datadirs
- clean_datadir() unless $opt_start_dirty;
-
- # Restore old ENV
- while (my ($option, $value)= each( %old_env )) {
- if (defined $value){
- mtr_verbose("Restoring $option to $value");
- $ENV{$option}= $value;
-
- } else {
- mtr_verbose("Removing $option");
- delete($ENV{$option});
- }
- }
- %old_env= ();
-
- mtr_verbose("Generating my.cnf from '$tinfo->{template_path}'");
-
- # Generate new config file from template
- $config= My::ConfigFactory->new_config
- ( {
- testname => $tinfo->{name},
- basedir => $basedir,
- testdir => $glob_mysql_test_dir,
- template_path => $tinfo->{template_path},
- extra_template_path => $tinfo->{extra_template_path},
- vardir => $opt_vardir,
- tmpdir => $opt_tmpdir,
- baseport => $baseport,
- user => $opt_user,
- password => '',
- ssl => $opt_ssl_supported,
- embedded => $opt_embedded_server,
- }
- );
-
- fix_servers($tinfo);
-
- # Write config files:
- my %config_files = config_files($tinfo);
- while (my ($file, $generate) = each %config_files) {
- next unless $generate;
- my ($path) = "$opt_vardir/$file";
- open (F, '>', $path) or die "Could not open '$path': $!";
- print F &$generate($config);
- close F;
- }
-
- # Remember current config so a restart can occur when a test need
- # to use a different one
- $current_config_name= $tinfo->{template_path};
-
- #
- # Set variables in the ENV section
- #
- foreach my $option ($config->options_in_group("ENV"))
- {
- my ($name, $val)= ($option->name(), $option->value());
-
- # Save old value to restore it before next time
- $old_env{$name}= $ENV{$name};
-
- unless (defined $val) {
- mtr_warning("Uninitialized value for ", $name,
- ", group [ENV], file ", $current_config_name);
- } else {
- mtr_verbose($name, "=", $val);
- $ENV{$name}= $val;
- }
- }
- }
-
- # Write start of testcase to log
- mark_log($path_current_testlog, $tinfo);
-
- # Make sure the safe_process also exits from now on
- if ($opt_start_exit) {
- My::SafeProcess->start_exit();
- }
-
- if (start_servers($tinfo))
- {
- report_failure_and_restart($tinfo);
- unlink $path_current_testlog;
- return 1;
- }
- }
- mark_time_used('restart');
-
- # --------------------------------------------------------------------
- # If --start or --start-dirty given, stop here to let user manually
- # run tests
- # If --wait-all is also given, do the same, but don't die if one
- # server exits
- # ----------------------------------------------------------------------
-
- if ( $start_only )
- {
- mtr_print("\nStarted", started(all_servers()));
- mtr_print("Using config for test", $tinfo->{name});
- mtr_print("Port and socket path for server(s):");
- foreach my $mysqld ( mysqlds() )
- {
- mtr_print ($mysqld->name() . " " . $mysqld->value('port') .
- " " . $mysqld->value('socket'));
- }
- if ( $opt_start_exit )
- {
- mtr_print("Server(s) started, not waiting for them to finish");
- if (IS_WINDOWS)
- {
- POSIX::_exit(0); # exit hangs here in ActiveState Perl
- }
- else
- {
- exit(0);
- }
- }
- mtr_print("Waiting for server(s) to exit...");
- if ( $opt_wait_all ) {
- My::SafeProcess->wait_all();
- mtr_print( "All servers exited" );
- exit(1);
- }
- else {
- my $proc= My::SafeProcess->wait_any();
- if ( grep($proc eq $_, started(all_servers())) )
- {
- mtr_print("Server $proc died");
- exit(1);
- }
- mtr_print("Unknown process $proc died");
- exit(1);
- }
- }
-
- my $test_timeout= start_timer(testcase_timeout($tinfo));
-
- do_before_run_mysqltest($tinfo);
-
- mark_time_used('admin');
-
- if ( $opt_check_testcases and check_testcase($tinfo, "before") ){
- # Failed to record state of server or server crashed
- report_failure_and_restart($tinfo);
-
- return 1;
- }
-
- my $test= $tinfo->{suite}->start_test($tinfo);
- # Set to a list of processes we have to keep waiting (expectedly died servers)
- my %keep_waiting_proc = ();
- my $print_timeout= start_timer($print_freq * 60);
-
- while (1)
- {
- my $proc;
- if (%keep_waiting_proc)
- {
- # Any other process exited?
- $proc = My::SafeProcess->check_any();
- if ($proc)
- {
- mtr_verbose ("Found exited process $proc");
- }
- else
- {
- # Also check if timer has expired, if so cancel waiting
- if ( has_expired($test_timeout) )
- {
- %keep_waiting_proc = ();
- }
- }
- }
- if (!%keep_waiting_proc && !$proc)
- {
- if ($test_timeout > $print_timeout)
- {
- $proc= My::SafeProcess->wait_any_timeout($print_timeout);
- if ($proc->{timeout})
- {
- #print out that the test is still on
- mtr_print("Test still running: $tinfo->{name}");
- #reset the timer
- $print_timeout= start_timer($print_freq * 60);
- next;
- }
- }
- else
- {
- $proc= My::SafeProcess->wait_any_timeout($test_timeout);
- }
- }
-
- if ($proc and $proc eq $test) # mysqltest itself exited
- {
- my $res= $test->exit_status();
-
- if (($res == 0 or $res == 62) and $opt_warnings and check_warnings($tinfo) )
- {
- # If test case suceeded, but it has produced unexpected
- # warnings, continue with $res == 1;
- # but if the test was skipped, it should remain skipped
- $res= 1 if $res == 0;
- resfile_output($tinfo->{'warnings'}) if $opt_resfile;
- }
-
- if ( $res == 0 )
- {
- my $check_res;
- if ( restart_forced_by_test('force_restart') )
- {
- stop_all_servers($opt_shutdown_timeout);
- }
- elsif ( $opt_check_testcases and
- $check_res= check_testcase($tinfo, "after"))
- {
- if ($check_res == 1) {
- # Test case had sideeffects, not fatal error, just continue
- if ($opt_warnings) {
- # Checking error logs for warnings, so need to stop server
- # gracefully so that memory leaks etc. can be properly detected.
- stop_servers(reverse all_servers());
- check_warnings_post_shutdown($server_socket);
- # Even if we got warnings here, we should not fail this
- # particular test, as the warnings may be caused by an earlier
- # test.
- } else {
- # Not checking warnings, so can do a hard shutdown.
- stop_all_servers($opt_shutdown_timeout);
- }
- mtr_report("Resuming tests...\n");
- resfile_output($tinfo->{'check'}) if $opt_resfile;
- }
- else {
- # Test case check failed fatally, probably a server crashed
- report_failure_and_restart($tinfo);
- return 1;
- }
- }
- mtr_report_test_passed($tinfo);
- }
- elsif ( $res == 62 )
- {
- # Testcase itself tell us to skip this one
- $tinfo->{skip_detected_by_test}= 1;
- # Try to get reason from test log file
- find_testcase_skipped_reason($tinfo);
- mtr_report_test_skipped($tinfo);
- # Restart if skipped due to missing perl, it may have had side effects
- if ( restart_forced_by_test('force_restart_if_skipped') ||
- $tinfo->{'comment'} =~ /^perl not found/ )
- {
- stop_all_servers($opt_shutdown_timeout);
- }
- }
- elsif ( $res == 65 )
- {
- # Testprogram killed by signal
- $tinfo->{comment}=
- "testprogram crashed(returned code $res)";
- report_failure_and_restart($tinfo);
- }
- elsif ( $res == 1 )
- {
- # Check if the test tool requests that
- # an analyze script should be run
- my $analyze= find_analyze_request();
- if ($analyze){
- run_on_all($tinfo, "analyze-$analyze");
- }
-
- # Wait a bit and see if a server died, if so report that instead
- mtr_milli_sleep(100);
- my $srvproc= My::SafeProcess::check_any();
- if ($srvproc && grep($srvproc eq $_, started(all_servers()))) {
- $proc= $srvproc;
- goto SRVDIED;
- }
-
- # Test case failure reported by mysqltest
- report_failure_and_restart($tinfo);
- }
- else
- {
- # mysqltest failed, probably crashed
- $tinfo->{comment}=
- "mysqltest failed with unexpected return code $res\n";
- report_failure_and_restart($tinfo);
- }
-
- # Save info from this testcase run to mysqltest.log
- if( -f $path_current_testlog)
- {
- if ($opt_resfile && $res && $res != 62) {
- resfile_output_file($path_current_testlog);
- }
- mtr_appendfile_to_file($path_current_testlog, $path_testlog);
- unlink($path_current_testlog);
- }
-
- return ($res == 62) ? 0 : $res;
- }
-
- if ($proc)
- {
- # It was not mysqltest that exited, add to a wait-to-be-started-again list.
- $keep_waiting_proc{$proc} = 1;
- }
-
- mtr_verbose("Got " . join(",", keys(%keep_waiting_proc)));
-
- mark_time_used('test');
- foreach my $wait_for_proc (keys(%keep_waiting_proc)) {
- # ----------------------------------------------------
- # Check if it was an expected crash
- # ----------------------------------------------------
- my $check_crash = check_expected_crash_and_restart($wait_for_proc);
- if ($check_crash == 0) # unexpected exit/crash of $wait_for_proc
- {
- goto SRVDIED;
- }
- elsif ($check_crash == 1) # $wait_for_proc was started again by check_expected_crash_and_restart()
- {
- delete $keep_waiting_proc{$wait_for_proc};
- }
- elsif ($check_crash == 2) # we must keep waiting
- {
- # do nothing
- }
- }
-
- next;
-
- SRVDIED:
- # ----------------------------------------------------
- # Stop the test case timer
- # ----------------------------------------------------
- $test_timeout= 0;
-
- # ----------------------------------------------------
- # Check if it was a server that died
- # ----------------------------------------------------
- if ( grep($proc eq $_, started(all_servers())) )
- {
- # Server failed, probably crashed
- $tinfo->{comment}=
- "Server $proc failed during test run" .
- get_log_from_proc($proc, $tinfo->{name});
-
- # ----------------------------------------------------
- # It's not mysqltest that has exited, kill it
- # ----------------------------------------------------
- $test->kill();
-
- report_failure_and_restart($tinfo);
- return 1;
- }
-
- # Try to dump core for mysqltest and all servers
- foreach my $proc ($test, started(all_servers()))
- {
- mtr_print("Trying to dump core for $proc");
- if ($proc->dump_core())
- {
- $proc->wait_one(20);
- }
- }
-
- # ----------------------------------------------------
- # It's not mysqltest that has exited, kill it
- # ----------------------------------------------------
- $test->kill();
-
- # ----------------------------------------------------
- # Check if testcase timer expired
- # ----------------------------------------------------
- if ( $proc->{timeout} )
- {
- my $log_file_name= $opt_vardir."/log/".$tinfo->{shortname}.".log";
- $tinfo->{comment}=
- "Test case timeout after ".testcase_timeout($tinfo).
- " seconds\n\n";
- # Add 20 last executed commands from test case log file
- if (-e $log_file_name)
- {
- $tinfo->{comment}.=
- "== $log_file_name == \n".
- mtr_lastlinesfromfile($log_file_name, 20)."\n";
- }
- $tinfo->{'timeout'}= testcase_timeout($tinfo); # Mark as timeout
- run_on_all($tinfo, 'analyze-timeout');
-
- report_failure_and_restart($tinfo);
- return 1;
- }
-
- mtr_error("Unhandled process $proc exited");
- }
- mtr_error("Should never come here");
-}
-
-
-# Keep track of last position in mysqld error log where we scanned for
-# warnings, so we can attribute any warnings found to the correct test
-# suite or server restart.
-our $last_warning_position= { };
-
-# Called just before a mysqld server is started or a testcase is run,
-# to keep track of which tests have been run since last restart, and
-# of when the error log is reset.
-#
-# Second argument $test_name is test name, or undef for server restart.
-sub pre_write_errorlog {
- my ($error_log, $test_name)= @_;
-
- if (! -e $error_log) {
- # If the error log is moved away, reset the warning parse position.
- delete $last_warning_position->{$error_log};
- }
-
- if (defined($test_name)) {
- $last_warning_position->{$error_log}{test_names}= []
- unless exists($last_warning_position->{$error_log}{test_names});
- push @{$last_warning_position->{$error_log}{test_names}}, $test_name;
- } else {
- # Server restart, so clear the list of tests run since last restart.
- # (except the last one (if any), which is the test about to be run).
- if (defined($last_warning_position->{$error_log}{test_names}) &&
- @{$last_warning_position->{$error_log}{test_names}}) {
- $last_warning_position->{$error_log}{test_names}=
- [$last_warning_position->{$error_log}{test_names}[-1]];
- } else {
- $last_warning_position->{$error_log}{test_names}= [];
- }
- }
-}
-
-# Extract server log from after the last occurrence of named test
-# Return as an array of lines
-#
-
-sub extract_server_log ($$) {
- my ($error_log, $tname) = @_;
-
- return unless $error_log;
-
- # Open the servers .err log file and read all lines
- # belonging to current test into @lines
- my $Ferr = IO::File->new($error_log)
- or mtr_error("Could not open file '$error_log' for reading: $!");
-
- my @lines;
- my $found_test= 0; # Set once we've found the log of this test
- while ( my $line = <$Ferr> )
- {
- if ($found_test)
- {
- # If test wasn't last after all, discard what we found, test again.
- if ( $line =~ /^CURRENT_TEST:/)
- {
- @lines= ();
- $found_test= $line =~ /^CURRENT_TEST: $tname/;
- }
- else
- {
- push(@lines, $line);
- if (scalar(@lines) > 1000000) {
- $Ferr = undef;
- mtr_warning("Too much log in $error_log, bailing out from extracting");
- return ();
- }
- }
- }
- else
- {
- # Search for beginning of test, until found
- $found_test= 1 if ($line =~ /^CURRENT_TEST: $tname/);
- }
- }
- $Ferr = undef; # Close error log file
-
- return @lines;
-}
-
-# Get log from server identified from its $proc object, from named test
-# Return as a single string
-#
-
-sub get_log_from_proc ($$) {
- my ($proc, $name)= @_;
- my $srv_log= "";
-
- foreach my $mysqld (all_servers()) {
- if ($mysqld->{proc} eq $proc) {
- my @srv_lines= extract_server_log($mysqld->if_exist('log-error'), $name);
- $srv_log= "\nServer log from this test:\n" .
- "----------SERVER LOG START-----------\n". join ("", @srv_lines) .
- "----------SERVER LOG END-------------\n";
- last;
- }
- }
- return $srv_log;
-}
-
-#
-# Perform a rough examination of the servers
-# error log and write all lines that look
-# suspicious into $error_log.warnings
-#
-
-sub extract_warning_lines ($$) {
- my ($error_log, $append) = @_;
-
- # Open the servers .err log file and read all lines
- # belonging to current tets into @lines
- my $Ferr = IO::File->new($error_log)
- or return [];
- my $last_pos= $last_warning_position->{$error_log}{seek_pos};
- $Ferr->seek($last_pos, 0) if defined($last_pos);
- # If the seek fails, we will parse the whole error log, at least we will not
- # miss any warnings.
-
- my @lines= <$Ferr>;
- $last_warning_position->{$error_log}{seek_pos}= $Ferr->tell();
- $Ferr = undef; # Close error log file
-
- # mysql_client_test.test sends a COM_DEBUG packet to the server
- # to provoke a safemalloc leak report, ignore any warnings
- # between "Begin/end safemalloc memory dump"
- if ( grep(/Begin safemalloc memory dump:/, @lines) > 0)
- {
- my $discard_lines= 1;
- foreach my $line ( @lines )
- {
- if ($line =~ /Begin safemalloc memory dump:/){
- $discard_lines = 1;
- } elsif ($line =~ /End safemalloc memory dump./){
- $discard_lines = 0;
- }
-
- if ($discard_lines){
- $line = "ignored";
- }
- }
- }
-
- # Write all suspicious lines to $error_log.warnings file
- my $warning_log = "$error_log.warnings";
- my $Fwarn = IO::File->new($warning_log, $append ? "a+" : "w")
- or die("Could not open file '$warning_log' for writing: $!");
- if (!$append)
- {
- print $Fwarn "Suspicious lines from $error_log\n";
- }
-
- my @patterns =
- (
- qr/^Warning|(mysqld|mariadbd): Warning|\[Warning\]/,
- qr/^Error:|\[ERROR\]/,
- qr/^==\d+==\s+\S/, # valgrind errors
- qr/InnoDB: Warning|InnoDB: Error/,
- qr/^safe_mutex:|allocated at line/,
- qr/missing DBUG_RETURN/,
- qr/Attempting backtrace/,
- qr/Assertion .* failed/,
- qr/Sanitizer/,
- qr/runtime error:/,
- );
- # These are taken from the include/mtr_warnings.sql global suppression
- # list. They occur delayed, so they can be parsed during shutdown rather
- # than during the per-test check.
- #
- # ToDo: having the warning suppressions inside the mysqld we are trying to
- # check is in any case horrible. We should change it to all be done here
- # within the Perl code, which is both simpler, easier, faster, and more
- # robust. We could still have individual test cases put in suppressions by
- # parsing statically or by writing dynamically to a CSV table read by the
- # Perl code.
- my @antipatterns =
- (
- @global_suppressions,
- qr/error .*connecting to master/,
- qr/InnoDB: Error: in ALTER TABLE `test`.`t[12]`/,
- qr/InnoDB: Error: table `test`.`t[12]` .*does not exist in the InnoDB internal/,
- qr/InnoDB: Warning: a long semaphore wait:/,
- qr/InnoDB: Dumping buffer pool.*/,
- qr/InnoDB: Buffer pool.*/,
- qr/InnoDB: Warning: Writer thread is waiting this semaphore:/,
- qr/InnoDB: innodb_open_files .* should not be greater than/,
- qr/Slave: Unknown table 't1' .* 1051/,
- qr/Slave SQL:.*(Internal MariaDB error code: [[:digit:]]+|Query:.*)/,
- qr/slave SQL thread aborted/,
- qr/unknown option '--loose[-_]/,
- qr/unknown variable 'loose[-_]/,
- #qr/Invalid .*old.* table or database name/,
- qr/Now setting lower_case_table_names to [02]/,
- qr/Setting lower_case_table_names=2/,
- qr/You have forced lower_case_table_names to 0/,
- qr/deprecated/,
- qr/Slave SQL thread retried transaction/,
- qr/Slave \(additional info\)/,
- qr/Incorrect information in file/,
- qr/Simulating error for/,
- qr/Slave I\/O: Get master SERVER_ID failed with error:.*/,
- qr/Slave I\/O: Get master clock failed with error:.*/,
- qr/Slave I\/O: Get master COLLATION_SERVER failed with error:.*/,
- qr/Slave I\/O: Get master TIME_ZONE failed with error:.*/,
- qr/Slave I\/O: Get master \@\@GLOBAL.gtid_domain_id failed with error:.*/,
- qr/Slave I\/O: Setting \@slave_connect_state failed with error:.*/,
- qr/Slave I\/O: Setting \@slave_gtid_strict_mode failed with error:.*/,
- qr/Slave I\/O: Setting \@slave_gtid_ignore_duplicates failed with error:.*/,
- qr/Slave I\/O: Setting \@slave_until_gtid failed with error:.*/,
- qr/Slave I\/O: Get master GTID position failed with error:.*/,
- qr/Slave I\/O: error reconnecting to master '.*' - retry-time: [1-3] retries/,
- qr/Slave I\/0: Master command COM_BINLOG_DUMP failed/,
- qr/Error reading packet/,
- qr/Lost connection to MariaDB server at 'reading initial communication packet'/,
- qr/Failed on request_dump/,
- qr/Slave: Can't drop database.* database doesn't exist/,
- qr/Slave: Operation DROP USER failed for 'create_rout_db'/,
- qr|Checking table: '\..mtr.test_suppressions'|,
- qr|Table \./test/bug53592 has a primary key in InnoDB data dictionary, but not in|,
- qr|Table '\..mtr.test_suppressions' is marked as crashed and should be repaired|,
- qr|Table 'test_suppressions' is marked as crashed and should be repaired|,
- qr|Can't open shared library|,
- qr|Couldn't load plugin named .*EXAMPLE.*|,
- qr|InnoDB: Error: table 'test/bug39438'|,
- qr| entry '.*' ignored in --skip-name-resolve mode|,
- qr|mysqld got signal 6|,
- qr|Error while setting value 'pool-of-threads' to 'thread_handling'|,
- qr|Access denied for user|,
- qr|Aborted connection|,
- qr|table.*is full|,
- qr/\[ERROR\] (mysqld|mariadbd): \Z/, # Warning from Aria recovery
- qr|Linux Native AIO|, # warning that aio does not work on /dev/shm
- qr|InnoDB: io_setup\(\) attempt|,
- qr|InnoDB: io_setup\(\) failed with EAGAIN|,
- qr|io_uring_queue_init\(\) failed with|,
- qr|InnoDB: liburing disabled|,
- qr|setrlimit could not change the size of core files to 'infinity';|,
- qr|feedback plugin: failed to retrieve the MAC address|,
- qr|Plugin 'FEEDBACK' init function returned error|,
- qr|Plugin 'FEEDBACK' registration as a INFORMATION SCHEMA failed|,
- qr|'log-bin-use-v1-row-events' is MySQL .* compatible option|,
- qr|InnoDB: Setting thread \d+ nice to \d+ failed, current nice \d+, errno 13|, # setpriority() fails under valgrind
- qr|Failed to setup SSL|,
- qr|SSL error: Failed to set ciphers to use|,
- qr/Plugin 'InnoDB' will be forced to shutdown/,
- qr|Could not increase number of max_open_files to more than|,
- qr|Changed limits: max_open_files|,
- qr/InnoDB: Error table encrypted but encryption service not available.*/,
- qr/InnoDB: Could not find a valid tablespace file for*/,
- qr/InnoDB: Tablespace open failed for*/,
- qr/InnoDB: Failed to find tablespace for table*/,
- qr/InnoDB: Space */,
- qr|InnoDB: You may have to recover from a backup|,
- qr|InnoDB: It is also possible that your operatingsystem has corrupted its own file cache|,
- qr|InnoDB: and rebooting your computer removes the error|,
- qr|InnoDB: If the corrupt page is an index page you can also try to|,
- qr|nnoDB: fix the corruption by dumping, dropping, and reimporting|,
- qr|InnoDB: the corrupt table. You can use CHECK|,
- qr|InnoDB: TABLE to scan your table for corruption|,
- qr/InnoDB: See also */,
- qr/InnoDB: Cannot open .*ib_buffer_pool.* for reading: No such file or directory*/,
- qr/InnoDB: Table .*mysql.*innodb_table_stats.* not found./,
- qr/InnoDB: User stopword table .* does not exist./,
- qr/Dump thread [0-9]+ last sent to server [0-9]+ binlog file:pos .+/,
- qr/Detected table cache mutex contention at instance .* waits. Additional table cache instance cannot be activated: consider raising table_open_cache_instances. Number of active instances/,
- qr/WSREP: Failed to guess base node address/,
- qr/WSREP: Guessing address for incoming client/,
-
- # for UBSAN
- qr/decimal\.c.*: runtime error: signed integer overflow/,
- # Disable test for UBSAN on dynamically loaded objects
- qr/runtime error: member call.*object.*'Handler_share'/,
- qr/sql_type\.cc.* runtime error: member call.*object.* 'Type_collection'/,
- );
-
- my $matched_lines= [];
- LINE: foreach my $line ( @lines )
- {
- PAT: foreach my $pat ( @patterns )
- {
- if ( $line =~ /$pat/ )
- {
- foreach my $apat (@antipatterns)
- {
- next LINE if $line =~ $apat;
- }
- print $Fwarn $line;
- push @$matched_lines, $line;
- last PAT;
- }
- }
- }
- $Fwarn = undef; # Close file
-
- if (scalar(@$matched_lines) > 0 &&
- defined($last_warning_position->{$error_log}{test_names})) {
- return ($last_warning_position->{$error_log}{test_names}, $matched_lines);
- } else {
- return ([], $matched_lines);
- }
-}
-
-
-# Run include/check-warnings.test
-#
-# RETURN VALUE
-# 0 OK
-# 1 Check failed
-#
-sub start_check_warnings ($$) {
- my $tinfo= shift;
- my $mysqld= shift;
-
- my $name= "warnings-".$mysqld->name();
-
- my $log_error= $mysqld->value('log-error');
- # To be communicated to the test
- $ENV{MTR_LOG_ERROR}= $log_error;
- extract_warning_lines($log_error, 0);
-
- my $args;
- mtr_init_args(\$args);
-
- mtr_add_arg($args, "--defaults-file=%s", $path_config_file);
- mtr_add_arg($args, "--defaults-group-suffix=%s", $mysqld->after('mysqld'));
- mtr_add_arg($args, "--test-file=%s", "include/check-warnings.test");
-
- if ( $opt_embedded_server )
- {
-
- # Get the args needed for the embedded server
- # and append them to args prefixed
- # with --sever-arg=
-
- my $mysqld= $config->group('embedded')
- or mtr_error("Could not get [embedded] section");
-
- my $mysqld_args;
- mtr_init_args(\$mysqld_args);
- my $extra_opts= get_extra_opts($mysqld, $tinfo);
- mysqld_arguments($mysqld_args, $mysqld, $extra_opts);
- mtr_add_arg($args, "--server-arg=%s", $_) for @$mysqld_args;
- }
-
- my $errfile= "$opt_vardir/tmp/$name.err";
- my $proc= My::SafeProcess->new
- (
- name => $name,
- path => $exe_mysqltest,
- error => $errfile,
- output => $errfile,
- args => \$args,
- user_data => [$errfile, $mysqld],
- verbose => $opt_verbose,
- );
- mtr_verbose("Started $proc");
- return $proc;
-}
-
-
-#
-# Loop through our list of processes and check the error log
-# for unexpected errors and warnings
-#
-sub check_warnings ($) {
- my ($tinfo)= @_;
- my $res= 0;
-
- my $tname= $tinfo->{name};
-
- # Clear previous warnings
- delete($tinfo->{warnings});
-
- # Start the mysqltest processes in parallel to save time
- # also makes it possible to wait for any process to exit during the check
- my %started;
- foreach my $mysqld ( mysqlds() )
- {
- if ( defined $mysqld->{'proc'} )
- {
- my $proc= start_check_warnings($tinfo, $mysqld);
- $started{$proc->pid()}= $proc;
- }
- }
-
- # Return immediately if no check proceess was started
- return 0 unless ( keys %started );
-
- my $timeout= start_timer(check_timeout($tinfo));
-
- my $result= 0;
- while (1){
- my $proc= My::SafeProcess->wait_any_timeout($timeout);
- mtr_report("Got $proc");
-
- if ( delete $started{$proc->pid()} ) {
- # One check warning process returned
- my $res= $proc->exit_status();
- my ($err_file, $mysqld)= @{$proc->user_data()};
-
- if ( $res == 0 or $res == 62 ){
-
- if ( $res == 0 ) {
- # Check completed with problem
- my $report= mtr_grab_file($err_file);
- # Log to var/log/warnings file
- mtr_tofile("$opt_vardir/log/warnings",
- $tname."\n".$report);
-
- $tinfo->{'warnings'}.= $report;
- $result= 1;
- }
-
- if ( $res == 62 ) {
- # Test case was ok and called "skip"
- # Remove the .err file the check generated
- unlink($err_file);
- }
-
- if ( keys(%started) == 0){
- # All checks completed
- mark_time_used('ch-warn');
- return $result;
- }
- # Wait for next process to exit
- next;
- }
- else
- {
- my $report= mtr_grab_file($err_file);
- $tinfo->{comment}.=
- "Could not execute 'check-warnings' for ".
- "testcase '$tname' (res: $res) server: '".
- $mysqld->name() .":\n";
- $tinfo->{comment}.= $report;
-
- $result= 2;
- }
- }
- elsif ( $proc->{timeout} ) {
- $tinfo->{comment}.= "Timeout for 'check warnings' expired after "
- .check_timeout($tinfo)." seconds";
- $result= 4;
- }
- else {
- # Unknown process returned, most likley a crash, abort everything
- $tinfo->{comment}=
- "The server $proc crashed while running 'check warnings'".
- get_log_from_proc($proc, $tinfo->{name});
- $result= 3;
- }
-
- # Kill any check processes still running
- map($_->kill(), values(%started));
-
- mark_time_used('ch-warn');
- return $result;
- }
-
- mtr_error("INTERNAL_ERROR: check_warnings");
-}
-
-# Check for warnings generated during shutdown of a mysqld server.
-# If any, report them to master server, and return true; else just return
-# false.
-
-sub check_warnings_post_shutdown {
- my ($server_socket)= @_;
- my $testname_hash= { };
- my $report= '';
- foreach my $mysqld ( mysqlds())
- {
- my ($testlist, $match_lines)=
- extract_warning_lines($mysqld->value('log-error'), 1);
- $testname_hash->{$_}= 1 for @$testlist;
- $report.= join('', @$match_lines);
- }
- my @warning_tests= keys(%$testname_hash);
- if (@warning_tests) {
- my $fake_test= My::Test->new(testnames => \@warning_tests);
- $fake_test->{'warnings'}= $report;
- $fake_test->write_test($server_socket, 'WARNINGS');
- }
-}
-
-#
-# Loop through our list of processes and look for and entry
-# with the provided pid, if found check for the file indicating
-# expected crash and restart it.
-#
-sub check_expected_crash_and_restart {
- my ($proc)= @_;
-
- foreach my $mysqld ( mysqlds() )
- {
- next unless ( $mysqld->{proc} and $mysqld->{proc} eq $proc );
-
- # Check if crash expected by looking at the .expect file
- # in var/tmp
- my $expect_file= "$opt_vardir/tmp/".$mysqld->name().".expect";
- if ( -f $expect_file )
- {
- mtr_verbose("Crash was expected, file '$expect_file' exists");
-
- for (my $waits = 0; $waits < 50; mtr_milli_sleep(100), $waits++)
- {
- # Race condition seen on Windows: try again until file not empty
- next if -z $expect_file;
- # If last line in expect file starts with "wait"
- # sleep a little and try again, thus allowing the
- # test script to control when the server should start
- # up again. Keep trying for up to 5s at a time.
- my $last_line= mtr_lastlinesfromfile($expect_file, 1);
- if ($last_line =~ /^wait/ )
- {
- mtr_verbose("Test says wait before restart") if $waits == 0;
- next;
- }
-
- # Ignore any partial or unknown command
- next unless $last_line =~ /^restart/;
- # If last line begins "restart:", the rest of the line is read as
- # extra command line options to add to the restarted mysqld.
- # Anything other than 'wait' or 'restart:' (with a colon) will
- # result in a restart with original mysqld options.
- if ($last_line =~ /restart:(.+)/) {
- my @rest_opt= split(' ', $1);
- $mysqld->{'restart_opts'}= \@rest_opt;
- } else {
- delete $mysqld->{'restart_opts'};
- }
- unlink($expect_file);
-
- # Start server with same settings as last time
- mysqld_start($mysqld, $mysqld->{'started_opts'});
-
- return 1;
- }
- # Loop ran through: we should keep waiting after a re-check
- return 2;
- }
- }
-
- # Not an expected crash
- return 0;
-}
-
-
-# Remove all files and subdirectories of a directory
-sub clean_dir {
- my ($dir)= @_;
- mtr_verbose("clean_dir: $dir");
- finddepth(
- { no_chdir => 1,
- wanted => sub {
- if (-d $_){
- # A dir
- if ($_ eq $dir){
- # The dir to clean
- return;
- } else {
- mtr_verbose("rmdir: '$_'");
- rmdir($_) or mtr_warning("rmdir($_) failed: $!");
- }
- } else {
- # Hopefully a file
- mtr_verbose("unlink: '$_'");
- unlink($_) or mtr_warning("unlink($_) failed: $!");
- }
- }
- },
- $dir);
-}
-
-
-sub clean_datadir {
- mtr_verbose("Cleaning datadirs...");
-
- if (started(all_servers()) != 0){
- mtr_error("Trying to clean datadir before all servers stopped");
- }
-
- for (all_servers())
- {
- my $dir= "$opt_vardir/".$_->{name};
- mtr_verbose(" - removing '$dir'");
- rmtree($dir);
- }
-
- # Remove all files in tmp and var/tmp
- clean_dir("$opt_vardir/tmp");
- if ($opt_tmpdir ne "$opt_vardir/tmp"){
- clean_dir($opt_tmpdir);
- }
-}
-
-
-#
-# Save datadir before it's removed
-#
-sub save_datadir_after_failure($$) {
- my ($dir, $savedir)= @_;
-
- mtr_report(" - saving '$dir'");
- my $dir_name= basename($dir);
- rename("$dir", "$savedir/$dir_name");
-}
-
-
-sub after_failure ($) {
- my ($tinfo)= @_;
-
- mtr_report("Saving datadirs...");
-
- my $save_dir= "$opt_vardir/log/";
- $save_dir.= $tinfo->{name};
- # Add combination name if any
- $save_dir.= '-' . join(',', sort @{$tinfo->{combinations}})
- if defined $tinfo->{combinations};
-
- # Save savedir path for server
- $tinfo->{savedir}= $save_dir;
-
- mkpath($save_dir) if ! -d $save_dir;
-
- #
- # Create a log of files in vardir (good for buildbot)
- #
- if (!IS_WINDOWS)
- {
- my $Flog= IO::File->new("$opt_vardir/log/files.log", "w");
- if ($Flog)
- {
- print $Flog scalar(`/bin/ls -Rl $opt_vardir/*`);
- close($Flog);
- }
- }
-
- # Save the used config files
- my %config_files = config_files($tinfo);
- while (my ($file, $generate) = each %config_files) {
- copy("$opt_vardir/$file", $save_dir);
- }
-
- # Copy the tmp dir
- copytree("$opt_vardir/tmp/", "$save_dir/tmp/");
-
- foreach (all_servers()) {
- my $dir= "$opt_vardir/".$_->{name};
- save_datadir_after_failure($dir, $save_dir);
- }
-}
-
-
-sub report_failure_and_restart ($) {
- my $tinfo= shift;
-
- if ($opt_valgrind && ($tinfo->{'warnings'} || $tinfo->{'timeout'}) &&
- $opt_core_on_failure == 0)
- {
- # In these cases we may want valgrind report from normal termination
- $tinfo->{'dont_kill_server'}= 1;
- }
- # Shutdown properly if not to be killed (for valgrind)
- stop_all_servers($tinfo->{'dont_kill_server'} ? $opt_shutdown_timeout : 0);
-
- $tinfo->{'result'}= 'MTR_RES_FAILED';
-
- my $test_failures= $tinfo->{'failures'} || 0;
- $tinfo->{'failures'}= $test_failures + 1;
-
-
- if ( $tinfo->{comment} )
- {
- # The test failure has been detected by mysql-test-run.pl
- # when starting the servers or due to other error, the reason for
- # failing the test is saved in "comment"
- ;
- }
-
- if ( !defined $tinfo->{logfile} )
- {
- my $logfile= $path_current_testlog;
- if ( defined $logfile )
- {
- if ( -f $logfile )
- {
- # Test failure was detected by test tool and its report
- # about what failed has been saved to file. Save the report
- # in tinfo
- $tinfo->{logfile}= mtr_fromfile($logfile);
- # If no newlines in the test log:
- # (it will contain the CURRENT_TEST written by mtr, so is not empty)
- if ($tinfo->{logfile} !~ /\n/)
- {
- # Show how far it got before suddenly failing
- $tinfo->{comment}.= "mysqltest failed but provided no output\n";
- my $log_file_name= $opt_vardir."/log/".$tinfo->{shortname}.".log";
- if (-e $log_file_name) {
- $tinfo->{comment}.=
- "The result from queries just before the failure was:".
- "\n< snip >\n".
- mtr_lastlinesfromfile($log_file_name, $opt_tail_lines)."\n";
- }
- }
- }
- else
- {
- # The test tool report didn't exist, display an
- # error message
- $tinfo->{logfile}= "Could not open test tool report '$logfile'";
- }
- }
- }
-
- after_failure($tinfo);
-
- mtr_report_test($tinfo);
-
-}
-
-
-sub run_system(@) {
- mtr_verbose("Running '$_[0]'");
- my $ret= system(@_) >> 8;
- return $ret;
-}
-
-
-sub mysqld_stop {
- my $mysqld= shift or die "usage: mysqld_stop(<mysqld>)";
-
- my $args;
- mtr_init_args(\$args);
-
- mtr_add_arg($args, "--no-defaults");
- mtr_add_arg($args, "--character-sets-dir=%s", $mysqld->value('character-sets-dir'));
- mtr_add_arg($args, "--user=%s", $opt_user);
- mtr_add_arg($args, "--password=");
- mtr_add_arg($args, "--port=%d", $mysqld->value('port'));
- mtr_add_arg($args, "--host=%s", $mysqld->value('#host'));
- mtr_add_arg($args, "--connect_timeout=20");
- mtr_add_arg($args, "--protocol=tcp");
-
- mtr_add_arg($args, "shutdown");
-
- My::SafeProcess->run
- (
- name => "mysqladmin shutdown ".$mysqld->name(),
- path => $exe_mysqladmin,
- args => \$args,
- error => "$opt_vardir/log/mysqladmin.err",
-
- );
-}
-
-
-sub mysqld_arguments ($$$) {
- my $args= shift;
- my $mysqld= shift;
- my $extra_opts= shift;
-
- my @defaults = grep(/^--defaults-file=/, @$extra_opts);
- if (@defaults > 0) {
- mtr_add_arg($args, pop(@defaults))
- }
- else {
- mtr_add_arg($args, "--defaults-file=%s", $path_config_file);
- }
-
- # When mysqld is run by a root user(euid is 0), it will fail
- # to start unless we specify what user to run as, see BUG#30630
- my $euid= $>;
- if (!IS_WINDOWS and $euid == 0 and
- (grep(/^--user/, @$extra_opts)) == 0) {
- mtr_add_arg($args, "--user=root");
- }
-
- if (!using_extern() and !$opt_user_args)
- {
- # Turn on logging to file
- mtr_add_arg($args, "%s--log-output=file");
- }
-
- # Check if "extra_opt" contains --log-bin
- my $skip_binlog= not grep /^--(loose-)?log-bin/, @$extra_opts;
-
- my $found_skip_core= 0;
- foreach my $arg ( @$extra_opts )
- {
- # Skip --defaults-file option since it's handled above.
- next if $arg =~ /^--defaults-file/;
-
- # Allow --skip-core-file to be set in <testname>-[master|slave].opt file
- if ($arg eq "--skip-core-file")
- {
- $found_skip_core= 1;
- }
- elsif ($skip_binlog and mtr_match_prefix($arg, "--binlog-format"))
- {
- ; # Dont add --binlog-format when running without binlog
- }
- elsif ($arg eq "--loose-skip-log-bin" and
- $mysqld->option("log-slave-updates"))
- {
- ; # Dont add --skip-log-bin when mysqld have --log-slave-updates in config
- }
- else
- {
- mtr_add_arg($args, "%s", $arg);
- }
- }
- $opt_skip_core = $found_skip_core;
- if ( !$found_skip_core && !$opt_user_args )
- {
- mtr_add_arg($args, "%s", "--core-file");
- }
-
- # Enable the debug sync facility, set default wait timeout.
- # Facility stays disabled if timeout value is zero.
- mtr_add_arg($args, "--loose-debug-sync-timeout=%s",
- $opt_debug_sync_timeout) unless $opt_user_args;
-
- return $args;
-}
-
-
-
-sub mysqld_start ($$) {
- my $mysqld= shift;
- my $extra_opts= shift;
-
- mtr_verbose(My::Options::toStr("mysqld_start", @$extra_opts));
-
- my $exe= find_mysqld($mysqld->value('basedir'));
-
- mtr_error("Internal error: mysqld should never be started for embedded")
- if $opt_embedded_server;
-
- my $args;
- mtr_init_args(\$args);
-
- mtr_add_arg($args, "--defaults-group-suffix=%s", $mysqld->after('mysqld'));
-
- # Add any additional options from an in-test restart
- my @all_opts= @$extra_opts;
- if (exists $mysqld->{'restart_opts'}) {
- push (@all_opts, @{$mysqld->{'restart_opts'}});
- mtr_verbose(My::Options::toStr("mysqld_start restart",
- @{$mysqld->{'restart_opts'}}));
- }
- mysqld_arguments($args,$mysqld,\@all_opts);
-
- if ( $opt_debug )
- {
- mtr_add_arg($args, "--debug-dbug=$debug_d:t:i:A,%s/log/%s.trace",
- $path_vardir_trace, $mysqld->name());
- }
-
-
- # Command line for mysqld started for *this particular test*.
- # Differs from "generic" MYSQLD_CMD by including all command line
- # options from *.opt and *.combination files.
- $ENV{'MYSQLD_LAST_CMD'}= "$exe @$args";
-
- My::Debugger::setup_args(\$args, \$exe, $mysqld->name());
- $ENV{'VALGRIND_TEST'}= $opt_valgrind = int(($exe || '') eq 'valgrind');
-
- # Remove the old pidfile if any
- unlink($mysqld->value('pid-file'));
-
- my $output= $mysqld->value('log-error');
-
- if ( $opt_valgrind and $opt_debug )
- {
- # When both --valgrind and --debug is selected, send
- # all output to the trace file, making it possible to
- # see the exact location where valgrind complains
-
- # Write a message about this to the normal log file
- my $trace_name= "$opt_vardir/log/".$mysqld->name().".trace";
- mtr_tofile($output,
- "NOTE: When running with --valgrind --debug the output from ",
- "mysqld (where the valgrind messages shows up) is stored ",
- "together with the trace file to make it ",
- "easier to find the exact position of valgrind errors.",
- "See trace file $trace_name.\n");
- $output= $trace_name;
-
- }
- # Remember this log file for valgrind error report search
- $mysqld_logs{$output}= 1 if $opt_valgrind;
- # Remember data dir for gmon.out files if using gprof
- $gprof_dirs{$mysqld->value('datadir')}= 1 if $opt_gprof;
-
- if ( defined $exe )
- {
- pre_write_errorlog($output);
- $mysqld->{'proc'}= My::SafeProcess->new
- (
- name => $mysqld->name(),
- path => $exe,
- args => \$args,
- output => $output,
- error => $output,
- append => 1,
- verbose => $opt_verbose,
- nocore => $opt_skip_core,
- host => undef,
- shutdown => sub { mysqld_stop($mysqld) },
- envs => \@opt_mysqld_envs,
- );
- mtr_verbose("Started $mysqld->{proc}");
- }
-
- if (!sleep_until_file_created($mysqld->value('pid-file'),
- $opt_start_timeout, $mysqld->{'proc'}, $warn_seconds))
- {
- my $mname= $mysqld->name();
- # Report failure about the last test case before exit
- my $test_name= mtr_grab_file($path_current_testlog);
- $test_name =~ s/^CURRENT_TEST:\s//;
- my $tinfo = My::Test->new(name => $test_name);
- $tinfo->{result}= 'MTR_RES_FAILED';
- $tinfo->{failures}= 1;
- $tinfo->{logfile}=get_log_from_proc($mysqld->{'proc'}, $tinfo->{name});
- report_option('verbose', 1);
- mtr_report_test($tinfo);
- mtr_error("Failed to start mysqld $mname with command $exe");
- }
-
- # Remember options used when starting
- $mysqld->{'started_opts'}= $extra_opts;
-
- return;
-}
-
-
-sub stop_all_servers () {
- my $shutdown_timeout = $_[0] or 0;
-
- mtr_verbose("Stopping all servers...");
-
- # Kill all started servers
- My::SafeProcess::shutdown($shutdown_timeout,
- started(all_servers()));
-
- # Remove pidfiles
- foreach my $server ( all_servers() )
- {
- my $pid_file= $server->if_exist('pid-file');
- unlink($pid_file) if defined $pid_file;
- }
-
- # Mark servers as stopped
- map($_->{proc}= undef, all_servers());
-
-}
-
-
-# Find out if server should be restarted for this test
-sub server_need_restart {
- my ($tinfo, $server)= @_;
-
- if ( using_extern() )
- {
- mtr_verbose_restart($server, "no restart for --extern server");
- return 0;
- }
-
- if ( $tinfo->{'force_restart'} ) {
- mtr_verbose_restart($server, "forced in .opt file");
- return 1;
- }
-
- if ( $opt_force_restart ) {
- mtr_verbose_restart($server, "forced restart turned on");
- return 1;
- }
-
- if ( $tinfo->{template_path} ne $current_config_name)
- {
- mtr_verbose_restart($server, "using different config file");
- return 1;
- }
-
- if ( $tinfo->{'master_sh'} || $tinfo->{'slave_sh'} )
- {
- mtr_verbose_restart($server, "sh script to run");
- return 1;
- }
-
- if ( ! started($server) )
- {
- mtr_verbose_restart($server, "not started");
- return 1;
- }
-
- my $started_tinfo= $server->{'started_tinfo'};
- if ( defined $started_tinfo )
- {
-
- # Check if timezone of test that server was started
- # with differs from timezone of next test
- if ( timezone($started_tinfo) ne timezone($tinfo) )
- {
- mtr_verbose_restart($server, "different timezone");
- return 1;
- }
- }
-
- if ($server->name() =~ /^mysqld\./)
- {
-
- # Check that running process was started with same options
- # as the current test requires
- my $extra_opts= get_extra_opts($server, $tinfo);
- my $started_opts= $server->{'started_opts'};
-
- # Also, always restart if server had been restarted with additional
- # options within test.
- if (!My::Options::same($started_opts, $extra_opts) ||
- exists $server->{'restart_opts'})
- {
- delete $server->{'restart_opts'};
- my $use_dynamic_option_switch= 0;
- my $restart_opts = delete $server->{'restart_opts'} || [];
- if (!$use_dynamic_option_switch)
- {
- mtr_verbose_restart($server, "running with different options '" .
- join(" ", @{$extra_opts}) . "' != '" .
- join(" ", @{$started_opts}, @{$restart_opts}) . "'" );
- return 1;
- }
-
- mtr_verbose(My::Options::toStr("started_opts", @$started_opts));
- mtr_verbose(My::Options::toStr("extra_opts", @$extra_opts));
-
- # Get diff and check if dynamic switch is possible
- my @diff_opts= My::Options::diff($started_opts, $extra_opts);
- mtr_verbose(My::Options::toStr("diff_opts", @diff_opts));
-
- my $query= My::Options::toSQL(@diff_opts);
- mtr_verbose("Attempting dynamic switch '$query'");
- if (run_query($tinfo, $server, $query)){
- mtr_verbose("Restart: running with different options '" .
- join(" ", @{$extra_opts}) . "' != '" .
- join(" ", @{$started_opts}) . "'" );
- return 1;
- }
-
- # Remember the dynamically set options
- $server->{'started_opts'}= $extra_opts;
- }
- }
-
- # Default, no restart
- return 0;
-}
-
-
-sub servers_need_restart($) {
- my ($tinfo)= @_;
- return grep { server_need_restart($tinfo, $_); } all_servers();
-}
-
-
-
-############################################
-
-############################################
-
-#
-# Filter a list of servers and return the SafeProcess
-# for only those that are started or stopped
-#
-sub started { return grep(defined $_, map($_->{proc}, @_)); }
-sub stopped { return grep(!defined $_, map($_->{proc}, @_)); }
-
-
-sub get_extra_opts {
- # No extra options if --user-args
- return \@opt_extra_mysqld_opt if $opt_user_args;
-
- my ($mysqld, $tinfo)= @_;
-
- my $opts=
- $mysqld->option("#!use-slave-opt") ?
- $tinfo->{slave_opt} : $tinfo->{master_opt};
-
- # Expand environment variables
- foreach my $opt ( @$opts )
- {
- no warnings 'uninitialized';
- $opt =~ s/\$\{(\w+)\}/$ENV{$1}/ge;
- $opt =~ s/\$(\w+)/$ENV{$1}/ge;
- }
- return $opts;
-}
-
-
-sub stop_servers($$) {
- my (@servers)= @_;
-
- mtr_report("Stopping ", started(@servers));
-
- My::SafeProcess::shutdown($opt_shutdown_timeout,
- started(@servers));
-
- foreach my $server (@servers)
- {
- # Mark server as stopped
- $server->{proc}= undef;
-
- # Forget history
- delete $server->{'started_tinfo'};
- delete $server->{'started_opts'};
- delete $server->{'started_cnf'};
- }
-}
-
-#
-# run_query_output
-#
-# Run a query against a server using mysql client. The output of
-# the query will be written into outfile.
-#
-sub run_query_output {
- my ($mysqld, $query, $outfile)= @_;
- my $args;
-
- mtr_init_args(\$args);
- mtr_add_arg($args, "--defaults-file=%s", $path_config_file);
- mtr_add_arg($args, "--defaults-group-suffix=%s", $mysqld->after('mysqld'));
- mtr_add_arg($args, "--silent");
- mtr_add_arg($args, "--execute=%s", $query);
-
- my $res= My::SafeProcess->run
- (
- name => "run_query_output -> ".$mysqld->name(),
- path => $exe_mysql,
- args => \$args,
- output => $outfile,
- error => $outfile
- );
-
- return $res
-}
-
-
-#
-# wsrep_wait_ready
-#
-# Wait until the server has been joined to the cluster and is
-# ready for operation.
-#
-# RETURN
-# 1 Server is ready
-# 0 Server didn't transition to ready state within start timeout
-#
-sub wait_wsrep_ready($$) {
- my ($tinfo, $mysqld)= @_;
-
- my $sleeptime= 100; # Milliseconds
- my $loops= ($opt_start_timeout * 1000) / $sleeptime;
-
- my $name= $mysqld->name();
- my $outfile= "$opt_vardir/tmp/$name.wsrep_ready";
- my $query= "SET SESSION wsrep_sync_wait = 0;
- SELECT VARIABLE_NAME, VARIABLE_VALUE
- FROM INFORMATION_SCHEMA.GLOBAL_STATUS
- WHERE VARIABLE_NAME = 'wsrep_ready'";
-
- for (my $loop= 1; $loop <= $loops; $loop++)
- {
- # Careful... if MTR runs with option 'verbose' then the
- # file contains also SafeProcess verbose output
- if (run_query_output($mysqld, $query, $outfile) == 0 &&
- mtr_grab_file($outfile) =~ /WSREP_READY\s+ON/)
- {
- unlink($outfile);
- return 1;
- }
- mtr_milli_sleep($sleeptime);
- }
-
- $tinfo->{logfile}= "WSREP did not transition to state READY";
- return 0;
-}
-
-#
-# wsrep_is_bootstrap_server
-#
-# Check if the server is the first one to be started in the
-# cluster.
-#
-# RETURN
-# 1 The server is a bootstrap server
-# 0 The server is not a bootstrap server
-#
-sub wsrep_is_bootstrap_server($) {
- my $mysqld= shift;
-
- my $cluster_address= $mysqld->if_exist('wsrep-cluster-address') ||
- $mysqld->if_exist('wsrep_cluster_address');
- if (defined $cluster_address)
- {
- return $cluster_address eq "gcomm://" || $cluster_address eq "'gcomm://'";
- }
- return 0;
-}
-
-#
-# wsrep_on
-#
-# Check if wsrep has been enabled for a server.
-#
-# RETURN
-# 1 Wsrep has been enabled
-# 0 Wsrep is not enabled
-#
-sub wsrep_on($) {
- my $mysqld= shift;
- #check if wsrep_on= is set in configuration
- if ($mysqld->if_exist('wsrep-on')) {
- my $on= "".$mysqld->value('wsrep-on');
- if ($on eq "1" || $on eq "ON") {
- return 1;
- }
- }
- return 0;
-}
-
-
-#
-# start_servers
-#
-# Start servers not already started
-#
-# RETURN
-# 0 OK
-# 1 Start failed
-#
-sub start_servers($) {
- my ($tinfo)= @_;
-
- for (all_servers()) {
- $_->{START}->($_, $tinfo) if $_->{START};
- }
-
- for (all_servers()) {
- next unless $_->{WAIT} and started($_);
- if ($_->{WAIT}->($_, $tinfo)) {
- return 1;
- }
- }
- return 0;
-}
-
-
-#
-# Run include/check-testcase.test
-# Before a testcase, run in record mode and save result file to var/tmp
-# After testcase, run and compare with the recorded file, they should be equal!
-#
-# RETURN VALUE
-# The newly started process
-#
-sub start_check_testcase ($$$) {
- my $tinfo= shift;
- my $mode= shift;
- my $mysqld= shift;
-
- my $name= "check-".$mysqld->name();
- # Replace dots in name with underscore to avoid that mysqltest
- # misinterpret's what the filename extension is :(
- $name=~ s/\./_/g;
-
- my $args;
- mtr_init_args(\$args);
-
- mtr_add_arg($args, "--defaults-file=%s", $path_config_file);
- mtr_add_arg($args, "--defaults-group-suffix=%s", $mysqld->after('mysqld'));
- mtr_add_arg($args, "--result-file=%s", "$opt_vardir/tmp/$name.result");
- mtr_add_arg($args, "--test-file=%s", "include/check-testcase.test");
- mtr_add_arg($args, "--verbose");
-
- if ( $mode eq "before" )
- {
- mtr_add_arg($args, "--record");
- }
- my $errfile= "$opt_vardir/tmp/$name.err";
- my $proc= My::SafeProcess->new
- (
- name => $name,
- path => $exe_mysqltest,
- error => $errfile,
- output => $errfile,
- args => \$args,
- user_data => $errfile,
- verbose => $opt_verbose,
- );
-
- mtr_report("Started $proc");
- return $proc;
-}
-
-
-sub run_mysqltest ($) {
- my $proc= start_mysqltest(@_);
- $proc->wait();
-}
-
-
-sub start_mysqltest ($) {
- my ($tinfo)= @_;
- my $exe= $exe_mysqltest;
- my $args;
-
- mark_time_used('admin');
-
- mtr_init_args(\$args);
-
- mtr_add_arg($args, "--defaults-file=%s", $path_config_file);
- mtr_add_arg($args, "--silent");
- mtr_add_arg($args, "--tmpdir=%s", $opt_tmpdir);
- mtr_add_arg($args, "--character-sets-dir=%s", $path_charsetsdir);
- mtr_add_arg($args, "--logdir=%s/log", $opt_vardir);
-
- # Log line number and time for each line in .test file
- mtr_add_arg($args, "--mark-progress")
- if $opt_mark_progress;
-
- mtr_add_arg($args, "--database=test");
-
- 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_non_blocking_api )
- {
- mtr_add_arg($args, "--non-blocking-api");
- }
-
- 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_ssl )
- {
- # Turn on SSL for _all_ test cases if option --ssl was used
- mtr_add_arg($args, "--ssl");
- }
-
- if ( $opt_max_connections ) {
- mtr_add_arg($args, "--max-connections=%d", $opt_max_connections);
- }
-
- if ( $opt_embedded_server )
- {
-
- # Get the args needed for the embedded server
- # and append them to args prefixed
- # with --sever-arg=
-
- my $mysqld= $config->group('embedded')
- or mtr_error("Could not get [embedded] section");
-
- my $mysqld_args;
- mtr_init_args(\$mysqld_args);
- my $extra_opts= get_extra_opts($mysqld, $tinfo);
- mysqld_arguments($mysqld_args, $mysqld, $extra_opts);
- mtr_add_arg($args, "--server-arg=%s", $_) for @$mysqld_args;
- }
-
- # ----------------------------------------------------------------------
- # export MYSQL_TEST variable containing <path>/mysqltest <args>
- # ----------------------------------------------------------------------
- $ENV{'MYSQL_TEST'}= mtr_args2str($exe_mysqltest, @$args);
-
- if ($opt_force > 1)
- {
- mtr_add_arg($args, "--continue-on-error");
- }
-
- my $suite = $tinfo->{suite};
- if ($suite->{parent}) {
- mtr_add_arg($args, "--overlay-dir=%s/", $suite->{dir});
- mtr_add_arg($args, "--suite-dir=%s/", $suite->{parent}->{dir});
- } else {
- mtr_add_arg($args, "--suite-dir=%s/", $suite->{dir});
- }
-
- mtr_add_arg($args, "--test-file=%s", $tinfo->{'path'});
-
- # Number of lines of resut to include in failure report
- mtr_add_arg($args, "--tail-lines=%d", $opt_tail_lines);
-
- if ( defined $tinfo->{'result_file'} ) {
- mtr_add_arg($args, "--result-file=%s", $tinfo->{'result_file'});
- }
-
- client_debug_arg($args, "mysqltest");
-
- if ( $opt_record )
- {
- mtr_add_arg($args, "--record");
-
- # When recording to a non existing result file
- # the name of that file is in "record_file"
- if ( defined $tinfo->{'record_file'} ) {
- mtr_add_arg($args, "--result-file=%s", $tinfo->{record_file});
- }
- }
-
- My::Debugger::setup_client_args(\$args, \$exe);
-
- my $proc= My::SafeProcess->new
- (
- name => "mysqltest",
- path => $exe,
- args => \$args,
- append => 1,
- error => $path_current_testlog,
- verbose => $opt_verbose,
- );
- mtr_verbose("Started $proc");
- return $proc;
-}
-
-#
-# Search server logs for valgrind reports printed at mysqld termination
-#
-sub valgrind_exit_reports() {
- my $found_err= 0;
-
- foreach my $log_file (keys %mysqld_logs)
- {
- my @culprits= ();
- my $valgrind_rep= "";
- my $found_report= 0;
- my $err_in_report= 0;
-
- my $LOGF = IO::File->new($log_file)
- or mtr_error("Could not open file '$log_file' for reading: $!");
-
- while ( my $line = <$LOGF> )
- {
- if ($line =~ /^CURRENT_TEST: (.+)$/)
- {
- my $testname= $1;
- # If we have a report, report it if needed and start new list of tests
- if ($found_report)
- {
- if ($err_in_report)
- {
- mtr_print ("Valgrind report from $log_file after tests:\n",
- @culprits);
- mtr_print_line();
- print ("$valgrind_rep\n");
- $found_err= 1;
- $err_in_report= 0;
- }
- # Make ready to collect new report
- @culprits= ();
- $found_report= 0;
- $valgrind_rep= "";
- }
- push (@culprits, $testname);
- next;
- }
- # This line marks the start of a valgrind report
- $found_report= 1 if $line =~ /^==\d+== .* SUMMARY:/;
-
- if ($found_report) {
- $line=~ s/^==\d+== //;
- $valgrind_rep .= $line;
- $err_in_report= 1 if $line =~ /ERROR SUMMARY: [1-9]/;
- $err_in_report= 1 if $line =~ /definitely lost: [1-9]/;
- $err_in_report= 1 if $line =~ /possibly lost: [1-9]/;
- }
- }
-
- $LOGF= undef;
-
- if ($err_in_report) {
- mtr_print ("Valgrind report from $log_file after tests:\n", @culprits);
- mtr_print_line();
- print ("$valgrind_rep\n");
- $found_err= 1;
- }
- }
-
- return $found_err;
-}
-
-#
-# Usage
-#
-sub usage ($) {
- my ($message)= @_;
-
- if ( $message )
- {
- print STDERR "$message\n";
- print STDERR "For full list of options, use $0 --help\n";
- exit;
- }
-
- local $"= ','; # for @DEFAULT_SUITES below
-
- print <<HERE . My::Debugger::help() . <<HERE;
-
-$0 [ OPTIONS ] [ TESTCASE ]
-
-Where test case can be specified as:
-
-testcase[.test] Runs the test case named 'testcase' from all suits
-path-to-testcase
-[suite.]testcase[,combination]
-
-Examples:
-
-alias
-main.alias 'main' is the name of the main test suite
-rpl.rpl_invoked_features,mix,innodb
-suite/rpl/t/rpl.rpl_invoked_features
-
-Options to control what engine/variation to run:
-
- embedded-server Use the embedded server, i.e. no mysqld daemons
- ps-protocol Use the binary protocol between client and server
- cursor-protocol Use the cursor protocol between client and server
- (implies --ps-protocol)
- view-protocol Create a view to execute all non updating queries
- sp-protocol Create a stored procedure to execute all queries
- non-blocking-api Use the non-blocking client API
- compress Use the compressed protocol between client and server
- ssl Use ssl protocol between client and server
- skip-ssl Don't start server with support for ssl connections
- vs-config Visual Studio configuration used to create executables
- (default: MTR_VS_CONFIG environment variable)
- parallel=# How many parallel test should be run
- defaults-file=<config template> Use fixed config template for all
- tests
- defaults-extra-file=<config template> Extra config template to add to
- all generated configs
- combination=<opt> Use at least twice to run tests with specified
- options to mysqld
- dry-run Don't run any tests, print the list of tests
- that were selected for execution
-
-Options to control directories to use
- tmpdir=DIR The directory where temporary files are stored
- (default: ./var/tmp).
- vardir=DIR The directory where files generated from the test run
- is stored (default: ./var). Specifying a ramdisk or
- tmpfs will speed up tests.
- mem[=DIR] Run testsuite in "memory" using tmpfs or ramdisk
- Attempts to use DIR first if specified else
- uses a builtin list of standard locations
- for tmpfs (/run/shm, /dev/shm, /tmp)
- The option can also be set using environment
- variable MTR_MEM=[DIR]
- clean-vardir Clean vardir if tests were successful and if
- running in "memory". Otherwise this option is ignored
- client-bindir=PATH Path to the directory where client binaries are located
- client-libdir=PATH Path to the directory where client libraries are located
-
-
-Options to control what test suites or cases to run
-
- force Continue after a failure. When specified once, a
- failure in a test file will abort this test file, and
- the execution will continue from the next test file.
- When specified twice, execution will continue executing
- the failed test file from the next command.
- do-test=PREFIX or REGEX
- Run test cases which name are prefixed with PREFIX
- or fulfills REGEX
- skip-test=PREFIX or REGEX
- Skip test cases which name are prefixed with PREFIX
- or fulfills REGEX
- start-from=PREFIX Run test cases starting test prefixed with PREFIX where
- prefix may be suite.testname or just testname
- suite[s]=NAME1,..,NAMEN
- Collect tests in suites from the comma separated
- list of suite names.
- The default is: "@DEFAULT_SUITES"
- skip-rpl Skip the replication test cases.
- big-test Also run tests marked as "big". Repeat this option
- twice to run only "big" tests.
- staging-run Run a limited number of tests (no slow tests). Used
- for running staging trees with valgrind.
- enable-disabled Run also tests marked as disabled
- print-testcases Don't run the tests but print details about all the
- selected tests, in the order they would be run.
- skip-test-list=FILE Skip the tests listed in FILE. Each line in the file
- is an entry and should be formatted as:
- <TESTNAME> : <COMMENT>
- force-restart Always restart servers between tests. This makes it
- easier to see from which test warnings may come from.
-
-Options that specify ports
-
- mtr-port-base=# Base for port numbers, ports from this number to
- port-base=# number+9 are reserved. Should be divisible by 10;
- if not it will be rounded down. May be set with
- environment variable MTR_PORT_BASE. If this value is
- set and is not "auto", it overrides build-thread.
- mtr-build-thread=# Specify unique number to calculate port number(s) from.
- build-thread=# Can be set in environment variable MTR_BUILD_THREAD.
- Set MTR_BUILD_THREAD="auto" to automatically aquire
- a build thread id that is unique to current host
- port-group-size=N Reserve groups of TCP ports of size N for each MTR thread
-
-
-Options for test case authoring
-
- record TESTNAME (Re)genereate the result file for TESTNAME
- check-testcases Check testcases for sideeffects
- mark-progress Log line number and elapsed time to <testname>.progress
-
-Options that pass on options (these may be repeated)
-
- mariadbd=ARGS Specify additional arguments to "mariadbd"
- mysqld Alias for mariadbd.
- mariadbd-env=VAR=VAL Specify additional environment settings for "mariadbd"
- mysqld-env Alias for mariadbd-env.
-
-Options to run test on running server
-
- extern option=value Run only the tests against an already started server
- the options to use for connection to the extern server
- must be specified using name-value pair notation
- For example:
- ./$0 --extern socket=/tmp/mysqld.sock
-
-Options for debugging the product
-
- debug Dump trace output for all servers and client programs
- debug-common Same as debug, but sets 'd' debug flags to
- "query,info,error,enter,exit"
- debug-server Use debug version of server, but without turning on
- tracing
- max-save-core Limit the number of core files saved (to avoid filling
- up disks for heavily crashing server). Defaults to
- $opt_max_save_core. Set its default with
- MTR_MAX_SAVE_CORE
- max-save-datadir Limit the number of datadir saved (to avoid filling
- up disks for heavily crashing server). Defaults to
- $opt_max_save_datadir. Set its default with
- MTR_MAX_SAVE_DATADIR
- max-test-fail Limit the number of test failures before aborting
- the current test run. Defaults to
- $opt_max_test_fail, set to 0 for no limit. Set
- it's default with MTR_MAX_TEST_FAIL
- core-in-failure Generate a core even if run server is run with valgrind
-HERE
-
-Misc options
- user=USER User for connecting to mysqld(default: $opt_user)
- comment=STR Write STR to the output
- timer Show test case execution time.
- verbose More verbose output(use multiple times for even more)
- verbose-restart Write when and why servers are restarted
- start Only initialize and start the servers, using the
- startup settings for the first specified test case
- Example:
- $0 --start alias &
- start-and-exit Same as --start, but mysql-test-run terminates and
- leaves just the server running
- start-dirty Only start the servers (without initialization) for
- the first specified test case
- user-args In combination with start* and no test name, drops
- arguments to mariadbd except those specified with
- --mariadbd (if any)
- wait-all If --start or --start-dirty option is used, wait for all
- servers to exit before finishing the process
- fast Run as fast as possible, don't wait for servers
- to shutdown etc.
- force-restart Always restart servers between tests
- parallel=N Run tests in N parallel threads (default 1)
- Use parallel=auto for auto-setting of N
- repeat=N Run each test N number of times
- retry=N Retry tests that fail up to N times (default $opt_retry).
- Retries are also limited by the maximum number of
- failures before stopping, set with the --retry-failure
- option
- retry-failure=N When using the --retry option to retry failed tests,
- stop when N failures have occurred (default $opt_retry_failure)
- reorder Reorder tests to get fewer server restarts
- help Get this help text
-
- testcase-timeout=MINUTES Max test case run time (default $opt_testcase_timeout)
- suite-timeout=MINUTES Max test suite run time (default $opt_suite_timeout)
- shutdown-timeout=SECONDS Max number of seconds to wait for server shutdown
- before killing servers (default $opt_shutdown_timeout)
- warnings Scan the log files for warnings. Use --nowarnings
- to turn off.
-
- stop-file=file (also MTR_STOP_FILE environment variable) if this
- file detected mysql test will not start new tests
- until the file will be removed.
- stop-keep-alive=sec (also MTR_STOP_KEEP_ALIVE environment variable)
- works with stop-file, print messages every sec
- seconds when mysql test is waiting to removing
- the file (for buildbot)
-
- sleep=SECONDS Passed to mysqltest, will be used as fixed sleep time
- debug-sync-timeout=NUM Set default timeout for WAIT_FOR debug sync
- actions. Disable facility with NUM=0.
- gcov Collect coverage information after the test.
- The result is a gcov file per source and header file.
- gprof Collect profiling information using gprof.
- experimental=<file> Refer to list of tests considered experimental;
- failures will be marked exp-fail instead of fail.
- timestamp Print timestamp before each test report line
- timediff With --timestamp, also print time passed since
- *previous* test started
- max-connections=N Max number of open connection to server in mysqltest
- report-times Report how much time has been spent on different
- phases of test execution.
- stress=ARGS Run stress test, providing options to
- mysql-stress-test.pl. Options are separated by comma.
- xml-report=<file> Output jUnit xml file of the results.
- tail-lines=N Number of lines of the result to include in a failure
- report.
-
-Some options that control enabling a feature for normal test runs,
-can be turned off by prepending 'no' to the option, e.g. --notimer.
-This applies to reorder, timer, check-testcases and warnings.
-
-HERE
- exit(1);
-
-}
-
-sub list_options ($) {
- my $hash= shift;
-
- for (keys %$hash) {
- s/([:=].*|[+!])$//;
- s/\|/\n--/g;
- print "--$_\n";
- }
-
- exit(1);
-}