mysql-test-run.pl 166 KB
Newer Older
unknown's avatar
unknown committed
1 2 3 4
#!/usr/bin/perl
# -*- cperl -*-

#
5 6 7
##############################################################################
#
#  mysql-test-run.pl
unknown's avatar
unknown committed
8
#
unknown's avatar
unknown committed
9
#  Tool used for executing a suite of .test files
unknown's avatar
unknown committed
10
#
11 12
#  See the "MySQL Test framework manual" for more information
#  http://dev.mysql.com/doc/mysqltest/en/index.html
unknown's avatar
unknown committed
13 14
#
#
15
##############################################################################
unknown's avatar
unknown committed
16

unknown's avatar
unknown committed
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
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);
  }
}
36

37 38 39 40 41 42 43 44 45 46 47
BEGIN {
  # 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";
48 49
    # 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);
50 51 52 53 54 55 56 57 58 59 60 61
  }
  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);
  }
}
62

unknown's avatar
unknown committed
63
use lib "lib";
unknown's avatar
unknown committed
64 65 66

use Cwd;
use Getopt::Long;
unknown's avatar
unknown committed
67 68 69
use My::File::Path; # Patched version of File::Path
use File::Basename;
use File::Copy;
70
use File::Find;
71
use File::Temp qw/tempdir/;
72
use File::Spec::Functions qw/splitdir rel2abs/;
unknown's avatar
unknown committed
73
use My::Platform;
unknown's avatar
unknown committed
74 75
use My::SafeProcess;
use My::ConfigFactory;
76
use My::Options;
unknown's avatar
unknown committed
77
use My::Find;
78
use My::SysInfo;
79
use My::CoreDump;
unknown's avatar
unknown committed
80
use mtr_cases;
81
use mtr_report;
82
use mtr_match;
83
use mtr_unique;
unknown's avatar
unknown committed
84
use IO::Socket::INET;
85
use IO::Select;
86

unknown's avatar
unknown committed
87 88 89
require "lib/mtr_process.pl";
require "lib/mtr_io.pl";
require "lib/mtr_gcov.pl";
90
require "lib/mtr_gprof.pl";
unknown's avatar
unknown committed
91 92
require "lib/mtr_misc.pl";

unknown's avatar
unknown committed
93
$SIG{INT}= sub { mtr_error("Got ^C signal"); };
unknown's avatar
unknown committed
94

unknown's avatar
unknown committed
95
our $mysql_version_id;
unknown's avatar
unknown committed
96 97
our $glob_mysql_test_dir;
our $basedir;
unknown's avatar
unknown committed
98 99 100

our $path_charsetsdir;
our $path_client_bindir;
101
our $path_client_libdir;
unknown's avatar
unknown committed
102
our $path_language;
unknown's avatar
unknown committed
103

104 105
our $path_current_testlog;
our $path_testlog;
unknown's avatar
unknown committed
106

unknown's avatar
unknown committed
107 108
our $default_vardir;
our $opt_vardir;                # Path to use for var/ dir
109
our $plugindir;
unknown's avatar
unknown committed
110 111
my $path_vardir_trace;          # unix formatted opt_vardir for trace files
my $opt_tmpdir;                 # Path to use for tmp/ dir
Bjorn Munch's avatar
Bjorn Munch committed
112 113 114
my $opt_tmpdir_pid;

END {
115 116
  if ( defined $opt_tmpdir_pid and $opt_tmpdir_pid == $$ )
  {
Bjorn Munch's avatar
Bjorn Munch committed
117 118 119 120 121 122
    # Remove the tempdir this process has created
    mtr_verbose("Removing tmpdir '$opt_tmpdir");
    rmtree($opt_tmpdir);
  }
}

123 124
sub env_or_val($$) { defined $ENV{$_[0]} ? $ENV{$_[0]} : $_[1] }

unknown's avatar
unknown committed
125
my $path_config_file;           # The generated config file, var/my.cnf
unknown's avatar
unknown committed
126

127 128 129 130 131 132
# 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'};

133 134 135
my $DEFAULT_SUITES="main,binlog,federated,rpl,maria,parts,innodb," . 
                   "innodb_plugin,percona,ndb,vcol,oqgraph,sphinx," .
                   "optimizer_unfixed_bugs";
136
my $opt_suites;
137

138
our $opt_verbose= 0;  # Verbose output, enable with --verbose
unknown's avatar
unknown committed
139 140 141
our $exe_mysql;
our $exe_mysqladmin;
our $exe_mysqltest;
142
our $exe_libtool;
unknown's avatar
unknown committed
143

144
our $opt_big_test= 0;
145
our $opt_staging_run= 0;
unknown's avatar
unknown committed
146

147
our @opt_combinations;
148

unknown's avatar
unknown committed
149
our @opt_extra_mysqld_opt;
150
our @opt_extra_mysqltest_opt;
unknown's avatar
unknown committed
151

Magnus Svensson's avatar
Magnus Svensson committed
152 153
my $opt_compress;
my $opt_ssl;
154
my $opt_skip_ssl;
155
our $opt_ssl_supported;
Magnus Svensson's avatar
Magnus Svensson committed
156 157 158 159
my $opt_ps_protocol;
my $opt_sp_protocol;
my $opt_cursor_protocol;
my $opt_view_protocol;
160

unknown's avatar
unknown committed
161
our $opt_debug;
unknown's avatar
unknown committed
162
our @opt_cases;                  # The test cases names in argv
unknown's avatar
unknown committed
163
our $opt_embedded_server;
164

unknown's avatar
unknown committed
165 166 167
# Options used when connecting to an already running server
my %opts_extern;
sub using_extern { return (keys %opts_extern > 0);};
168

unknown's avatar
unknown committed
169
our $opt_fast= 0;
unknown's avatar
unknown committed
170
our $opt_force;
171
our $opt_mem= $ENV{'MTR_MEM'};
unknown's avatar
unknown committed
172 173

our $opt_gcov;
Sergey Petrunya's avatar
Sergey Petrunya committed
174
our $opt_gcov_src_dir;
175 176 177
our $opt_gcov_exe= "gcov";
our $opt_gcov_err= "mysql-test-gcov.msg";
our $opt_gcov_msg= "mysql-test-gcov.err";
unknown's avatar
unknown committed
178

179 180 181
our $opt_gprof;
our %gprof_dirs;

unknown's avatar
unknown committed
182
our $glob_debugger= 0;
unknown's avatar
unknown committed
183 184
our $opt_gdb;
our $opt_client_gdb;
unknown's avatar
unknown committed
185 186
our $opt_ddd;
our $opt_client_ddd;
unknown's avatar
unknown committed
187
our $opt_manual_gdb;
unknown's avatar
unknown committed
188 189
our $opt_manual_ddd;
our $opt_manual_debug;
190 191
our $opt_debugger;
our $opt_client_debugger;
unknown's avatar
unknown committed
192

unknown's avatar
unknown committed
193 194
my $config; # The currently running config
my $current_config_name; # The currently running config file template
unknown's avatar
unknown committed
195

196
our @opt_experimentals;
197
our $experimental_test_cases= [];
198

199
my $baseport;
200
# $opt_build_thread may later be set from $opt_port_base
201
my $opt_build_thread= $ENV{'MTR_BUILD_THREAD'} || "auto";
202
my $opt_port_base= $ENV{'MTR_PORT_BASE'} || "auto";
203
my $build_thread= 0;
204

unknown's avatar
unknown committed
205
my $opt_record;
206
my $opt_report_features;
unknown's avatar
unknown committed
207

208 209
my $opt_skip_core;

210
our $opt_check_testcases= 1;
unknown's avatar
unknown committed
211
my $opt_mark_progress;
212
my $opt_max_connections;
unknown's avatar
unknown committed
213

unknown's avatar
unknown committed
214
my $opt_sleep;
unknown's avatar
unknown committed
215

216
my $opt_testcase_timeout= $ENV{MTR_TESTCASE_TIMEOUT} ||  15; # minutes
unknown's avatar
unknown committed
217
my $opt_suite_timeout   = $ENV{MTR_SUITE_TIMEOUT}    || 360; # minutes
218 219
my $opt_shutdown_timeout= $ENV{MTR_SHUTDOWN_TIMEOUT} ||  10; # seconds
my $opt_start_timeout   = $ENV{MTR_START_TIMEOUT}    || 180; # seconds
unknown's avatar
unknown committed
220

221 222 223
sub testcase_timeout { return $opt_testcase_timeout * 60; };
sub suite_timeout { return $opt_suite_timeout * 60; };
sub check_timeout { return $opt_testcase_timeout * 6; };
unknown's avatar
unknown committed
224

unknown's avatar
unknown committed
225 226
my $opt_start;
my $opt_start_dirty;
227
my $opt_start_exit;
228
my $start_only;
229
my $opt_wait_all;
230
my $opt_user_args;
unknown's avatar
unknown committed
231
my $opt_repeat= 1;
232
my $opt_retry= 1;
233
my $opt_retry_failure= env_or_val(MTR_RETRY_FAILURE => 2);
234
my $opt_reorder= 1;
unknown's avatar
unknown committed
235

unknown's avatar
unknown committed
236
my $opt_strace_client;
unknown's avatar
unknown committed
237

238
our $opt_user = "root";
unknown's avatar
unknown committed
239

240 241 242
my $opt_valgrind= 0;
my @default_valgrind_args= ("--show-reachable=yes");
my @valgrind_args;
243 244 245 246
our $opt_valgrind_mysqld= 0;
my $opt_valgrind_mysqltest= 0;
my $opt_strace= 0;
my @strace_args;
247 248
my $opt_valgrind_path;
my $opt_callgrind;
249
my %mysqld_logs;
250
my $opt_debug_sync_timeout= 300; # Default timeout for WAIT_FOR actions.
unknown's avatar
unknown committed
251

unknown's avatar
unknown committed
252
our $opt_warnings= 1;
unknown's avatar
unknown committed
253

254
our $opt_skip_ndbcluster= 0;
unknown's avatar
unknown committed
255

unknown's avatar
unknown committed
256 257 258
my $exe_ndbd;
my $exe_ndb_mgmd;
my $exe_ndb_waiter;
unknown's avatar
unknown committed
259

unknown's avatar
unknown committed
260
our $debug_compiled_binaries;
261

262 263
our %mysqld_variables;

264 265
our %suites;

266 267
my $source_dist= 0;

268 269 270
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);
unknown's avatar
unknown committed
271

272
my $opt_parallel= $ENV{MTR_PARALLEL} || 1;
273

274 275 276 277 278
# 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};

unknown's avatar
unknown committed
279 280
select(STDOUT);
$| = 1; # Automatically flush STDOUT
unknown's avatar
unknown committed
281 282 283

main();

284

unknown's avatar
unknown committed
285
sub main {
Magnus Svensson's avatar
Magnus Svensson committed
286
  # Default, verbosity on
287
  report_option('verbose', 0);
unknown's avatar
unknown committed
288

289 290 291 292
  # 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));
unknown's avatar
unknown committed
293 294

  command_line_setup();
295

296 297 298
  # --help will not reach here, so now it's safe to assume we have binaries
  My::SafeProcess::find_bin();

299
  if ( $opt_gcov ) {
Sergey Petrunya's avatar
Sergey Petrunya committed
300
    gcov_prepare($basedir . "/" . $opt_gcov_src_dir);
unknown's avatar
unknown committed
301 302
  }

303
  if (!$opt_suites) {
304 305 306 307 308 309 310 311 312 313 314 315 316
    $opt_suites= $DEFAULT_SUITES;

    # Check for any extra suites to enable based on the path name
    my %extra_suites=
      (
       "mysql-5.1-new-ndb"              => "ndb_team",
       "mysql-5.1-new-ndb-merge"        => "ndb_team",
       "mysql-5.1-telco-6.2"            => "ndb_team",
       "mysql-5.1-telco-6.2-merge"      => "ndb_team",
       "mysql-5.1-telco-6.3"            => "ndb_team",
       "mysql-6.0-ndb"                  => "ndb_team",
      );

317
    foreach my $dir ( reverse splitdir($basedir) ) {
318
      my $extra_suite= $extra_suites{$dir};
319
      if (defined $extra_suite) {
320 321 322 323 324 325
	mtr_report("Found extra suite: $extra_suite");
	$opt_suites= "$extra_suite,$opt_suites";
	last;
      }
    }
  }
326

327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
  print "vardir: $opt_vardir\n";
  initialize_servers();

  mtr_report("Checking supported features...");
  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_ndbcluster_support(\%mysqld_variables);
  check_ssl_support(\%mysqld_variables);
  check_debug_support(\%mysqld_variables);

  executable_setup();
346

unknown's avatar
unknown committed
347
  mtr_report("Collecting tests...");
348
  my $tests= collect_test_cases($opt_reorder, $opt_suites, \@opt_cases);
unknown's avatar
unknown committed
349

unknown's avatar
unknown committed
350 351
  if ( $opt_report_features ) {
    # Put "report features" as the first test to run
352 353 354
    my $tinfo = My::Test->new
      (
       name           => 'report_features',
355
       # No result_file => Prints result
Magnus Svensson's avatar
Magnus Svensson committed
356
       path           => 'include/report-features.test',
357
       template_path  => "include/default_my.cnf",
358 359 360
       master_opt     => [],
       slave_opt      => [],
      );
unknown's avatar
unknown committed
361
    unshift(@$tests, $tinfo);
unknown's avatar
unknown committed
362
  }
363

Magnus Svensson's avatar
Magnus Svensson committed
364 365
  #######################################################################
  my $num_tests= @$tests;
366
  if ( $opt_parallel eq "auto" ) {
Magnus Svensson's avatar
Magnus Svensson committed
367 368 369 370 371 372 373
    # Try to find a suitable value for number of workers
    my $sys_info= My::SysInfo->new();

    $opt_parallel= $sys_info->num_cpus();
    for my $limit (2000, 1500, 1000, 500){
      $opt_parallel-- if ($sys_info->min_bogomips() < $limit);
    }
374 375
    my $max_par= $ENV{MTR_MAX_PARALLEL} || 8;
    $opt_parallel= $max_par if ($opt_parallel > $max_par);
Magnus Svensson's avatar
Magnus Svensson committed
376
    $opt_parallel= $num_tests if ($opt_parallel > $num_tests);
377
    $opt_parallel= 1 if (IS_WINDOWS and $sys_info->isvm());
Magnus Svensson's avatar
Magnus Svensson committed
378 379 380 381
    $opt_parallel= 1 if ($opt_parallel < 1);
    mtr_report("Using parallel: $opt_parallel");
  }

382 383 384 385 386 387
  if ($opt_parallel > 1 && $opt_start_exit) {
    mtr_warning("Parallel and --start-and-exit cannot be combined\n" .
               "Setting parallel to 1");
    $opt_parallel= 1;
  }

Magnus Svensson's avatar
Magnus Svensson committed
388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411
  # 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();
  mtr_report("Using server port $server_port");

  # 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";
      }
412

Magnus Svensson's avatar
Magnus Svensson committed
413 414 415
      run_worker($server_port, $child_num);
      exit(1);
    }
unknown's avatar
unknown committed
416

Magnus Svensson's avatar
Magnus Svensson committed
417
    $children{$child_pid}= 1;
unknown's avatar
unknown committed
418
  }
Magnus Svensson's avatar
Magnus Svensson committed
419 420
  #######################################################################

421 422 423 424
  mtr_report();
  mtr_print_thick_line();
  mtr_print_header();

unknown's avatar
unknown committed
425
  my ($prefix, $fail, $completed, $extra_warnings)=
426
    run_test_server($server, $tests, $opt_parallel);
unknown's avatar
unknown committed
427

428 429
  exit(0) if $opt_start_exit;

430 431 432 433 434
  # Send Ctrl-C to any children still running
  kill("INT", keys(%children));

  # Wait for childs to exit
  foreach my $pid (keys %children)
unknown's avatar
unknown committed
435
  {
436 437 438 439 440 441 442
    my $ret_pid= waitpid($pid, 0);
    if ($ret_pid != $pid){
      mtr_report("Unknown process $ret_pid exited");
    }
    else {
      delete $children{$ret_pid};
    }
unknown's avatar
unknown committed
443 444
  }

unknown's avatar
unknown committed
445 446
  if ( not defined @$completed ) {
    mtr_error("Test suite aborted");
unknown's avatar
unknown committed
447
  }
unknown's avatar
unknown committed
448

449
  if ( @$completed != $num_tests){
450

451 452
    if ($opt_force){
      # All test should have been run, print any that are still in $tests
453 454 455
      #foreach my $test ( @$tests ){
      #  $test->print_test();
      #}
456
    }
457

458
    # Not all tests completed, failure
459
    mtr_report();
460
    mtr_report("Only ", int(@$completed), " of $num_tests completed.");
461
  }
462

463 464
  mtr_print_line();

Magnus Svensson's avatar
Magnus Svensson committed
465
  if ( $opt_gcov ) {
Sergey Petrunya's avatar
Sergey Petrunya committed
466
    gcov_collect($basedir . "/" . $opt_gcov_src_dir, $opt_gcov_exe,
Magnus Svensson's avatar
Magnus Svensson committed
467 468 469
		 $opt_gcov_msg, $opt_gcov_err);
  }

unknown's avatar
unknown committed
470
  mtr_report_stats($prefix, $fail, $completed, $extra_warnings);
471

472 473 474 475
  if ( @$completed != $num_tests)
  {
    mtr_error("Not all tests completed");
  }
476 477 478 479
  exit(0);
}


Magnus Svensson's avatar
Magnus Svensson committed
480
sub run_test_server ($$$) {
481 482
  my ($server, $tests, $childs) = @_;

483 484
  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.
485
  my $num_failed_test= 0; # Number of tests failed so far
486 487
  my $test_failure= 0;    # Set true if test suite failed
  my $extra_warnings= []; # Warnings found during server shutdowns
488

489
  # Scheduler variables
Magnus Svensson's avatar
Magnus Svensson committed
490
  my $max_ndb= $childs / 2;
491 492 493 494 495 496 497
  $max_ndb = 4 if $max_ndb > 4;
  $max_ndb = 1 if $max_ndb < 1;
  my $num_ndb_tests= 0;

  my $completed= [];
  my %running;
  my $result;
498
  my $exe_mysqld= find_mysqld($basedir) || ""; # Used as hint to CoreDump
499

500
  my $suite_timeout= start_timer(suite_timeout());
unknown's avatar
unknown committed
501

502 503 504
  my $s= IO::Select->new();
  $s->add($server);
  while (1) {
505 506 507 508 509
    if ($opt_stop_file)
    {
      if (mtr_wait_lock_file($opt_stop_file, $opt_stop_keep_alive))
      {
        # We were waiting so restart timer process
unknown's avatar
unknown committed
510
        my $suite_timeout= start_timer(suite_timeout());
511 512
      }
    }
513 514 515 516 517 518 519 520
    my @ready = $s->can_read(1); # Wake up once every second
    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";
521
      }
522 523 524 525 526 527 528
      else {
	my $line= <$sock>;
	if (!defined $line) {
	  # Client disconnected
	  mtr_verbose("Child closed socket");
	  $s->remove($sock);
	  if (--$childs == 0){
unknown's avatar
unknown committed
529
	    return ("Completed", $test_failure, $completed, $extra_warnings);
530 531 532 533 534 535 536 537 538 539 540 541
	  }
	  next;
	}
	chomp($line);

	if ($line eq 'TESTRESULT'){
	  $result= My::Test::read_test($sock);
	  # $result->print_test();

	  # Report test status
	  mtr_report_test($result);

542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557
	  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";

	    if ($opt_max_save_datadir > 0 &&
		$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);
558
	      # Move any core files from e.g. mysqltest
Magnus Svensson's avatar
Magnus Svensson committed
559
	      foreach my $coref (glob("core*"), glob("*.dmp"))
560
	      {
Magnus Svensson's avatar
Magnus Svensson committed
561
		mtr_report(" - found '$coref', moving it to '$savedir'");
562 563
                move($coref, $savedir);
              }
564 565 566 567 568 569
	      if ($opt_max_save_core > 0) {
		# Limit number of core files saved
		find({ no_chdir => 1,
		       wanted => sub {
			 my $core_file= $File::Find::name;
			 my $core_name= basename($core_file);
570

Magnus Svensson's avatar
Magnus Svensson committed
571 572 573
			 if ($core_name =~ /^core/ or  # Starting with core
			     (IS_WINDOWS and $core_name =~ /\.dmp$/)){
                                                       # Ending with .dmp
574
			   mtr_report(" - found '$core_name'",
575
				      "($num_saved_cores/$opt_max_save_core)");
576

577
			   My::CoreDump->show($core_file, $exe_mysqld);
578 579 580 581

			   if ($num_saved_cores >= $opt_max_save_core) {
			     mtr_report(" - deleting it, already saved",
					"$opt_max_save_core");
582 583 584
			     unlink("$core_file");
			   }
			   ++$num_saved_cores;
585 586
			 }
		       }
587 588 589
		     },
		     $savedir);
	      }
590
	    }
591
	    $num_saved_datadir++;
592 593
	    $num_failed_test++ unless ($result->{retries} ||
                                       $result->{exp_fail});
594

595
            $test_failure= 1;
596 597 598
	    if ( !$opt_force ) {
	      # Test has failed, force is off
	      push(@$completed, $result);
unknown's avatar
unknown committed
599
	      return ("Failure", 1, $completed, $extra_warnings);
600
	    }
601
	    elsif ($opt_max_test_fail > 0 and
602
		   $num_failed_test >= $opt_max_test_fail) {
603
	      push(@$completed, $result);
604 605
	      mtr_report("Too many tests($num_failed_test) failed!",
			 "Terminating...");
unknown's avatar
unknown committed
606
	      return ("Too many failed", 1, $completed, $extra_warnings);
607
	    }
608
	  }
609

610
	  # Retry test run after test failure
unknown's avatar
unknown committed
611
	  my $retries= $result->{retries} || 2;
612
	  my $test_has_failed= $result->{failures} || 0;
unknown's avatar
unknown committed
613
	  if ($test_has_failed and $retries <= $opt_retry){
614 615 616 617
	    # Test should be run one more time unless it has failed
	    # too many times already
	    my $failures= $result->{failures};
	    if ($opt_retry > 1 and $failures >= $opt_retry_failure){
unknown's avatar
unknown committed
618
	      mtr_report("\nTest has failed $failures times,",
619 620 621 622
			 "no more retries!\n");
	    }
	    else {
	      mtr_report("\nRetrying test, attempt($retries/$opt_retry)...\n");
623
	      delete($result->{result});
624 625 626 627 628
	      $result->{retries}= $retries+1;
	      $result->write_test($sock, 'TESTCASE');
	      next;
	    }
	  }
629

630 631
	  # Repeat test $opt_repeat number of times
	  my $repeat= $result->{repeat} || 1;
632 633
	  # Don't repeat if test was skipped
	  if ($repeat < $opt_repeat && $result->{'result'} ne 'MTR_RES_SKIPPED')
634 635
	  {
	    $result->{retries}= 0;
636
	    $result->{rep_failures}++ if $result->{failures};
637
	    $result->{failures}= 0;
638
	    delete($result->{result});
639 640 641 642
	    $result->{repeat}= $repeat+1;
	    $result->write_test($sock, 'TESTCASE');
	    next;
	  }
643

644 645 646 647 648 649 650 651 652 653 654 655 656 657
	  # Remove from list of running
	  mtr_error("'", $result->{name},"' is not known to be running")
	    unless delete $running{$result->key()};

	  # Update scheduler variables
	  $num_ndb_tests-- if ($result->{ndb_test});

	  # Save result in completed list
	  push(@$completed, $result);

	}
	elsif ($line eq 'START'){
	  ; # Send first test
	}
658 659 660
	elsif ($line eq 'WARNINGS'){
          my $fake_test= My::Test::read_test($sock);
          my $test_list= join (" ", @{$fake_test->{testnames}});
661
          push @$extra_warnings, $test_list;
662
          my $report= $fake_test->{'warnings'};
663
          mtr_report("***Warnings generated in error logs during shutdown ".
664
                     "after running tests: $test_list\n\n$report");
665 666 667
          $test_failure= 1;
          if ( !$opt_force ) {
            # Test failure due to warnings, force is off
unknown's avatar
unknown committed
668
            return ("Warnings in log", 1, $completed, $extra_warnings);
669 670
          }
        } else {
671 672 673 674 675 676 677 678 679
	  mtr_error("Unknown response: '$line' from client");
	}

	# Find next test to schedule
	# - Try to use same configuration as worker used last time
	# - Limit number of parallel ndb tests

	my $next;
	my $second_best;
680
	for(my $i= 0; $i <= @$tests; $i++)
681 682 683
	{
	  my $t= $tests->[$i];

684 685
	  last unless defined $t;

686 687 688 689
	  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));
690 691 692 693

	    # Since the test at pos $i was taken away, next
	    # test will also be at $i -> redo
	    redo;
694 695 696 697 698 699 700 701
	  }

	  # Limit number of parallell NDB tests
	  if ($t->{ndb_test} and $num_ndb_tests >= $max_ndb){
	    #mtr_report("Skipping, num ndb is already at max, $num_ndb_tests");
	    next;
	  }

702 703 704
	  # Prefer same configuration, or just use next if --noreorder
	  if (!$opt_reorder or (defined $result and
	      $result->{template_path} eq $t->{template_path}))
705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722
	  {
	    #mtr_report("Test uses same config => good match");
	    # Test uses same config => good match
	    $next= splice(@$tests, $i, 1);
	    last;
	  }

	  # Second best choice is the first that does not fulfill
	  # any of the above conditions
	  if (!defined $second_best){
	    #mtr_report("Setting second_best to $i");
	    $second_best= $i;
	  }
	}

	# 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");
723
	  mtr_error("Internal error, second best too large($second_best)")
724 725
	    if $second_best >  $#$tests;
	  $next= splice(@$tests, $second_best, 1);
unknown's avatar
unknown committed
726
	}
727

728 729
        xterm_stat(scalar(@$tests));

730 731 732 733 734 735 736 737 738 739
	if ($next) {
	  #$next->print_test();
	  $next->write_test($sock, 'TESTCASE');
	  $running{$next->key()}= $next;
	  $num_ndb_tests++ if ($next->{ndb_test});
	}
	else {
	  # No more test, tell child to exit
	  #mtr_report("Saying BYE to child");
	  print $sock "BYE\n";
unknown's avatar
unknown committed
740
	}
741
      }
742 743
    }

unknown's avatar
unknown committed
744 745 746
    # ----------------------------------------------------
    # Check if test suite timer expired
    # ----------------------------------------------------
747
    if ( has_expired($suite_timeout) )
748
    {
unknown's avatar
unknown committed
749
      mtr_report("Test suite timeout! Terminating...");
unknown's avatar
unknown committed
750
      return ("Timeout", 1, $completed, $extra_warnings);
751
    }
752 753
  }
}
unknown's avatar
unknown committed
754

unknown's avatar
unknown committed
755

756 757
sub run_worker ($) {
  my ($server_port, $thread_num)= @_;
unknown's avatar
unknown committed
758

759
  $SIG{INT}= sub { exit(1); };
unknown's avatar
unknown committed
760

761 762 763 764 765 766 767 768 769
  # 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;
unknown's avatar
unknown committed
770

Magnus Svensson's avatar
Magnus Svensson committed
771 772 773
  # --------------------------------------------------------------------------
  # Set worker name
  # --------------------------------------------------------------------------
774
  report_option('name',"worker[$thread_num]");
775

Magnus Svensson's avatar
Magnus Svensson committed
776
  # --------------------------------------------------------------------------
777
  # Set different ports per thread
Magnus Svensson's avatar
Magnus Svensson committed
778
  # --------------------------------------------------------------------------
779
  set_build_thread_ports($thread_num);
unknown's avatar
unknown committed
780

Magnus Svensson's avatar
Magnus Svensson committed
781 782 783 784
  # --------------------------------------------------------------------------
  # Turn off verbosity in workers, unless explicitly specified
  # --------------------------------------------------------------------------
  report_option('verbose', undef) if ($opt_verbose == 0);
unknown's avatar
unknown committed
785

Magnus Svensson's avatar
Magnus Svensson committed
786
  environment_setup();
787

788 789 790
  # Read hello from server which it will send when shared
  # resources have been setup
  my $hello= <$server>;
791

792
  setup_vardir();
793
  check_running_as_root();
794

unknown's avatar
unknown committed
795 796 797
  if ( using_extern() ) {
    create_config_file_for_extern(%opts_extern);
  }
unknown's avatar
unknown committed
798

799 800
  # Ask server for first test
  print $server "START\n";
unknown's avatar
unknown committed
801

802 803 804 805 806
  while(my $line= <$server>){
    chomp($line);
    if ($line eq 'TESTCASE'){
      my $test= My::Test::read_test($server);
      #$test->print_test();
unknown's avatar
unknown committed
807

Magnus Svensson's avatar
Magnus Svensson committed
808 809 810 811
      # Clear comment and logfile, to avoid
      # reusing them from previous test
      delete($test->{'comment'});
      delete($test->{'logfile'});
812

813 814
      $test->{worker} = $thread_num if $opt_parallel > 1;

815
      run_testcase($test, $server);
816 817 818 819 820 821 822
      #$test->{result}= 'MTR_RES_PASSED';
      # Send it back, now with results set
      #$test->print_test();
      $test->write_test($server, 'TESTRESULT');
    }
    elsif ($line eq 'BYE'){
      mtr_report("Server said BYE");
823 824 825
      # We need to gracefully shut down the servers to see any
      # Valgrind memory leak errors etc. since last server restart.
      if ($opt_warnings) {
826
        stop_servers(reverse all_servers());
827 828 829 830 831
        if(check_warnings_post_shutdown($server)) {
          # Warnings appeared in log file(s) during final server shutdown.
          exit(1);
        }
      }
unknown's avatar
unknown committed
832 833
      else {
        stop_all_servers($opt_shutdown_timeout);
834
      }
835 836 837
      if ( $opt_gprof ) {
	gprof_collect (find_mysqld($basedir), keys %gprof_dirs);
      }
838 839 840 841
      exit(0);
    }
    else {
      mtr_error("Could not understand server, '$line'");
842 843
    }
  }
unknown's avatar
unknown committed
844

845 846 847
  stop_all_servers();

  exit(1);
unknown's avatar
unknown committed
848
}
849

unknown's avatar
unknown committed
850

unknown's avatar
unknown committed
851 852
sub ignore_option {
  my ($opt, $value)= @_;
853
  mtr_report("Ignoring option '$opt'");
unknown's avatar
unknown committed
854
}
855

856

Magnus Svensson's avatar
Magnus Svensson committed
857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875

# Setup any paths that are $opt_vardir related
sub set_vardir {
  my ($vardir)= @_;

  $opt_vardir= $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";

}

876

Magnus Svensson's avatar
Magnus Svensson committed
877
sub command_line_setup {
unknown's avatar
unknown committed
878
  my $opt_comment;
unknown's avatar
unknown committed
879
  my $opt_usage;
Michael Widenius's avatar
Michael Widenius committed
880
  my $opt_list_options;
unknown's avatar
unknown committed
881

unknown's avatar
unknown committed
882
  # Read the command line options
unknown's avatar
unknown committed
883
  # Note: Keep list, and the order, in sync with usage at end of this file
unknown's avatar
unknown committed
884
  Getopt::Long::Configure("pass_through");
885
  my %options=(
unknown's avatar
unknown committed
886
             # Control what engine/variation to run
unknown's avatar
unknown committed
887
             'embedded-server'          => \$opt_embedded_server,
unknown's avatar
unknown committed
888
             'ps-protocol'              => \$opt_ps_protocol,
889 890 891
             'sp-protocol'              => \$opt_sp_protocol,
             'view-protocol'            => \$opt_view_protocol,
             'cursor-protocol'          => \$opt_cursor_protocol,
unknown's avatar
unknown committed
892
             'ssl|with-openssl'         => \$opt_ssl,
893 894
             'skip-ssl'                 => \$opt_skip_ssl,
             'compress'                 => \$opt_compress,
895
             'vs-config=s'              => \$opt_vs_config,
unknown's avatar
unknown committed
896

897
	     # Max number of parallel threads to use
898
	     'parallel=s'               => \$opt_parallel,
899

unknown's avatar
unknown committed
900 901 902 903
             # 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,
unknown's avatar
unknown committed
904 905

             # Control what test suites or cases to run
unknown's avatar
unknown committed
906
             'force'                    => \$opt_force,
unknown's avatar
unknown committed
907
             'with-ndbcluster-only'     => \&collect_option,
unknown's avatar
unknown committed
908
             'skip-ndbcluster|skip-ndb' => \$opt_skip_ndbcluster,
909
             'suite|suites=s'           => \$opt_suites,
unknown's avatar
unknown committed
910 911 912 913
             'skip-rpl'                 => \&collect_option,
             'skip-test=s'              => \&collect_option,
             'do-test=s'                => \&collect_option,
             'start-from=s'             => \&collect_option,
914
             'big-test'                 => \$opt_big_test,
unknown's avatar
unknown committed
915
	     'combination=s'            => \@opt_combinations,
unknown's avatar
unknown committed
916
             'skip-combinations'        => \&collect_option,
917
             'experimental=s'           => \@opt_experimentals,
unknown's avatar
unknown committed
918
	     'skip-im'                  => \&ignore_option,
919
             'staging-run'              => \$opt_staging_run,
unknown's avatar
unknown committed
920 921

             # Specify ports
922
	     'build-thread|mtr-build-thread=i' => \$opt_build_thread,
923
	     'port-base|mtr-port-base=i'       => \$opt_port_base,
unknown's avatar
unknown committed
924 925 926

             # Test case authoring
             'record'                   => \$opt_record,
927
             'check-testcases!'         => \$opt_check_testcases,
928
             'mark-progress'            => \$opt_mark_progress,
unknown's avatar
unknown committed
929

930
             # Extra options used when starting mysqld
unknown's avatar
unknown committed
931
             'mysqld=s'                 => \@opt_extra_mysqld_opt,
unknown's avatar
unknown committed
932

933 934
             # Extra options used when starting mysqltest
             'mysqltest=s'              => \@opt_extra_mysqltest_opt,
935

unknown's avatar
unknown committed
936
             # Run test on running server
unknown's avatar
unknown committed
937
             'extern=s'                  => \%opts_extern, # Append to hash
unknown's avatar
unknown committed
938 939

             # Debugging
unknown's avatar
unknown committed
940
             'debug'                    => \$opt_debug,
unknown's avatar
unknown committed
941
             'gdb'                      => \$opt_gdb,
unknown's avatar
unknown committed
942
             'client-gdb'               => \$opt_client_gdb,
unknown's avatar
unknown committed
943 944
             'manual-gdb'               => \$opt_manual_gdb,
             'manual-debug'             => \$opt_manual_debug,
unknown's avatar
unknown committed
945
             'ddd'                      => \$opt_ddd,
unknown's avatar
unknown committed
946
             'client-ddd'               => \$opt_client_ddd,
unknown's avatar
unknown committed
947
             'manual-ddd'               => \$opt_manual_ddd,
948 949
	     'debugger=s'               => \$opt_debugger,
	     'client-debugger=s'        => \$opt_client_debugger,
950
             'strace'			=> \$opt_strace,
unknown's avatar
unknown committed
951
             'strace-client:s'          => \$opt_strace_client,
952
             'strace-option=s'          => \@strace_args,
953
             'max-save-core=i'          => \$opt_max_save_core,
954
             'max-save-datadir=i'       => \$opt_max_save_datadir,
955
             'max-test-fail=i'          => \$opt_max_test_fail,
unknown's avatar
unknown committed
956 957 958

             # Coverage, profiling etc
             'gcov'                     => \$opt_gcov,
Sergey Petrunya's avatar
Sergey Petrunya committed
959
             'gcov-src-dir=s'           => \$opt_gcov_src_dir,
960
             'gprof'                    => \$opt_gprof,
961
             'valgrind|valgrind-all'    => \$opt_valgrind,
unknown's avatar
unknown committed
962 963
             'valgrind-mysqltest'       => \$opt_valgrind_mysqltest,
             'valgrind-mysqld'          => \$opt_valgrind_mysqld,
964 965 966 967 968 969 970 971 972 973 974 975
             'valgrind-options=s'       => sub {
	       my ($opt, $value)= @_;
	       # Deprecated option unless it's what we know pushbuild uses
	       if ($value eq "--gen-suppressions=all --show-reachable=yes") {
		 push(@valgrind_args, $_) for (split(' ', $value));
		 return;
	       }
	       die("--valgrind-options=s is deprecated. Use ",
		   "--valgrind-option=s, to be specified several",
		   " times if necessary");
	     },
             'valgrind-option=s'        => \@valgrind_args,
unknown's avatar
unknown committed
976
             'valgrind-path=s'          => \$opt_valgrind_path,
977
	     'callgrind'                => \$opt_callgrind,
978
	     'debug-sync-timeout=i'     => \$opt_debug_sync_timeout,
unknown's avatar
unknown committed
979

980 981 982
	     # Directories
             'tmpdir=s'                 => \$opt_tmpdir,
             'vardir=s'                 => \$opt_vardir,
983
             'mem'                      => \$opt_mem,
984 985
             'client-bindir=s'          => \$path_client_bindir,
             'client-libdir=s'          => \$path_client_libdir,
986

unknown's avatar
unknown committed
987
             # Misc
988
             'report-features'          => \$opt_report_features,
unknown's avatar
unknown committed
989
             'comment=s'                => \$opt_comment,
unknown's avatar
unknown committed
990
             'fast'                     => \$opt_fast,
991
             'reorder!'                 => \$opt_reorder,
unknown's avatar
unknown committed
992 993
             'enable-disabled'          => \&collect_option,
             'verbose+'                 => \$opt_verbose,
994
             'verbose-restart'          => \&report_option,
unknown's avatar
unknown committed
995
             'sleep=i'                  => \$opt_sleep,
996
             'start-dirty'              => \$opt_start_dirty,
997
             'start-and-exit'           => \$opt_start_exit,
unknown's avatar
unknown committed
998
             'start'                    => \$opt_start,
999
	     'user-args'                => \$opt_user_args,
1000
             'wait-all'                 => \$opt_wait_all,
unknown's avatar
unknown committed
1001
	     'print-testcases'          => \&collect_option,
unknown's avatar
unknown committed
1002 1003 1004
	     'repeat=i'                 => \$opt_repeat,
	     'retry=i'                  => \$opt_retry,
	     'retry-failure=i'          => \$opt_retry_failure,
unknown's avatar
unknown committed
1005
             'timer!'                   => \&report_option,
unknown's avatar
unknown committed
1006
             'user=s'                   => \$opt_user,
1007 1008
             'testcase-timeout=i'       => \$opt_testcase_timeout,
             'suite-timeout=i'          => \$opt_suite_timeout,
unknown's avatar
unknown committed
1009 1010
             'shutdown-timeout=i'       => \$opt_shutdown_timeout,
             'warnings!'                => \$opt_warnings,
1011
	     'timestamp'                => \&report_option,
unknown's avatar
unknown committed
1012
	     'timediff'                 => \&report_option,
1013 1014
             'stop-file=s'              => \$opt_stop_file,
             'stop-keep-alive=i'        => \$opt_stop_keep_alive,
1015
	     'max-connections=i'        => \$opt_max_connections,
1016

unknown's avatar
unknown committed
1017
             'help|h'                   => \$opt_usage,
1018 1019 1020 1021
             'list-options'             => \$opt_list_options,
            );

  GetOptions(%options) or usage("Can't read options");
unknown's avatar
unknown committed
1022
  usage("") if $opt_usage;
1023
  list_options(\%options) if $opt_list_options;
unknown's avatar
unknown committed
1024

unknown's avatar
unknown committed
1025
  # --------------------------------------------------------------------------
1026
  # Setup verbosity
unknown's avatar
unknown committed
1027
  # --------------------------------------------------------------------------
1028 1029
  if ($opt_verbose != 0){
    report_option('verbose', $opt_verbose);
1030 1031 1032 1033
  }

  if ( -d "../sql" )
  {
1034
    $source_dist=  1;
1035 1036
  }

1037
  # Find the absolute path to the test directory
unknown's avatar
unknown committed
1038
  $glob_mysql_test_dir= cwd();
1039 1040 1041 1042 1043
  if ($glob_mysql_test_dir =~ / /)
  {
    die("Working directory \"$glob_mysql_test_dir\" contains space\n".
	"Bailing out, cannot function properly with space in path");
  }
unknown's avatar
unknown committed
1044
  if (IS_CYGWIN)
unknown's avatar
unknown committed
1045
  {
unknown's avatar
unknown committed
1046 1047
    # Use mixed path format i.e c:/path/to/
    $glob_mysql_test_dir= mixed_path($glob_mysql_test_dir);
unknown's avatar
unknown committed
1048
  }
1049 1050 1051 1052

  # 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.
unknown's avatar
unknown committed
1053
  $basedir= dirname($glob_mysql_test_dir);
1054 1055 1056 1057 1058 1059

  # 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.
unknown's avatar
unknown committed
1060
  if ( ! $source_dist and ! -d "$basedir/bin" )
1061
  {
unknown's avatar
unknown committed
1062
    $basedir= dirname($basedir);
1063
  }
1064 1065 1066 1067 1068 1069
  # 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);
  }
1070

1071 1072
  fix_vs_config_dir();

1073
  # Look for the client binaries directory
1074 1075 1076 1077 1078 1079 1080
  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
  {
unknown's avatar
unknown committed
1081 1082
    $path_client_bindir= mtr_path_exists("$basedir/client_release",
					 "$basedir/client_debug",
1083
					 "$basedir/client$opt_vs_config",
unknown's avatar
unknown committed
1084 1085
					 "$basedir/client",
					 "$basedir/bin");
1086
  }
1087

unknown's avatar
unknown committed
1088
  # Look for language files and charsetsdir, use same share
1089 1090
  $path_language=   mtr_path_exists("$basedir/share/mariadb/english",
                                    "$basedir/share/mysql/english",
1091 1092
                                    "$basedir/sql/share/english",
                                    "$basedir/share/english");
unknown's avatar
unknown committed
1093

1094
  my $path_share= dirname($path_language);
unknown's avatar
unknown committed
1095 1096
  $path_charsetsdir=   mtr_path_exists("$path_share/charsets");

unknown's avatar
unknown committed
1097
  if ( $opt_comment )
unknown's avatar
unknown committed
1098
  {
unknown's avatar
unknown committed
1099 1100 1101 1102
    mtr_report();
    mtr_print_thick_line('#');
    mtr_report("# $opt_comment");
    mtr_print_thick_line('#');
unknown's avatar
unknown committed
1103
  }
unknown's avatar
unknown committed
1104

1105
  if ( @opt_experimentals )
1106
  {
1107 1108 1109
    # $^O on Windows considered not generic enough
    my $plat= (IS_WINDOWS) ? 'windows' : $^O;

1110
    # read the list of experimental test cases from the files specified on
Daniel Fischer's avatar
Daniel Fischer committed
1111 1112
    # the command line
    $experimental_test_cases = [];
1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142
    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/( +|^)#.*$//;
	# 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/ +$//;
	# 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, $_;
1143
      }
1144
      close FILE;
1145
    }
1146 1147
  }

unknown's avatar
unknown committed
1148 1149 1150 1151 1152 1153
  foreach my $arg ( @ARGV )
  {
    if ( $arg =~ /^--skip-/ )
    {
      push(@opt_extra_mysqld_opt, $arg);
    }
1154 1155 1156 1157 1158 1159
    elsif ( $arg =~ /^--$/ )
    {
      # It is an effect of setting 'pass_through' in option processing
      # that the lone '--' separating options from arguments survives,
      # simply ignore it.
    }
unknown's avatar
unknown committed
1160 1161 1162 1163 1164 1165 1166 1167 1168
    elsif ( $arg =~ /^-/ )
    {
      usage("Invalid option \"$arg\"");
    }
    else
    {
      push(@opt_cases, $arg);
    }
  }
unknown's avatar
unknown committed
1169

Michael Widenius's avatar
Michael Widenius committed
1170 1171 1172 1173 1174 1175
  if ( @opt_cases )
  {
    # Run big tests if explicitely specified on command line
    $opt_big_test= 1;
  }

1176 1177 1178
  # --------------------------------------------------------------------------
  # Find out type of logging that are being used
  # --------------------------------------------------------------------------
unknown's avatar
unknown committed
1179
  foreach my $arg ( @opt_extra_mysqld_opt )
1180
  {
unknown's avatar
unknown committed
1181
    if ( $arg =~ /binlog[-_]format=(\S+)/ )
1182
    {
unknown's avatar
unknown committed
1183 1184 1185
      # Save this for collect phase
      collect_option('binlog-format', $1);
      mtr_report("Using binlog format '$1'");
1186
    }
1187 1188
  }

1189 1190 1191 1192 1193 1194 1195 1196

  # --------------------------------------------------------------------------
  # Find out default storage engine being used(if any)
  # --------------------------------------------------------------------------
  foreach my $arg ( @opt_extra_mysqld_opt )
  {
    if ( $arg =~ /default-storage-engine=(\S+)/ )
    {
unknown's avatar
unknown committed
1197 1198 1199
      # Save this for collect phase
      collect_option('default-storage-engine', $1);
      mtr_report("Using default engine '$1'")
1200 1201 1202
    }
  }

1203 1204 1205 1206 1207
  if (IS_WINDOWS and defined $opt_mem) {
    mtr_report("--mem not supported on Windows, ignored");
    $opt_mem= undef;
  }

1208 1209 1210 1211 1212 1213 1214 1215 1216 1217
  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;
  }

1218
  # --------------------------------------------------------------------------
1219
  # Check if we should speed up tests by trying to run on tmpfs
1220
  # --------------------------------------------------------------------------
Magnus Svensson's avatar
Magnus Svensson committed
1221
  if ( defined $opt_mem)
1222 1223 1224 1225 1226 1227
  {
    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;

1228
    # Search through list of locations that are known
1229
    # to be "fast disks" to find a suitable location
1230 1231 1232
    # Use --mem=<dir> as first location to look.
    my @tmpfs_locations= ($opt_mem, "/dev/shm", "/tmp");

1233 1234 1235 1236
    foreach my $fs (@tmpfs_locations)
    {
      if ( -d $fs )
      {
1237
	my $template= "var_${opt_build_thread}_XXXX";
1238
	$opt_mem= tempdir( $template, DIR => $fs, CLEANUP => 0);
1239 1240 1241 1242
	last;
      }
    }
  }
1243

1244
  # --------------------------------------------------------------------------
Magnus Svensson's avatar
Magnus Svensson committed
1245
  # Set the "var/" directory, the base for everything else
1246
  # --------------------------------------------------------------------------
unknown's avatar
unknown committed
1247
  $default_vardir= "$glob_mysql_test_dir/var";
1248 1249
  if ( ! $opt_vardir )
  {
1250
    $opt_vardir= $default_vardir;
1251
  }
unknown's avatar
unknown committed
1252

unknown's avatar
unknown committed
1253 1254
  # We make the path absolute, as the server will do a chdir() before usage
  unless ( $opt_vardir =~ m,^/, or
unknown's avatar
unknown committed
1255
           (IS_WINDOWS and $opt_vardir =~ m,^[a-z]:/,i) )
1256 1257 1258 1259
  {
    # Make absolute path, relative test dir
    $opt_vardir= "$glob_mysql_test_dir/$opt_vardir";
  }
unknown's avatar
unknown committed
1260

Magnus Svensson's avatar
Magnus Svensson committed
1261
  set_vardir($opt_vardir);
unknown's avatar
unknown committed
1262

1263
  # --------------------------------------------------------------------------
Magnus Svensson's avatar
Magnus Svensson committed
1264
  # Set the "tmp" directory
1265
  # --------------------------------------------------------------------------
1266 1267 1268 1269
  if ( ! $opt_tmpdir )
  {
    $opt_tmpdir=       "$opt_vardir/tmp" unless $opt_tmpdir;

1270
    if (check_socket_path_length("$opt_tmpdir/mysql_testsocket.sock"))
1271 1272 1273 1274 1275
    {
      mtr_report("Too long tmpdir path '$opt_tmpdir'",
		 " creating a shorter one...");

      # Create temporary directory in standard location for temporary files
Bjorn Munch's avatar
Bjorn Munch committed
1276
      $opt_tmpdir= tempdir( TMPDIR => 1, CLEANUP => 0 );
1277
      mtr_report(" - using tmpdir: '$opt_tmpdir'\n");
Bjorn Munch's avatar
Bjorn Munch committed
1278 1279 1280

      # Remember pid that created dir so it's removed by correct process
      $opt_tmpdir_pid= $$;
1281 1282
    }
  }
unknown's avatar
unknown committed
1283
  $opt_tmpdir =~ s,/+$,,;       # Remove ending slash if any
unknown's avatar
unknown committed
1284 1285

  # --------------------------------------------------------------------------
unknown's avatar
unknown committed
1286
  # fast option
unknown's avatar
unknown committed
1287
  # --------------------------------------------------------------------------
unknown's avatar
unknown committed
1288 1289
  if ($opt_fast){
    $opt_shutdown_timeout= 0; # Kill processes instead of nice shutdown
unknown's avatar
unknown committed
1290 1291
  }

1292 1293 1294
  # --------------------------------------------------------------------------
  # Check parallel value
  # --------------------------------------------------------------------------
1295
  if ($opt_parallel ne "auto" && $opt_parallel < 1)
1296
  {
1297
    mtr_error("0 or negative parallel value makes no sense, use 'auto' or positive number");
1298 1299
  }

unknown's avatar
unknown committed
1300
  # --------------------------------------------------------------------------
1301
  # Record flag
unknown's avatar
unknown committed
1302
  # --------------------------------------------------------------------------
unknown's avatar
unknown committed
1303
  if ( $opt_record and ! @opt_cases )
unknown's avatar
unknown committed
1304 1305 1306 1307
  {
    mtr_error("Will not run in record mode without a specific test case");
  }

1308 1309 1310
  if ( $opt_record ) {
    # Use only one worker with --record
    $opt_parallel= 1;
1311
  }
1312 1313

  # --------------------------------------------------------------------------
unknown's avatar
unknown committed
1314
  # Embedded server flag
1315
  # --------------------------------------------------------------------------
unknown's avatar
unknown committed
1316
  if ( $opt_embedded_server )
unknown's avatar
unknown committed
1317
  {
unknown's avatar
unknown committed
1318
    if ( IS_WINDOWS )
unknown's avatar
unknown committed
1319 1320 1321 1322
    {
      # Add the location for libmysqld.dll to the path.
      my $separator= ";";
      my $lib_mysqld=
1323
        mtr_path_exists("$basedir/libmysqld$opt_vs_config");
unknown's avatar
unknown committed
1324
      if ( IS_CYGWIN )
unknown's avatar
unknown committed
1325
      {
unknown's avatar
unknown committed
1326
	$lib_mysqld= posix_path($lib_mysqld);
unknown's avatar
unknown committed
1327 1328 1329 1330 1331 1332
	$separator= ":";
      }
      $ENV{'PATH'}= "$ENV{'PATH'}".$separator.$lib_mysqld;
    }
    $opt_skip_ndbcluster= 1;       # Turn off use of NDB cluster
    $opt_skip_ssl= 1;              # Turn off use of SSL
unknown's avatar
unknown committed
1333

unknown's avatar
unknown committed
1334 1335 1336 1337 1338 1339 1340
    # 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");
    }
1341

1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360

    if ($opt_gdb)
    {
      $opt_client_gdb= $opt_gdb;
      $opt_gdb= undef;
    }

    if ($opt_ddd)
    {
      $opt_client_ddd= $opt_ddd;
      $opt_ddd= undef;
    }

    if ($opt_debugger)
    {
      $opt_client_debugger= $opt_debugger;
      $opt_debugger= undef;
    }

1361 1362 1363 1364 1365 1366
    if ( $opt_gdb || $opt_ddd || $opt_manual_gdb || $opt_manual_ddd ||
	 $opt_manual_debug || $opt_debugger )
    {
      mtr_error("You need to use the client debug options for the",
		"embedded server. Ex: --client-gdb");
    }
unknown's avatar
unknown committed
1367 1368
  }

1369
  # --------------------------------------------------------------------------
1370
  # Big test and staging_run flags
1371
  # --------------------------------------------------------------------------
1372 1373 1374 1375
   if ( $opt_big_test )
   {
     $ENV{'BIG_TEST'}= 1;
   }
1376
  $ENV{'STAGING_RUN'}= $opt_staging_run;
unknown's avatar
unknown committed
1377

1378 1379 1380
  # --------------------------------------------------------------------------
  # Gcov flag
  # --------------------------------------------------------------------------
1381
  if ( ($opt_gcov or $opt_gprof) and ! $source_dist )
unknown's avatar
unknown committed
1382
  {
unknown's avatar
unknown committed
1383 1384 1385
    mtr_error("Coverage test needs the source - please use source dist");
  }

1386
  # --------------------------------------------------------------------------
unknown's avatar
unknown committed
1387
  # Check debug related options
1388
  # --------------------------------------------------------------------------
1389
  if ( $opt_gdb || $opt_client_gdb || $opt_ddd || $opt_client_ddd ||
1390 1391
       $opt_manual_gdb || $opt_manual_ddd || $opt_manual_debug ||
       $opt_debugger || $opt_client_debugger )
unknown's avatar
unknown committed
1392
  {
1393
    # Indicate that we are using debugger
unknown's avatar
unknown committed
1394
    $glob_debugger= 1;
1395 1396 1397 1398 1399
    $opt_testcase_timeout= 60*60*24;  # Don't abort debugging with timeout
    $opt_suite_timeout= $opt_testcase_timeout;
    $opt_retry= 1;
    $opt_retry_failure= 1;

unknown's avatar
unknown committed
1400
    if ( using_extern() )
unknown's avatar
unknown committed
1401
    {
unknown's avatar
unknown committed
1402
      mtr_error("Can't use --extern when using debugger");
unknown's avatar
unknown committed
1403
    }
1404 1405 1406 1407 1408 1409 1410
    # Set one week timeout (check-testcase timeout will be 1/10th)
    $opt_testcase_timeout= 7 * 24 * 60;
    $opt_suite_timeout= 7 * 24 * 60;
    # One day to shutdown
    $opt_shutdown_timeout= 24 * 60;
    # One day for PID file creation (this is given in seconds not minutes)
    $opt_start_timeout= 24 * 60 * 60;
unknown's avatar
unknown committed
1411 1412
  }

1413 1414 1415
  # --------------------------------------------------------------------------
  # Modified behavior with --start options
  # --------------------------------------------------------------------------
1416
  if ($opt_start or $opt_start_dirty or $opt_start_exit) {
1417 1418
    collect_option ('quick-collect', 1);
    $start_only= 1;
unknown's avatar
unknown committed
1419
  }
1420 1421 1422 1423 1424 1425 1426
  if ($opt_debug)
  {
    $opt_testcase_timeout= 60*60*24;  # Don't abort debugging with timeout
    $opt_suite_timeout= $opt_testcase_timeout;
    $opt_retry= 1;
    $opt_retry_failure= 1;
  }
unknown's avatar
unknown committed
1427

1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438
  # --------------------------------------------------------------------------
  # 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;
  }

1439 1440 1441 1442
  # --------------------------------------------------------------------------
  # Check use of wait-all
  # --------------------------------------------------------------------------

1443
  if ($opt_wait_all && ! $start_only)
1444
  {
1445
    mtr_error("--wait-all can only be used with --start options");
1446 1447
  }

1448
  # --------------------------------------------------------------------------
1449
  # Check timeout arguments
1450
  # --------------------------------------------------------------------------
1451 1452 1453 1454 1455 1456 1457

  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);
1458

1459
  # --------------------------------------------------------------------------
1460
  # Check valgrind arguments
1461
  # --------------------------------------------------------------------------
1462
  if ( $opt_valgrind or $opt_valgrind_path or @valgrind_args)
unknown's avatar
unknown committed
1463
  {
unknown's avatar
unknown committed
1464 1465 1466 1467
    mtr_report("Turning on valgrind for all executables");
    $opt_valgrind= 1;
    $opt_valgrind_mysqld= 1;
    $opt_valgrind_mysqltest= 1;
unknown's avatar
unknown committed
1468 1469 1470 1471 1472 1473

    # Increase the timeouts when running with valgrind
    $opt_testcase_timeout*= 10;
    $opt_suite_timeout*= 6;
    $opt_start_timeout*= 10;

unknown's avatar
unknown committed
1474
  }
1475
  elsif ( $opt_valgrind_mysqld )
unknown's avatar
unknown committed
1476
  {
1477
    mtr_report("Turning on valgrind for mysqld(s) only");
unknown's avatar
unknown committed
1478
    $opt_valgrind= 1;
1479 1480 1481
  }
  elsif ( $opt_valgrind_mysqltest )
  {
1482
    mtr_report("Turning on valgrind for mysqltest and mysql_client_test only");
unknown's avatar
unknown committed
1483
    $opt_valgrind= 1;
1484 1485
  }

1486 1487 1488 1489 1490 1491 1492
  if ( $opt_callgrind )
  {
    mtr_report("Turning on valgrind with callgrind for mysqld(s)");
    $opt_valgrind= 1;
    $opt_valgrind_mysqld= 1;

    # Set special valgrind options unless options passed on command line
1493 1494
    push(@valgrind_args, "--trace-children=yes")
      unless @valgrind_args;
1495 1496
  }

1497 1498 1499
  if ( $opt_valgrind )
  {
    # Set valgrind_options to default unless already defined
1500 1501
    push(@valgrind_args, @default_valgrind_args)
      unless @valgrind_args;
1502

1503 1504 1505
    # Make valgrind run in quiet mode so it only print errors
    push(@valgrind_args, "--quiet" );

1506 1507
    mtr_report("Running valgrind with options \"",
	       join(" ", @valgrind_args), "\"");
unknown's avatar
unknown committed
1508 1509
  }

1510 1511 1512 1513 1514
  if (@strace_args)
  {
    $opt_strace=1;
  }

1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525
  # InnoDB does not bother to do individual de-allocations at exit. Instead it
  # relies on a custom allocator to track every allocation, and frees all at
  # once during exit.
  # In XtraDB, an option use-sys-malloc is introduced (and on by default) to
  # disable this (for performance). But this exposes Valgrind to all the
  # missing de-allocations, so we need to disable it to at least get
  # meaningful leak checking for the rest of the server.
  if ($opt_valgrind_mysqld)
  {
    push(@opt_extra_mysqld_opt, "--loose-skip-innodb-use-sys-malloc");
  }
1526 1527
}

unknown's avatar
unknown committed
1528

1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543
#
# 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
#
1544
sub set_build_thread_ports($) {
1545
  my $thread= shift || 0;
1546

1547 1548
  if ( lc($opt_build_thread) eq 'auto' ) {
    my $found_free = 0;
1549
    $build_thread = 300;	# Start attempts from here
1550 1551
    while (! $found_free)
    {
1552
      $build_thread= mtr_get_unique_id($build_thread, 349);
1553
      if ( !defined $build_thread ) {
1554
        mtr_error("Could not get a unique build thread id");
1555 1556 1557
      }
      $found_free= check_ports_free($build_thread);
      # If not free, release and try from next number
1558 1559 1560 1561
      if (! $found_free) {
        mtr_release_unique_id();
        $build_thread++;
      }
1562
    }
1563 1564 1565 1566
  }
  else
  {
    $build_thread = $opt_build_thread + $thread - 1;
1567 1568 1569 1570
    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")
    }
unknown's avatar
unknown committed
1571
  }
1572
  $ENV{MTR_BUILD_THREAD}= $build_thread;
1573

unknown's avatar
unknown committed
1574
  # Calculate baseport
1575 1576
  $baseport= $build_thread * 10 + 10000;
  if ( $baseport < 5001 or $baseport + 9 >= 32767 )
1577 1578 1579
  {
    mtr_error("MTR_BUILD_THREAD number results in a port",
              "outside 5001 - 32767",
1580
              "($baseport - $baseport + 9)");
1581
  }
1582

1583
  mtr_report("Using MTR_BUILD_THREAD $build_thread,",
1584
	     "with reserved ports $baseport..".($baseport+9));
1585

unknown's avatar
unknown committed
1586 1587 1588
}


unknown's avatar
unknown committed
1589
sub collect_mysqld_features {
unknown's avatar
unknown committed
1590
  my $found_variable_list_start= 0;
1591

1592
  #
unknown's avatar
unknown committed
1593
  # Execute "mysqld --no-defaults --help --verbose" to get a
unknown's avatar
unknown committed
1594
  # list of all features and settings
1595
  #
1596 1597 1598
  # --no-defaults and --skip-grant-tables are to avoid loading
  # system-wide configs and plugins
  #
1599
  # --datadir must exist, mysqld will chdir into it
unknown's avatar
unknown committed
1600
  #
unknown's avatar
unknown committed
1601 1602 1603
  my $args;
  mtr_init_args(\$args);
  mtr_add_arg($args, "--no-defaults");
1604 1605
  mtr_add_arg($args, "--datadir=%s/tmp", $opt_vardir);
  mtr_add_arg($args, "--basedir=%s", $basedir);
unknown's avatar
unknown committed
1606 1607
  mtr_add_arg($args, "--language=%s", $path_language);
  mtr_add_arg($args, "--skip-grant-tables");
1608 1609 1610
  for (@opt_extra_mysqld_opt) {
    mtr_add_arg($args, $_) unless /^--binlog-format\b/;
  }
1611 1612 1613 1614
  my $euid= $>;
  if (!IS_WINDOWS and $euid == 0) {
    mtr_add_arg($args, "--user=root");
  }
unknown's avatar
unknown committed
1615 1616 1617
  mtr_add_arg($args, "--verbose");
  mtr_add_arg($args, "--help");

1618 1619 1620 1621 1622 1623
  # Need --user=root if running as *nix root user
  if (!IS_WINDOWS and $> == 0)
  {
    mtr_add_arg($args, "--user=root");
  }

1624
  my $exe_mysqld= find_mysqld($basedir);
unknown's avatar
unknown committed
1625 1626
  my $cmd= join(" ", $exe_mysqld, @$args);
  my $list= `$cmd`;
unknown's avatar
unknown committed
1627

1628
  mtr_verbose("cmd: $cmd");
Michael Widenius's avatar
Michael Widenius committed
1629

1630
  foreach my $line (split('\n', $list))
unknown's avatar
unknown committed
1631
  {
unknown's avatar
unknown committed
1632 1633
    # First look for version
    if ( !$mysql_version_id )
unknown's avatar
unknown committed
1634
    {
unknown's avatar
unknown committed
1635
      # Look for version
1636 1637 1638
      my $exe_name= basename($exe_mysqld);
      mtr_verbose("exe_name: $exe_name");
      if ( $line =~ /^\S*$exe_name\s\sVer\s([0-9]*)\.([0-9]*)\.([0-9]*)/ )
unknown's avatar
unknown committed
1639
      {
1640
	#print "Major: $1 Minor: $2 Build: $3\n";
unknown's avatar
unknown committed
1641
	$mysql_version_id= $1*10000 + $2*100 + $3;
1642
	#print "mysql_version_id: $mysql_version_id\n";
1643
	mtr_report("MariaDB Version $1.$2.$3");
unknown's avatar
unknown committed
1644
      }
unknown's avatar
unknown committed
1645 1646 1647
    }
    else
    {
unknown's avatar
unknown committed
1648
      if (!$found_variable_list_start)
unknown's avatar
unknown committed
1649
      {
unknown's avatar
unknown committed
1650
	# Look for start of variables list
1651
	if ( $line =~ /[\-]+\s[\-]+/ )
unknown's avatar
unknown committed
1652 1653 1654
	{
	  $found_variable_list_start= 1;
	}
1655 1656 1657
      }
      else
      {
unknown's avatar
unknown committed
1658
	# Put variables into hash
1659
	if ( $line =~ /^([\S]+)[ \t]+(.*?)\r?$/ )
unknown's avatar
unknown committed
1660
	{
1661
	  # print "$1=\"$2\"\n";
unknown's avatar
unknown committed
1662 1663
	  $mysqld_variables{$1}= $2;
	}
1664 1665
	else
	{
1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678
	  # The variable list is ended with a blank line
	  if ( $line =~ /^[\s]*$/ )
	  {
	    last;
	  }
	  else
	  {
	    # Send out a warning, we should fix the variables that has no
	    # space between variable name and it's value
	    # or should it be fixed width column parsing? It does not
	    # look like that in function my_print_variables in my_getopt.c
	    mtr_warning("Could not parse variable list line : $line");
	  }
1679
	}
unknown's avatar
unknown committed
1680
      }
unknown's avatar
unknown committed
1681
    }
unknown's avatar
unknown committed
1682
  }
unknown's avatar
unknown committed
1683
  mtr_error("Could not find version of MySQL") unless $mysql_version_id;
1684
  mtr_error("Could not find variabes list") unless $found_variable_list_start;
unknown's avatar
unknown committed
1685 1686 1687 1688

}


1689 1690 1691 1692

sub collect_mysqld_features_from_running_server ()
{
  my $mysql= mtr_exe_exists("$path_client_bindir/mysql");
unknown's avatar
unknown committed
1693 1694 1695 1696 1697 1698 1699

  my $args;
  mtr_init_args(\$args);

  mtr_add_arg($args, "--no-defaults");
  mtr_add_arg($args, "--user=%s", $opt_user);

1700 1701 1702
  while (my ($option, $value)= each( %opts_extern )) {
    mtr_add_arg($args, "--$option=$value");
  }
unknown's avatar
unknown committed
1703

1704 1705 1706 1707
  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");
unknown's avatar
unknown committed
1708

1709 1710 1711
  my $list = `$cmd` or
    mtr_error("Could not connect to extern server using command: '$cmd'");
  foreach my $line (split('\n', $list ))
unknown's avatar
unknown committed
1712 1713 1714 1715
  {
    # Put variables into hash
    if ( $line =~ /^([\S]+)[ \t]+(.*?)\r?$/ )
    {
1716
      # print "$1=\"$2\"\n";
unknown's avatar
unknown committed
1717 1718 1719
      $mysqld_variables{$1}= $2;
    }
  }
1720

1721 1722 1723 1724
  # "Convert" innodb flag
  $mysqld_variables{'innodb'}= "ON"
    if ($mysqld_variables{'have_innodb'} eq "YES");

1725 1726 1727 1728 1729 1730 1731 1732 1733 1734
  # Parse version
  my $version_str= $mysqld_variables{'version'};
  if ( $version_str =~ /^([0-9]*)\.([0-9]*)\.([0-9]*)/ )
  {
    #print "Major: $1 Minor: $2 Build: $3\n";
    $mysql_version_id= $1*10000 + $2*100 + $3;
    #print "mysql_version_id: $mysql_version_id\n";
    mtr_report("MySQL Version $1.$2.$3");
  }
  mtr_error("Could not find version of MySQL") unless $mysql_version_id;
unknown's avatar
unknown committed
1735 1736
}

1737 1738
sub find_mysqld {
  my ($mysqld_basedir)= @_;
1739

1740 1741
  my @mysqld_names= ("mysqld", "mysqld-max-nt", "mysqld-max",
		     "mysqld-nt");
1742

1743 1744 1745 1746 1747
  if ( $opt_debug ){
    # 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");
  }
1748

1749
  return my_find_bin($mysqld_basedir,
1750
		     ["sql", "libexec", "sbin", "bin"],
1751
		     [@mysqld_names]);
1752 1753
}

1754

unknown's avatar
unknown committed
1755 1756
sub executable_setup () {

1757 1758 1759 1760 1761 1762 1763 1764 1765
  #
  # Check if libtool is available in this distribution/clone
  # we need it when valgrinding or debugging non installed binary
  # Otherwise valgrind will valgrind the libtool wrapper or bash
  # and gdb will not find the real executable to debug
  #
  if ( -x "../libtool")
  {
    $exe_libtool= "../libtool";
1766
    if ($opt_valgrind or $glob_debugger or $opt_strace)
1767
    {
1768
      mtr_report("Using \"$exe_libtool\" when running valgrind, strace or debugger");
1769 1770 1771
    }
  }

unknown's avatar
unknown committed
1772 1773 1774
  # Look for the client binaries
  $exe_mysqladmin=     mtr_exe_exists("$path_client_bindir/mysqladmin");
  $exe_mysql=          mtr_exe_exists("$path_client_bindir/mysql");
unknown's avatar
unknown committed
1775

unknown's avatar
unknown committed
1776
  if ( ! $opt_skip_ndbcluster )
1777
  {
unknown's avatar
unknown committed
1778 1779
    $exe_ndbd=
      my_find_bin($basedir,
Luis Soares's avatar
Luis Soares committed
1780
		  ["storage/ndb/src/kernel", "libexec", "sbin", "bin"],
unknown's avatar
unknown committed
1781
		  "ndbd");
1782

unknown's avatar
unknown committed
1783 1784
    $exe_ndb_mgmd=
      my_find_bin($basedir,
Luis Soares's avatar
Luis Soares committed
1785
		  ["storage/ndb/src/mgmsrv", "libexec", "sbin", "bin"],
unknown's avatar
unknown committed
1786
		  "ndb_mgmd");
unknown's avatar
unknown committed
1787

unknown's avatar
unknown committed
1788 1789 1790 1791
    $exe_ndb_waiter=
      my_find_bin($basedir,
		  ["storage/ndb/tools/", "bin"],
		  "ndb_waiter");
1792

unknown's avatar
unknown committed
1793
  }
1794

unknown's avatar
unknown committed
1795
  # Look for mysqltest executable
unknown's avatar
unknown committed
1796
  if ( $opt_embedded_server )
unknown's avatar
unknown committed
1797
  {
unknown's avatar
unknown committed
1798
    $exe_mysqltest=
1799
      mtr_exe_exists("$basedir/libmysqld/examples$opt_vs_config/mysqltest_embedded",
1800
                     "$path_client_bindir/mysqltest_embedded");
unknown's avatar
unknown committed
1801
  }
unknown's avatar
unknown committed
1802 1803
  else
  {
1804
    $exe_mysqltest= mtr_exe_exists("$path_client_bindir/mysqltest");
unknown's avatar
unknown committed
1805
  }
1806

unknown's avatar
unknown committed
1807 1808 1809
}


unknown's avatar
unknown committed
1810 1811 1812 1813 1814 1815 1816 1817
sub client_debug_arg($$) {
  my ($args, $client_name)= @_;

  if ( $opt_debug ) {
    mtr_add_arg($args,
		"--debug=d:t:A,%s/log/%s.trace",
		$path_vardir_trace, $client_name)
  }
1818 1819 1820
}


unknown's avatar
unknown committed
1821
sub mysql_fix_arguments () {
unknown's avatar
unknown committed
1822

unknown's avatar
unknown committed
1823
  return "" if ( IS_WINDOWS );
1824

unknown's avatar
unknown committed
1825 1826 1827
  my $exe=
    mtr_script_exists("$basedir/scripts/mysql_fix_privilege_tables",
		      "$path_client_bindir/mysql_fix_privilege_tables");
1828 1829
  my $args;
  mtr_init_args(\$args);
unknown's avatar
unknown committed
1830
  mtr_add_arg($args, "--defaults-file=%s", $path_config_file);
1831

1832 1833
  mtr_add_arg($args, "--basedir=%s", $basedir);
  mtr_add_arg($args, "--bindir=%s", $path_client_bindir);
unknown's avatar
unknown committed
1834
  mtr_add_arg($args, "--verbose");
1835
  mtr_add_arg($args, "--sync-sys=0"); # Speed up test suite
unknown's avatar
unknown committed
1836 1837
  return mtr_args2str($exe, @$args);
}
1838 1839


1840
sub client_arguments ($;$) {
unknown's avatar
unknown committed
1841
  my $client_name= shift;
1842
  my $group_suffix= shift;
unknown's avatar
unknown committed
1843
  my $client_exe= mtr_exe_exists("$path_client_bindir/$client_name");
1844

unknown's avatar
unknown committed
1845 1846 1847
  my $args;
  mtr_init_args(\$args);
  mtr_add_arg($args, "--defaults-file=%s", $path_config_file);
1848 1849 1850 1851 1852
  if (defined($group_suffix)) {
    mtr_add_arg($args, "--defaults-group-suffix=%s", $group_suffix);
    client_debug_arg($args, "$client_name-$group_suffix");
  }
  else
1853
  {
1854
    client_debug_arg($args, $client_name);
1855
  }
unknown's avatar
unknown committed
1856 1857 1858 1859
  return mtr_args2str($client_exe, @$args);
}


1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871
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);
}


unknown's avatar
unknown committed
1872 1873 1874 1875 1876 1877 1878 1879 1880
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
1881 1882
  }

unknown's avatar
unknown committed
1883 1884 1885 1886 1887
  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);
1888 1889
}

unknown's avatar
unknown committed
1890 1891 1892 1893

sub mysqldump_arguments ($) {
  my($group_suffix) = @_;
  my $exe= mtr_exe_exists("$path_client_bindir/mysqldump");
1894 1895 1896

  my $args;
  mtr_init_args(\$args);
unknown's avatar
unknown committed
1897
  mtr_add_arg($args, "--defaults-file=%s", $path_config_file);
1898
  mtr_add_arg($args, "--defaults-group-suffix=%s", $group_suffix);
unknown's avatar
unknown committed
1899 1900 1901
  client_debug_arg($args, "mysqldump-$group_suffix");
  return mtr_args2str($exe, @$args);
}
1902 1903


unknown's avatar
unknown committed
1904 1905 1906 1907 1908
sub mysql_client_test_arguments(){
  my $exe;
  # mysql_client_test executable may _not_ exist
  if ( $opt_embedded_server ) {
    $exe= mtr_exe_maybe_exists(
1909
            "$basedir/libmysqld/examples$opt_vs_config/mysql_client_test_embedded",
1910
		"$basedir/bin/mysql_client_test_embedded");
unknown's avatar
unknown committed
1911
  } else {
1912
    $exe= mtr_exe_maybe_exists("$basedir/tests$opt_vs_config/mysql_client_test",
unknown's avatar
unknown committed
1913 1914 1915 1916 1917 1918 1919
			       "$basedir/bin/mysql_client_test");
  }

  my $args;
  mtr_init_args(\$args);
  if ( $opt_valgrind_mysqltest ) {
    valgrind_arguments($args, \$exe);
1920
  }
unknown's avatar
unknown committed
1921 1922 1923 1924
  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");
1925

unknown's avatar
unknown committed
1926
  return mtr_args2str($exe, @$args);
1927 1928
}

1929 1930 1931 1932 1933
sub tool_arguments ($$) {
  my($sedir, $tool_name) = @_;
  my $exe= my_find_bin($basedir,
		       [$sedir, "bin"],
		       $tool_name);
unknown's avatar
unknown committed
1934

1935 1936 1937 1938 1939
  my $args;
  mtr_init_args(\$args);
  client_debug_arg($args, $tool_name);
  return mtr_args2str($exe, @$args);
}
unknown's avatar
unknown committed
1940

1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954
# 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($basedir);
  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);
}

unknown's avatar
unknown committed
1955

1956
sub have_maria_support () {
Sergei Golubchik's avatar
Sergei Golubchik committed
1957
  my $maria_var= $mysqld_variables{'aria'};
1958 1959 1960
  return defined $maria_var and $maria_var eq 'TRUE';
}

unknown's avatar
unknown committed
1961 1962 1963 1964 1965
#
# Set environment to be used by childs of this process for
# things that are constant during the whole lifetime of mysql-test-run
#
sub environment_setup {
unknown's avatar
unknown committed
1966

unknown's avatar
unknown committed
1967 1968
  umask(022);

1969
  my @ld_library_paths;
1970

1971
  if ($path_client_libdir)
unknown's avatar
unknown committed
1972
  {
1973 1974
    # Use the --client-libdir passed on commandline
    push(@ld_library_paths, "$path_client_libdir");
1975 1976
  }
  else
unknown's avatar
unknown committed
1977
  {
1978 1979 1980 1981
    # Setup LD_LIBRARY_PATH so the libraries from this distro/clone
    # are used in favor of the system installed ones
    if ( $source_dist )
    {
unknown's avatar
unknown committed
1982 1983
      push(@ld_library_paths, "$basedir/libmysql/.libs/",
	   "$basedir/libmysql_r/.libs/",
1984
	   "$basedir/zlib/.libs/");
1985 1986 1987
    }
    else
    {
1988
      push(@ld_library_paths, "$basedir/lib", "$basedir/lib/mysql");
1989
    }
1990 1991
  }

unknown's avatar
unknown committed
1992
  # --------------------------------------------------------------------------
1993 1994
  # Add the path where libndbclient can be found
  # --------------------------------------------------------------------------
1995
  if ( !$opt_skip_ndbcluster )
1996
  {
unknown's avatar
unknown committed
1997
    push(@ld_library_paths,  "$basedir/storage/ndb/src/.libs");
unknown's avatar
unknown committed
1998
  }
unknown's avatar
unknown committed
1999

2000
  # --------------------------------------------------------------------------
2001
  # Valgrind need to be run with debug libraries otherwise it's almost
2002 2003 2004
  # impossible to add correct supressions, that means if "/usr/lib/debug"
  # is available, it should be added to
  # LD_LIBRARY_PATH
2005 2006 2007 2008
  #
  # But pthread is broken in libc6-dbg on Debian <= 3.1 (see Debian
  # bug 399035, http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=399035),
  # so don't change LD_LIBRARY_PATH on that platform.
2009
  # --------------------------------------------------------------------------
2010
  my $debug_libraries_path= "/usr/lib/debug";
2011 2012 2013
  my $deb_version;
  if (  $opt_valgrind and -d $debug_libraries_path and
        (! -e '/etc/debian_version' or
unknown's avatar
unknown committed
2014 2015
	 ($deb_version=
	    mtr_grab_file('/etc/debian_version')) !~ /^[0-9]+\.[0-9]$/ or
2016
         $deb_version > 3.1 ) )
2017
  {
2018
    push(@ld_library_paths, $debug_libraries_path);
2019
  }
2020

2021
  $ENV{'LD_LIBRARY_PATH'}= join(":", @ld_library_paths,
unknown's avatar
unknown committed
2022
				$ENV{'LD_LIBRARY_PATH'} ?
2023
				split(':', $ENV{'LD_LIBRARY_PATH'}) : ());
2024 2025 2026
  mtr_debug("LD_LIBRARY_PATH: $ENV{'LD_LIBRARY_PATH'}");

  $ENV{'DYLD_LIBRARY_PATH'}= join(":", @ld_library_paths,
2027 2028
				  $ENV{'DYLD_LIBRARY_PATH'} ?
				  split(':', $ENV{'DYLD_LIBRARY_PATH'}) : ());
2029
  mtr_debug("DYLD_LIBRARY_PATH: $ENV{'DYLD_LIBRARY_PATH'}");
2030

2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041
  # 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'}");
2042

2043
  $ENV{'CHARSETSDIR'}=              $path_charsetsdir;
unknown's avatar
unknown committed
2044 2045
  $ENV{'UMASK'}=              "0660"; # The octal *string*
  $ENV{'UMASK_DIR'}=          "0770"; # The octal *string*
unknown's avatar
unknown committed
2046

2047 2048 2049 2050 2051 2052 2053 2054 2055 2056
  #
  # MySQL 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";
unknown's avatar
unknown committed
2057

unknown's avatar
unknown committed
2058
  $ENV{'LC_COLLATE'}=         "C";
unknown's avatar
unknown committed
2059
  $ENV{'USE_RUNNING_SERVER'}= using_extern();
unknown's avatar
unknown committed
2060
  $ENV{'MYSQL_TEST_DIR'}=     $glob_mysql_test_dir;
unknown's avatar
unknown committed
2061
  $ENV{'DEFAULT_MASTER_PORT'}= $mysqld_variables{'master-port'} || 3306;
2062
  $ENV{'MYSQL_TMP_DIR'}=      $opt_tmpdir;
Magnus Svensson's avatar
Magnus Svensson committed
2063
  $ENV{'MYSQLTEST_VARDIR'}=   $opt_vardir;
2064

2065 2066 2067 2068 2069 2070 2071 2072 2073
  #
  # 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'));

2074 2075 2076
  # ----------------------------------------------------
  # Setup env for NDB
  # ----------------------------------------------------
2077 2078
  if ( ! $opt_skip_ndbcluster )
  {
unknown's avatar
unknown committed
2079 2080 2081 2082
    $ENV{'NDB_MGM'}=
      my_find_bin($basedir,
		  ["storage/ndb/src/mgmclient", "bin"],
		  "ndb_mgm");
2083

unknown's avatar
unknown committed
2084 2085 2086
    $ENV{'NDB_TOOLS_DIR'}=
      my_find_dir($basedir,
		  ["storage/ndb/tools", "bin"]);
2087

unknown's avatar
unknown committed
2088 2089 2090
    $ENV{'NDB_EXAMPLES_DIR'}=
      my_find_dir($basedir,
		  ["storage/ndb/ndbapi-examples", "bin"]);
2091

unknown's avatar
unknown committed
2092 2093 2094 2095
    $ENV{'NDB_EXAMPLES_BINARY'}=
      my_find_bin($basedir,
		  ["storage/ndb/ndbapi-examples/ndbapi_simple", "bin"],
		  "ndbapi_simple", NOT_REQUIRED);
2096

unknown's avatar
unknown committed
2097 2098
    my $path_ndb_testrun_log= "$opt_vardir/log/ndb_testrun.log";
    $ENV{'NDB_TOOLS_OUTPUT'}=         $path_ndb_testrun_log;
2099 2100
    $ENV{'NDB_EXAMPLES_OUTPUT'}=      $path_ndb_testrun_log;
  }
2101

2102
  # ----------------------------------------------------
unknown's avatar
unknown committed
2103
  # mysql clients
2104
  # ----------------------------------------------------
unknown's avatar
unknown committed
2105 2106 2107 2108 2109 2110
  $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");
2111
  $ENV{'MYSQL_BINLOG'}=             mysqlbinlog_arguments();
unknown's avatar
unknown committed
2112
  $ENV{'MYSQL'}=                    client_arguments("mysql");
2113
  $ENV{'MYSQL_SLAVE'}=              client_arguments("mysql", ".2");
unknown's avatar
unknown committed
2114
  $ENV{'MYSQL_UPGRADE'}=            client_arguments("mysql_upgrade");
unknown's avatar
unknown committed
2115
  $ENV{'MYSQLADMIN'}=               native_path($exe_mysqladmin);
unknown's avatar
unknown committed
2116 2117
  $ENV{'MYSQL_CLIENT_TEST'}=        mysql_client_test_arguments();
  $ENV{'MYSQL_FIX_SYSTEM_TABLES'}=  mysql_fix_arguments();
2118
  $ENV{'MYSQLD'}=                   mysqld_client_arguments();
unknown's avatar
unknown committed
2119
  $ENV{'EXE_MYSQL'}=                $exe_mysql;
2120 2121

  # ----------------------------------------------------
unknown's avatar
unknown committed
2122 2123
  # bug25714 executable may _not_ exist in
  # some versions, test using it should be skipped
2124
  # ----------------------------------------------------
unknown's avatar
unknown committed
2125
  my $exe_bug25714=
2126
      mtr_exe_maybe_exists("$basedir/tests$opt_vs_config/bug25714");
unknown's avatar
unknown committed
2127
  $ENV{'MYSQL_BUG25714'}=  native_path($exe_bug25714);
2128

2129
  # ----------------------------------------------------
unknown's avatar
unknown committed
2130
  # mysql_fix_privilege_tables.sql
2131
  # ----------------------------------------------------
unknown's avatar
unknown committed
2132 2133
  my $file_mysql_fix_privilege_tables=
    mtr_file_exists("$basedir/scripts/mysql_fix_privilege_tables.sql",
Sven Sandberg's avatar
Sven Sandberg committed
2134
		    "$basedir/share/mysql_fix_privilege_tables.sql",
2135
		    "$basedir/share/mariadb/mysql_fix_privilege_tables.sql",
Sven Sandberg's avatar
Sven Sandberg committed
2136
		    "$basedir/share/mysql/mysql_fix_privilege_tables.sql");
2137
  $ENV{'MYSQL_FIX_PRIVILEGE_TABLES'}=  $file_mysql_fix_privilege_tables;
2138

2139
  # ----------------------------------------------------
unknown's avatar
unknown committed
2140
  # my_print_defaults
2141
  # ----------------------------------------------------
unknown's avatar
unknown committed
2142
  my $exe_my_print_defaults=
2143 2144
    mtr_exe_exists("$basedir/extra$opt_vs_config/my_print_defaults",
		   "$path_client_bindir/my_print_defaults");
unknown's avatar
unknown committed
2145
  $ENV{'MYSQL_MY_PRINT_DEFAULTS'}= native_path($exe_my_print_defaults);
2146

2147
  # ----------------------------------------------------
2148
  # myisam tools
2149
  # ----------------------------------------------------
2150 2151 2152 2153
  $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");
unknown's avatar
unknown committed
2154

2155
  # ----------------------------------------------------
Sergei Golubchik's avatar
Sergei Golubchik committed
2156
  # aria tools
2157
  # ----------------------------------------------------
2158
  if (have_maria_support())
2159
  {
Sergei Golubchik's avatar
Sergei Golubchik committed
2160 2161
    $ENV{'MARIA_CHK'}= tool_arguments("storage/maria", "aria_chk");
    $ENV{'MARIA_PACK'}= tool_arguments("storage/maria", "aria_pack");
2162
  }
2163

2164 2165 2166 2167 2168 2169 2170 2171 2172
  # ----------------------------------------------------
  # mysqlhotcopy
  # ----------------------------------------------------
  my $mysqlhotcopy=
    mtr_pl_maybe_exists("$basedir/scripts/mysqlhotcopy");
  # Since mysqltest interprets the real path as "false" in an if,
  # use 1 ("true") to indicate "not exists" so it can be tested for
  $ENV{'MYSQLHOTCOPY'}= $mysqlhotcopy || 1;

unknown's avatar
unknown committed
2173
  # ----------------------------------------------------
unknown's avatar
unknown committed
2174
  # perror
unknown's avatar
unknown committed
2175
  # ----------------------------------------------------
2176
  my $exe_perror= mtr_exe_exists("$basedir/extra$opt_vs_config/perror",
unknown's avatar
unknown committed
2177
				 "$path_client_bindir/perror");
unknown's avatar
unknown committed
2178
  $ENV{'MY_PERROR'}= native_path($exe_perror);
2179 2180 2181 2182

  # Create an environment variable to make it possible
  # to detect that valgrind is being used from test cases
  $ENV{'VALGRIND_TEST'}= $opt_valgrind;
unknown's avatar
unknown committed
2183 2184 2185
}


2186

2187 2188 2189 2190 2191
#
# Remove var and any directories in var/ created by previous
# tests
#
sub remove_stale_vardir () {
2192

unknown's avatar
unknown committed
2193
  mtr_report("Removing old var directory...");
unknown's avatar
unknown committed
2194

2195 2196
  # Safety!
  mtr_error("No, don't remove the vardir when running with --extern")
unknown's avatar
unknown committed
2197
    if using_extern();
2198 2199

  mtr_verbose("opt_vardir: $opt_vardir");
2200
  if ( $opt_vardir eq $default_vardir )
2201 2202 2203 2204
  {
    #
    # Running with "var" in mysql-test dir
    #
2205
    if ( -l $opt_vardir)
2206
    {
2207
      # var is a symlink
2208

2209
      if ( $opt_mem )
2210 2211
      {
	# Remove the directory which the link points at
2212
	mtr_verbose("Removing " . readlink($opt_vardir));
unknown's avatar
unknown committed
2213
	rmtree(readlink($opt_vardir));
2214

2215
	# Remove the "var" symlink
2216
	mtr_verbose("unlink($opt_vardir)");
2217
	unlink($opt_vardir);
2218 2219 2220 2221
      }
      else
      {
	# Some users creates a soft link in mysql-test/var to another area
2222 2223
	# - allow it, but remove all files in it

unknown's avatar
unknown committed
2224
	mtr_report(" - WARNING: Using the 'mysql-test/var' symlink");
2225

2226 2227 2228 2229
	# Make sure the directory where it points exist
	mtr_error("The destination for symlink $opt_vardir does not exist")
	  if ! -d readlink($opt_vardir);

2230 2231 2232
	foreach my $bin ( glob("$opt_vardir/*") )
	{
	  mtr_verbose("Removing bin $bin");
unknown's avatar
unknown committed
2233
	  rmtree($bin);
2234
	}
2235
      }
2236 2237 2238 2239
    }
    else
    {
      # Remove the entire "var" dir
2240
      mtr_verbose("Removing $opt_vardir/");
unknown's avatar
unknown committed
2241
      rmtree("$opt_vardir/");
2242
    }
2243 2244 2245 2246 2247 2248 2249

    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");
unknown's avatar
unknown committed
2250
      rmtree($opt_mem);
2251 2252
    }

2253 2254 2255 2256 2257 2258 2259 2260 2261
  }
  else
  {
    #
    # Running with "var" in some other place
    #

    # Remove the var/ dir in mysql-test dir if any
    # this could be an old symlink that shouldn't be there
2262
    mtr_verbose("Removing $default_vardir");
unknown's avatar
unknown committed
2263
    rmtree($default_vardir);
2264 2265

    # Remove the "var" dir
2266
    mtr_verbose("Removing $opt_vardir/");
unknown's avatar
unknown committed
2267
    rmtree("$opt_vardir/");
2268
  }
2269 2270
  # Remove the "tmp" dir
  mtr_verbose("Removing $opt_tmpdir/");
Luis Soares's avatar
Luis Soares committed
2271
  rmtree("$opt_tmpdir/");
2272 2273
}

2274 2275 2276 2277 2278
sub set_plugin_var($) {
  local $_ = $_[0];
  s/\.\w+$//;
  $ENV{"\U${_}_SO"} = $_[0];
}
unknown's avatar
unknown committed
2279

2280 2281 2282 2283
#
# Create var and the directories needed in var
#
sub setup_vardir() {
2284
  mtr_report("Creating var directory '$opt_vardir'...");
unknown's avatar
unknown committed
2285

2286
  if ( $opt_vardir eq $default_vardir )
2287
  {
2288 2289 2290 2291 2292 2293
    #
    # Running with "var" in mysql-test dir
    #
    if ( -l $opt_vardir )
    {
      #  it's a symlink
2294

2295 2296 2297 2298 2299 2300 2301 2302 2303
      # Make sure the directory where it points exist
      mtr_error("The destination for symlink $opt_vardir does not exist")
	if ! -d readlink($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);
2304

unknown's avatar
unknown committed
2305
      mtr_report(" - symlinking 'var' to '$opt_mem'");
2306 2307
      symlink($opt_mem, $opt_vardir);
    }
2308 2309
  }

2310 2311 2312 2313 2314
  if ( ! -d $opt_vardir )
  {
    mtr_verbose("Creating $opt_vardir");
    mkpath($opt_vardir);
  }
unknown's avatar
unknown committed
2315

2316 2317
  # Ensure a proper error message if vardir couldn't be created
  unless ( -d $opt_vardir and -w $opt_vardir )
2318
  {
2319 2320
    mtr_error("Writable 'var' directory is needed, use the " .
	      "'--vardir=<path>' option");
2321 2322
  }

2323 2324
  mkpath("$opt_vardir/log");
  mkpath("$opt_vardir/run");
unknown's avatar
unknown committed
2325

2326 2327 2328
  # Create var/tmp and tmp - they might be different
  mkpath("$opt_vardir/tmp");
  mkpath($opt_tmpdir) if ($opt_tmpdir ne "$opt_vardir/tmp");
2329

2330 2331 2332 2333 2334 2335 2336
  # 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 ",
	      "MySQL Server. Set a shorter with --tmpdir=<path> option");
2337
  }
2338

unknown's avatar
unknown committed
2339
  # copy all files from std_data into var/std_data
2340 2341
  # and make them world readable
  copytree("$glob_mysql_test_dir/std_data", "$opt_vardir/std_data", "0022");
unknown's avatar
unknown committed
2342

2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380
  # create a plugin dir and copy plugins into it
  if ($source_dist)
  {
    $plugindir="$opt_vardir/plugins";
    unshift (@opt_extra_mysqld_opt, "--plugin-dir=$plugindir");
    mkpath($plugindir);
    if (IS_WINDOWS)
    {
      for (<../storage/*$opt_vs_config/*.dll>,
           <../plugin/*$opt_vs_config/*.dll>,
           <../sql$opt_vs_config/*.dll>)
      {
        my $pname=basename($_);
        copy rel2abs($_), "$plugindir/$pname";
        set_plugin_var($pname);
      }
    }
    else
    {
      for (<../storage/*/.libs/*.so>,<../plugin/*/.libs/*.so>,<../sql/.libs/*.so>)
      {
        my $pname=basename($_);
        symlink rel2abs($_), "$plugindir/$pname";
        set_plugin_var($pname);
      }
    }
  }
  else
  {
    # hm, what paths work for debs and for rpms ?
    for (<$basedir/lib/mysql/plugin/*.so>,
         <$basedir/lib/plugin/*.dll>)
    {
      my $pname=basename($_);
      set_plugin_var($pname);
    }
  }

unknown's avatar
unknown committed
2381
  # Remove old log files
unknown's avatar
unknown committed
2382
  foreach my $name (glob("r/*.progress r/*.log r/*.warnings"))
unknown's avatar
unknown committed
2383 2384 2385
  {
    unlink($name);
  }
unknown's avatar
unknown committed
2386 2387 2388
}


unknown's avatar
unknown committed
2389 2390 2391 2392
#
# Check if running as root
# i.e a file can be read regardless what mode we set it to
#
2393
sub  check_running_as_root () {
2394
  my $test_file= "$opt_vardir/test_running_as_root.txt";
2395 2396 2397 2398 2399 2400 2401 2402 2403 2404
  mtr_tofile($test_file, "MySQL");
  chmod(oct("0000"), $test_file);

  my $result="";
  if (open(FILE,"<",$test_file))
  {
    $result= join('', <FILE>);
    close FILE;
  }

2405 2406 2407 2408
  # 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;
2409

2410 2411
  mtr_verbose("result: $result, file_mode: $file_mode");
  if ($result eq "MySQL" && $file_mode == 0)
2412 2413 2414
  {
    mtr_warning("running this script as _root_ will cause some " .
                "tests to be skipped");
2415
    $ENV{'MYSQL_TEST_ROOT'}= "1";
2416
  }
2417 2418 2419

  chmod(oct("0755"), $test_file);
  unlink($test_file);
2420 2421 2422
}


unknown's avatar
unknown committed
2423 2424
sub check_ssl_support ($) {
  my $mysqld_variables= shift;
2425

unknown's avatar
unknown committed
2426
  if ($opt_skip_ssl)
2427
  {
unknown's avatar
unknown committed
2428
    mtr_report(" - skipping SSL");
2429 2430 2431 2432 2433
    $opt_ssl_supported= 0;
    $opt_ssl= 0;
    return;
  }

2434
  if ( ! $mysqld_variables->{'ssl'} )
2435 2436 2437 2438 2439 2440
  {
    if ( $opt_ssl)
    {
      mtr_error("Couldn't find support for SSL");
      return;
    }
unknown's avatar
unknown committed
2441
    mtr_report(" - skipping SSL, mysqld not compiled with SSL");
2442 2443 2444 2445
    $opt_ssl_supported= 0;
    $opt_ssl= 0;
    return;
  }
unknown's avatar
unknown committed
2446
  mtr_report(" - SSL connections supported");
2447 2448 2449 2450
  $opt_ssl_supported= 1;
}


unknown's avatar
unknown committed
2451 2452
sub check_debug_support ($) {
  my $mysqld_variables= shift;
unknown's avatar
unknown committed
2453

2454
  if ( ! $mysqld_variables->{'debug'} )
unknown's avatar
unknown committed
2455
  {
unknown's avatar
unknown committed
2456
    #mtr_report(" - binaries are not debug compiled");
unknown's avatar
unknown committed
2457
    $debug_compiled_binaries= 0;
2458 2459 2460 2461 2462

    if ( $opt_debug )
    {
      mtr_error("Can't use --debug, binaries does not support it");
    }
unknown's avatar
unknown committed
2463 2464
    return;
  }
unknown's avatar
unknown committed
2465
  mtr_report(" - binaries are debug compiled");
unknown's avatar
unknown committed
2466 2467 2468
  $debug_compiled_binaries= 1;
}

unknown's avatar
unknown committed
2469

2470
#
2471 2472 2473 2474
# 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.
2475
#
2476 2477 2478 2479
# 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
2480
#
2481 2482 2483
sub fix_vs_config_dir () {
  return $opt_vs_config="" unless IS_WINDOWS;
  return $opt_vs_config="/$opt_vs_config" if $opt_vs_config;
2484

2485 2486
  my $modified = 1e30;
  $opt_vs_config="";
unknown's avatar
unknown committed
2487

2488 2489 2490 2491 2492 2493 2494 2495 2496
  for my $dir (qw(client/*.dir libmysql/libmysql.dir sql/mysqld.dir
                  sql/udf_example.dir storage/*/*.dir plugin/*/*.dir)) {
    for (<$basedir/$dir/*/BuildLog.htm>) {
      if (-M $_ < $modified)
      {
        $modified = -M _;
        $opt_vs_config = basename(dirname($_));
      }
    }
2497 2498
  }

2499 2500
  mtr_report("VS config: $opt_vs_config");
  $opt_vs_config="/$opt_vs_config" if $opt_vs_config;
2501 2502
}

unknown's avatar
unknown committed
2503

unknown's avatar
unknown committed
2504 2505
sub check_ndbcluster_support ($) {
  my $mysqld_variables= shift;
2506

unknown's avatar
unknown committed
2507
  if ($opt_skip_ndbcluster)
2508
  {
unknown's avatar
unknown committed
2509
    mtr_report(" - skipping ndbcluster");
2510 2511
    return;
  }
2512

unknown's avatar
unknown committed
2513
  if ( ! $mysqld_variables{'ndb-connectstring'} )
2514
  {
2515
    #mtr_report(" - skipping ndbcluster, mysqld not compiled with ndbcluster");
2516
    $opt_skip_ndbcluster= 2;
2517
    return;
2518
  }
2519

unknown's avatar
unknown committed
2520
  mtr_report(" - using ndbcluster when necessary, mysqld supports it");
2521

2522
  return;
2523 2524
}

unknown's avatar
unknown committed
2525

2526
sub ndbcluster_wait_started {
unknown's avatar
unknown committed
2527
  my $cluster= shift;
2528
  my $ndb_waiter_extra_opt= shift;
unknown's avatar
unknown committed
2529
  my $path_waitlog= join('/', $opt_vardir, $cluster->name(), "ndb_waiter.log");
2530

unknown's avatar
unknown committed
2531
  my $args;
2532
  mtr_init_args(\$args);
unknown's avatar
unknown committed
2533 2534
  mtr_add_arg($args, "--defaults-file=%s", $path_config_file);
  mtr_add_arg($args, "--defaults-group-suffix=%s", $cluster->suffix());
2535
  mtr_add_arg($args, "--timeout=%d", $opt_start_timeout);
2536 2537 2538 2539 2540

  if ($ndb_waiter_extra_opt)
  {
    mtr_add_arg($args, "$ndb_waiter_extra_opt");
  }
unknown's avatar
unknown committed
2541 2542 2543 2544

  # Start the ndb_waiter which will connect to the ndb_mgmd
  # and poll it for state of the ndbd's, will return when
  # all nodes in the cluster is started
2545

unknown's avatar
unknown committed
2546 2547 2548 2549 2550 2551 2552 2553 2554
  my $res= My::SafeProcess->run
    (
     name          => "ndb_waiter ".$cluster->name(),
     path          => $exe_ndb_waiter,
     args          => \$args,
     output        => $path_waitlog,
     error         => $path_waitlog,
     append        => 1,
    );
2555

unknown's avatar
unknown committed
2556 2557 2558 2559 2560 2561 2562 2563 2564 2565
  # Check that ndb_mgmd(s) are still alive
  foreach my $ndb_mgmd ( in_cluster($cluster, ndb_mgmds()) )
  {
    my $proc= $ndb_mgmd->{proc};
    if ( ! $proc->wait_one(0) )
    {
      mtr_warning("$proc died");
      return 2;
    }
  }
2566

unknown's avatar
unknown committed
2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577
  # Check that all started ndbd(s) are still alive
  foreach my $ndbd ( in_cluster($cluster, ndbds()) )
  {
    my $proc= $ndbd->{proc};
    next unless defined $proc;
    if ( ! $proc->wait_one(0) )
    {
      mtr_warning("$proc died");
      return 3;
    }
  }
2578

unknown's avatar
unknown committed
2579
  if ($res)
2580
  {
unknown's avatar
unknown committed
2581
    mtr_verbose("ndbcluster_wait_started failed");
2582 2583 2584
    return 1;
  }
  return 0;
unknown's avatar
unknown committed
2585 2586 2587
}


2588 2589 2590 2591
sub ndb_mgmd_wait_started($) {
  my ($cluster)= @_;

  my $retries= 100;
unknown's avatar
unknown committed
2592
  while ($retries)
2593
  {
unknown's avatar
unknown committed
2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605
    my $result= ndbcluster_wait_started($cluster, "--no-contact");
    if ($result == 0)
    {
      # ndb_mgmd is started
      mtr_verbose("ndb_mgmd is started");
      return 0;
    }
    elsif ($result > 1)
    {
      mtr_warning("Cluster process failed while waiting for start");
      return $result;
    }
2606

unknown's avatar
unknown committed
2607
    mtr_milli_sleep(100);
2608 2609 2610
    $retries--;
  }

unknown's avatar
unknown committed
2611
  return 1;
2612 2613
}

unknown's avatar
unknown committed
2614

unknown's avatar
unknown committed
2615 2616
sub ndb_mgmd_start ($$) {
  my ($cluster, $ndb_mgmd)= @_;
unknown's avatar
unknown committed
2617

unknown's avatar
unknown committed
2618 2619 2620 2621 2622 2623
  mtr_verbose("ndb_mgmd_start");

  my $dir= $ndb_mgmd->value("DataDir");
  mkpath($dir) unless -d $dir;

  my $args;
unknown's avatar
unknown committed
2624
  mtr_init_args(\$args);
unknown's avatar
unknown committed
2625 2626 2627
  mtr_add_arg($args, "--defaults-file=%s", $path_config_file);
  mtr_add_arg($args, "--defaults-group-suffix=%s", $cluster->suffix());
  mtr_add_arg($args, "--mycnf");
2628
  mtr_add_arg($args, "--nodaemon");
unknown's avatar
unknown committed
2629

unknown's avatar
unknown committed
2630
  my $path_ndb_mgmd_log= "$dir/ndb_mgmd.log";
unknown's avatar
unknown committed
2631

unknown's avatar
unknown committed
2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642
  $ndb_mgmd->{'proc'}= My::SafeProcess->new
    (
     name          => $ndb_mgmd->after('cluster_config.'),
     path          => $exe_ndb_mgmd,
     args          => \$args,
     output        => $path_ndb_mgmd_log,
     error         => $path_ndb_mgmd_log,
     append        => 1,
     verbose       => $opt_verbose,
    );
  mtr_verbose("Started $ndb_mgmd->{proc}");
unknown's avatar
unknown committed
2643

2644 2645 2646
  # FIXME Should not be needed
  # Unfortunately the cluster nodes will fail to start
  # if ndb_mgmd has not started properly
2647
  if (ndb_mgmd_wait_started($cluster))
2648
  {
unknown's avatar
unknown committed
2649 2650
    mtr_warning("Failed to wait for start of ndb_mgmd");
    return 1;
2651
  }
2652

unknown's avatar
unknown committed
2653
  return 0;
unknown's avatar
unknown committed
2654 2655 2656
}


unknown's avatar
unknown committed
2657 2658 2659 2660
sub ndbd_start {
  my ($cluster, $ndbd)= @_;

  mtr_verbose("ndbd_start");
unknown's avatar
unknown committed
2661

unknown's avatar
unknown committed
2662 2663
  my $dir= $ndbd->value("DataDir");
  mkpath($dir) unless -d $dir;
unknown's avatar
unknown committed
2664

unknown's avatar
unknown committed
2665
  my $args;
unknown's avatar
unknown committed
2666
  mtr_init_args(\$args);
unknown's avatar
unknown committed
2667 2668
  mtr_add_arg($args, "--defaults-file=%s", $path_config_file);
  mtr_add_arg($args, "--defaults-group-suffix=%s", $cluster->suffix());
unknown's avatar
unknown committed
2669 2670
  mtr_add_arg($args, "--nodaemon");

unknown's avatar
unknown committed
2671
# > 5.0 { 'character-sets-dir' => \&fix_charset_dir },
unknown's avatar
unknown committed
2672 2673


unknown's avatar
unknown committed
2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685
  my $path_ndbd_log= "$dir/ndbd.log";
  my $proc= My::SafeProcess->new
    (
     name          => $ndbd->after('cluster_config.'),
     path          => $exe_ndbd,
     args          => \$args,
     output        => $path_ndbd_log,
     error         => $path_ndbd_log,
     append        => 1,
     verbose       => $opt_verbose,
    );
  mtr_verbose("Started $proc");
2686

unknown's avatar
unknown committed
2687
  $ndbd->{proc}= $proc;
unknown's avatar
unknown committed
2688

unknown's avatar
unknown committed
2689
  return;
unknown's avatar
unknown committed
2690 2691 2692
}


unknown's avatar
unknown committed
2693
sub ndbcluster_start ($) {
2694
  my ($cluster) = @_;
unknown's avatar
unknown committed
2695

unknown's avatar
unknown committed
2696
  mtr_verbose("ndbcluster_start '".$cluster->name()."'");
unknown's avatar
unknown committed
2697

unknown's avatar
unknown committed
2698
  foreach my $ndb_mgmd ( in_cluster($cluster, ndb_mgmds()) )
2699
  {
unknown's avatar
unknown committed
2700 2701
    next if started($ndb_mgmd);
    ndb_mgmd_start($cluster, $ndb_mgmd);
2702 2703
  }

unknown's avatar
unknown committed
2704
  foreach my $ndbd ( in_cluster($cluster, ndbds()) )
unknown's avatar
unknown committed
2705
  {
unknown's avatar
unknown committed
2706 2707
    next if started($ndbd);
    ndbd_start($cluster, $ndbd);
unknown's avatar
unknown committed
2708 2709
  }

unknown's avatar
unknown committed
2710 2711 2712 2713
  return 0;
}


2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816
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 ) {
      preserve_error_log($mysqld);
      mtr_verbose(" - removing '$datadir'");
      rmtree($datadir);
    }
  }

  my $mysqld_basedir= $mysqld->value('basedir');
  if ( $basedir eq $mysqld_basedir )
  {
    if (! $opt_start_dirty)	# If dirty, keep possibly grown system db
    {
      # Copy datadir from installed system db
      for my $path ( "$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;

  }
  restore_error_log($mysqld);

  # 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
     run_sh_script($tinfo->{master_sh}) )
  {
    $tinfo->{'comment'}= "Failed to execute '$tinfo->{master_sh}'";
    return 1;
  }

  # Run <tname>-slave.sh
  if ($mysqld->option('#!run-slave-sh') and
      run_sh_script($tinfo->{slave_sh}))
  {
    $tinfo->{'comment'}= "Failed to execute '$tinfo->{slave_sh}'";
    return 1;
  }

  if (!$opt_embedded_server)
  {
    my $extra_opts= get_extra_opts($mysqld, $tinfo);
    mysqld_start($mysqld,$extra_opts);

    # Save this test case information, so next can examine it
    $mysqld->{'started_tinfo'}= $tinfo;
  }
}

sub mysql_server_wait {
  my ($mysqld) = @_;

  return not sleep_until_file_created($mysqld->value('pid-file'),
                                      $opt_start_timeout,
                                      $mysqld->{'proc'});
}

unknown's avatar
unknown committed
2817 2818 2819 2820 2821
sub create_config_file_for_extern {
  my %opts=
    (
     socket     => '/tmp/mysqld.sock',
     port       => 3306,
2822
     user       => $opt_user,
unknown's avatar
unknown committed
2823 2824 2825
     password   => '',
     @_
    );
unknown's avatar
unknown committed
2826

unknown's avatar
unknown committed
2827 2828 2829
  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: $!");
unknown's avatar
unknown committed
2830

unknown's avatar
unknown committed
2831 2832 2833 2834
  print $F "[client]\n";
  while (my ($option, $value)= each( %opts )) {
    print $F "$option= $value\n";
    mtr_report(" $option= $value");
unknown's avatar
unknown committed
2835 2836
  }

unknown's avatar
unknown committed
2837
  print $F <<EOF
unknown's avatar
unknown committed
2838

unknown's avatar
unknown committed
2839 2840 2841
# binlog reads from [client] and [mysqlbinlog]
[mysqlbinlog]
character-sets-dir= $path_charsetsdir
2842
local-load= $opt_tmpdir
unknown's avatar
unknown committed
2843

unknown's avatar
unknown committed
2844 2845 2846 2847 2848 2849
# mysql_fix_privilege_tables.sh don't read from [client]
[mysql_fix_privilege_tables]
socket            = $opts{'socket'}
port              = $opts{'port'}
user              = $opts{'user'}
password          = $opts{'password'}
unknown's avatar
unknown committed
2850 2851


unknown's avatar
unknown committed
2852 2853
EOF
;
unknown's avatar
unknown committed
2854

unknown's avatar
unknown committed
2855
  $F= undef; # Close file
unknown's avatar
unknown committed
2856 2857 2858 2859
}


#
unknown's avatar
unknown committed
2860 2861 2862
# Kill processes left from previous runs, normally
# there should be none so make sure to warn
# if there is one
unknown's avatar
unknown committed
2863
#
unknown's avatar
unknown committed
2864 2865 2866
sub kill_leftovers ($) {
  my $rundir= shift;
  return unless ( -d $rundir );
2867

unknown's avatar
unknown committed
2868
  mtr_report("Checking leftover processes...");
unknown's avatar
unknown committed
2869

unknown's avatar
unknown committed
2870 2871 2872 2873
  # 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) )
unknown's avatar
unknown committed
2874
  {
unknown's avatar
unknown committed
2875 2876
    # Only read pid from files that end with .pid
    if ( $elem =~ /.*[.]pid$/ )
2877
    {
unknown's avatar
unknown committed
2878 2879 2880 2881 2882 2883 2884 2885 2886 2887
      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...");
unknown's avatar
unknown committed
2888

2889
      my $ret= kill("KILL", $pid);
unknown's avatar
unknown committed
2890 2891 2892 2893
      if ($ret == 0) {
	mtr_report("   process did not exist!");
	next;
      }
unknown's avatar
unknown committed
2894

unknown's avatar
unknown committed
2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906
      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";
    }
unknown's avatar
unknown committed
2907
  }
unknown's avatar
unknown committed
2908 2909
  closedir(RUNDIR);
}
unknown's avatar
unknown committed
2910

unknown's avatar
unknown committed
2911 2912 2913 2914
#
# Check that all the ports that are going to
# be used are free
#
2915
sub check_ports_free ($)
unknown's avatar
unknown committed
2916
{
2917 2918 2919 2920 2921 2922
  my $bthread= shift;
  my $portbase = $bthread * 10 + 10000;
  for ($portbase..$portbase+9){
    if (mtr_ping_port($_)){
      mtr_report(" - 'localhost:$_' was not free");
      return 0; # One port was not free
unknown's avatar
unknown committed
2923
    }
unknown's avatar
unknown committed
2924 2925
  }

2926
  return 1; # All ports free
unknown's avatar
unknown committed
2927 2928 2929
}


unknown's avatar
unknown committed
2930
sub initialize_servers {
2931

unknown's avatar
unknown committed
2932
  if ( using_extern() )
2933 2934 2935 2936 2937 2938 2939 2940 2941
  {
    # 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
    {
2942
      mtr_verbose("No need to create '$opt_vardir' it already exists");
2943 2944 2945
    }
  }
  else
2946
  {
unknown's avatar
unknown committed
2947 2948 2949
    # Kill leftovers from previous run
    # using any pidfiles found in var/run
    kill_leftovers("$opt_vardir/run");
unknown's avatar
unknown committed
2950

2951
    if ( ! $opt_start_dirty )
2952
    {
2953 2954 2955
      remove_stale_vardir();
      setup_vardir();

Magnus Svensson's avatar
Magnus Svensson committed
2956
      mysql_install_db(default_mysqld(), "$opt_vardir/install.db");
2957
    }
2958
  }
2959 2960
}

unknown's avatar
unknown committed
2961

unknown's avatar
unknown committed
2962
#
2963
# Remove all newline characters expect after semicolon
unknown's avatar
unknown committed
2964
#
2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981
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;
2982
    }
2983

2984 2985 2986 2987 2988 2989 2990
    # 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;
2991
    }
2992

2993 2994 2995 2996
    # Remove comments starting with --
    if ( $line =~ /^\s*--/ ) {
      mtr_debug("Discarded $line");
      next;
2997
    }
unknown's avatar
unknown committed
2998

2999 3000
    # Replace @HOSTNAME with localhost
    $line=~ s/\'\@HOSTNAME\@\'/localhost/;
unknown's avatar
unknown committed
3001

3002 3003 3004
    # Default, just add the line without newline
    # but with a space as separator
    $result.= "$line ";
unknown's avatar
unknown committed
3005

3006 3007
  }
  return $result;
3008 3009 3010
}


Magnus Svensson's avatar
Magnus Svensson committed
3011 3012 3013 3014 3015
sub default_mysqld {
  # Generate new config file from template
  my $config= My::ConfigFactory->new_config
    ( {
       basedir         => $basedir,
3016
       testdir         => $glob_mysql_test_dir,
Magnus Svensson's avatar
Magnus Svensson committed
3017 3018 3019 3020 3021 3022 3023 3024
       template_path   => "include/default_my.cnf",
       vardir          => $opt_vardir,
       tmpdir          => $opt_tmpdir,
       baseport        => 0,
       user            => $opt_user,
       password        => '',
      }
    );
3025

Magnus Svensson's avatar
Magnus Svensson committed
3026 3027 3028
  my $mysqld= $config->group('mysqld.1')
    or mtr_error("Couldn't find mysqld.1 in default config");
  return $mysqld;
3029 3030 3031
}


unknown's avatar
unknown committed
3032
sub mysql_install_db {
Magnus Svensson's avatar
Magnus Svensson committed
3033
  my ($mysqld, $datadir)= @_;
unknown's avatar
unknown committed
3034

Magnus Svensson's avatar
Magnus Svensson committed
3035 3036 3037 3038
  my $install_datadir= $datadir || $mysqld->value('datadir');
  my $install_basedir= $mysqld->value('basedir');
  my $install_lang= $mysqld->value('language');
  my $install_chsdir= $mysqld->value('character-sets-dir');
unknown's avatar
unknown committed
3039

unknown's avatar
unknown committed
3040
  mtr_report("Installing system database...");
unknown's avatar
unknown committed
3041

3042
  my $args;
unknown's avatar
unknown committed
3043 3044 3045
  mtr_init_args(\$args);
  mtr_add_arg($args, "--no-defaults");
  mtr_add_arg($args, "--bootstrap");
Magnus Svensson's avatar
Magnus Svensson committed
3046 3047
  mtr_add_arg($args, "--basedir=%s", $install_basedir);
  mtr_add_arg($args, "--datadir=%s", $install_datadir);
unknown's avatar
unknown committed
3048
  mtr_add_arg($args, "--loose-skip-innodb");
3049
  mtr_add_arg($args, "--loose-skip-pbxt");
unknown's avatar
unknown committed
3050
  mtr_add_arg($args, "--loose-skip-ndbcluster");
Sergei Golubchik's avatar
Sergei Golubchik committed
3051
  mtr_add_arg($args, "--loose-skip-aria");
unknown's avatar
unknown committed
3052 3053
  mtr_add_arg($args, "--disable-sync-frm");
  mtr_add_arg($args, "--loose-disable-debug");
3054
  mtr_add_arg($args, "--tmpdir=%s", "$opt_vardir/tmp/");
3055
  mtr_add_arg($args, "--core-file");
unknown's avatar
unknown committed
3056

3057 3058
  if ( $opt_debug )
  {
unknown's avatar
unknown committed
3059 3060
    mtr_add_arg($args, "--debug=d:t:i:A,%s/log/bootstrap.trace",
		$path_vardir_trace);
3061 3062
  }

Magnus Svensson's avatar
Magnus Svensson committed
3063 3064
  mtr_add_arg($args, "--language=%s", $install_lang);
  mtr_add_arg($args, "--character-sets-dir=%s", $install_chsdir);
unknown's avatar
unknown committed
3065

3066 3067 3068 3069 3070
  # 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.
Magnus Svensson's avatar
Magnus Svensson committed
3071 3072
  my $exe_mysqld_bootstrap =
    $ENV{'MYSQLD_BOOTSTRAP'} || find_mysqld($install_basedir);
3073

3074 3075 3076 3077
  # MASV add only to bootstrap.test
  # Setup args for bootstrap.test
  #
  #mtr_init_args(\$cmd_args);
Sergei Golubchik's avatar
Sergei Golubchik committed
3078
  #mtr_add_arg($cmd_args, "--loose-skip-aria")
3079

3080 3081 3082 3083 3084
  # ----------------------------------------------------------------------
  # export MYSQLD_BOOTSTRAP_CMD variable containing <path>/mysqld <args>
  # ----------------------------------------------------------------------
  $ENV{'MYSQLD_BOOTSTRAP_CMD'}= "$exe_mysqld_bootstrap " . join(" ", @$args);

Magnus Svensson's avatar
Magnus Svensson committed
3085

3086

3087 3088 3089
  # ----------------------------------------------------------------------
  # Create the bootstrap.sql file
  # ----------------------------------------------------------------------
3090
  my $bootstrap_sql_file= "$opt_vardir/tmp/bootstrap.sql";
3091

Magnus Svensson's avatar
Magnus Svensson committed
3092
  my $path_sql= my_find_file($install_basedir,
3093 3094
			     ["mysql", "sql/share", "share/mariadb",
			      "share/mysql", "share", "scripts"],
Magnus Svensson's avatar
Magnus Svensson committed
3095 3096 3097 3098
			     "mysql_system_tables.sql",
			     NOT_REQUIRED);

  if (-f $path_sql )
3099
  {
Magnus Svensson's avatar
Magnus Svensson committed
3100
    my $sql_dir= dirname($path_sql);
3101 3102
    # Use the mysql database for system tables
    mtr_tofile($bootstrap_sql_file, "use mysql\n");
3103

3104 3105
    # Add the offical mysql system tables
    # for a production system
Magnus Svensson's avatar
Magnus Svensson committed
3106
    mtr_appendfile_to_file("$sql_dir/mysql_system_tables.sql",
3107
			   $bootstrap_sql_file);
3108

3109 3110
    # Add the mysql system tables initial data
    # for a production system
Magnus Svensson's avatar
Magnus Svensson committed
3111
    mtr_appendfile_to_file("$sql_dir/mysql_system_tables_data.sql",
3112
			   $bootstrap_sql_file);
3113

3114 3115 3116
    # 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
Magnus Svensson's avatar
Magnus Svensson committed
3117 3118
    mtr_appendfile_to_file("$sql_dir/mysql_test_data_timezone.sql",
			   $bootstrap_sql_file);
3119

Magnus Svensson's avatar
Magnus Svensson committed
3120 3121 3122 3123
    # 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",
3124
			   $bootstrap_sql_file);
3125

3126 3127 3128 3129 3130
  }
  else
  {
    # Install db from init_db.sql that exist in early 5.1 and 5.0
    # versions of MySQL
Magnus Svensson's avatar
Magnus Svensson committed
3131
    my $init_file= "$install_basedir/mysql-test/lib/init_db.sql";
3132 3133 3134
    mtr_report(" - from '$init_file'");
    my $text= mtr_grab_file($init_file) or
      mtr_error("Can't open '$init_file': $!");
3135

3136 3137 3138
    mtr_tofile($bootstrap_sql_file,
	       sql_to_bootstrap($text));
  }
3139

3140
  # Remove anonymous users
3141
  mtr_tofile($bootstrap_sql_file,
unknown's avatar
unknown committed
3142 3143 3144 3145 3146
	     "DELETE FROM mysql.user where user= '';\n");

  # Create mtr database
  mtr_tofile($bootstrap_sql_file,
	     "CREATE DATABASE mtr;\n");
3147

3148 3149 3150 3151
  # 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")));

3152 3153 3154
  # Add procedures for checking server is restored after testcase
  mtr_tofile($bootstrap_sql_file,
             sql_to_bootstrap(mtr_grab_file("include/mtr_check.sql")));
3155

3156 3157 3158
  # Log bootstrap command
  my $path_bootstrap_log= "$opt_vardir/log/bootstrap.log";
  mtr_tofile($path_bootstrap_log,
3159
	     "$exe_mysqld_bootstrap " . join(" ", @$args) . "\n");
3160

unknown's avatar
unknown committed
3161
  # Create directories mysql and test
Magnus Svensson's avatar
Magnus Svensson committed
3162 3163
  mkpath("$install_datadir/mysql");
  mkpath("$install_datadir/test");
unknown's avatar
unknown committed
3164 3165 3166 3167 3168 3169 3170 3171 3172 3173

  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,
3174
	verbose       => $opt_verbose,
unknown's avatar
unknown committed
3175
       ) != 0)
unknown's avatar
unknown committed
3176
  {
unknown's avatar
unknown committed
3177
    mtr_error("Error executing mysqld --bootstrap\n" .
3178 3179
              "Could not install system database from $bootstrap_sql_file\n" .
	      "see $path_bootstrap_log for errors");
unknown's avatar
unknown committed
3180 3181 3182 3183
  }
}


3184 3185 3186
sub run_testcase_check_skip_test($)
{
  my ($tinfo)= @_;
3187

3188 3189 3190 3191
  # ----------------------------------------------------------------------
  # Skip some tests silently
  # ----------------------------------------------------------------------

Michael Widenius's avatar
Michael Widenius committed
3192 3193
  my $start_from= $mtr_cases::start_from;
  if ( $start_from )
3194
  {
Michael Widenius's avatar
Michael Widenius committed
3195 3196
    if ($tinfo->{'name'} eq $start_from ||
        $tinfo->{'shortname'} eq $start_from)
3197 3198
    {
      ## Found parting test. Run this test and all tests after this one
Michael Widenius's avatar
Michael Widenius committed
3199
      $mtr_cases::start_from= "";
3200 3201 3202 3203 3204 3205 3206 3207
    }
    else
    {
      $tinfo->{'result'}= 'MTR_RES_SKIPPED';
      return 1;
    }
  }

unknown's avatar
unknown committed
3208 3209 3210 3211 3212 3213 3214 3215 3216
  # ----------------------------------------------------------------------
  # 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'} )
  {
3217
    mtr_report_test_skipped($tinfo) unless $start_only;
3218
    return 1;
unknown's avatar
unknown committed
3219 3220
  }

unknown's avatar
unknown committed
3221 3222
  return 0;
}
unknown's avatar
unknown committed
3223

unknown's avatar
unknown committed
3224

3225 3226
sub run_query {
  my ($tinfo, $mysqld, $query)= @_;
3227

3228 3229 3230 3231
  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'));
unknown's avatar
unknown committed
3232

3233 3234
  mtr_add_arg($args, "-e %s", $query);

3235 3236
  my $res= My::SafeProcess->run
    (
3237
     name          => "run_query -> ".$mysqld->name(),
3238 3239
     path          => $exe_mysql,
     args          => \$args,
3240 3241
     output        => '/dev/null',
     error         => '/dev/null'
unknown's avatar
unknown committed
3242 3243
    );

3244
  return $res
3245
}
unknown's avatar
unknown committed
3246

unknown's avatar
unknown committed
3247

3248 3249 3250 3251
sub do_before_run_mysqltest($)
{
  my $tinfo= shift;

3252
  # Remove old files produced by mysqltest
3253 3254 3255 3256 3257 3258 3259 3260
  my $base_file= mtr_match_extension($tinfo->{result_file},
				     "result"); # Trim extension
  if (defined $base_file ){
    unlink("$base_file.reject");
    unlink("$base_file.progress");
    unlink("$base_file.log");
    unlink("$base_file.warnings");
  }
3261

unknown's avatar
unknown committed
3262 3263 3264 3265 3266 3267 3268 3269
  if ( $mysql_version_id < 50000 ) {
    # Set environment variable NDB_STATUS_OK to 1
    # if script decided to run mysqltest cluster _is_ installed ok
    $ENV{'NDB_STATUS_OK'} = "1";
  } elsif ( $mysql_version_id < 50100 ) {
    # Set environment variable NDB_STATUS_OK to YES
    # if script decided to run mysqltest cluster _is_ installed ok
    $ENV{'NDB_STATUS_OK'} = "YES";
3270
  }
3271
}
unknown's avatar
unknown committed
3272

unknown's avatar
unknown committed
3273

3274 3275 3276 3277 3278 3279 3280
#
# Check all server for sideffects
#
# RETURN VALUE
#  0 ok
#  1 Check failed
#  >1 Fatal errro
3281

3282
sub check_testcase($$)
3283
{
unknown's avatar
unknown committed
3284
  my ($tinfo, $mode)= @_;
3285
  my $tname= $tinfo->{name};
3286

3287 3288 3289
  # 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;
unknown's avatar
unknown committed
3290
  foreach my $mysqld ( mysqlds() )
3291
  {
3292 3293
    # Skip if server has been restarted with additional options
    if ( defined $mysqld->{'proc'} && ! exists $mysqld->{'restart_opts'} )
unknown's avatar
unknown committed
3294
    {
3295 3296 3297
      my $proc= start_check_testcase($tinfo, $mode, $mysqld);
      $started{$proc->pid()}= $proc;
    }
3298 3299
  }

3300 3301
  # Return immediately if no check proceess was started
  return 0 unless ( keys %started );
3302

3303
  my $timeout= start_timer(check_timeout());
3304

3305 3306
  while (1){
    my $result;
3307
    my $proc= My::SafeProcess->wait_any_timeout($timeout);
3308
    mtr_report("Got $proc");
3309

3310
    if ( delete $started{$proc->pid()} ) {
3311 3312 3313 3314

      my $err_file= $proc->user_data();
      my $base_file= mtr_match_extension($err_file, "err"); # Trim extension

3315 3316 3317 3318 3319 3320
      # One check testcase process returned
      my $res= $proc->exit_status();

      if ( $res == 0){
	# Check completed without problem

3321 3322 3323
	# Remove the .err file the check generated
	unlink($err_file);

3324 3325 3326 3327 3328
	# Remove the .result file the check generated
	if ( $mode eq 'after' ){
	  unlink("$base_file.result");
	}

3329 3330 3331 3332 3333 3334 3335 3336
	if ( keys(%started) == 0){
	  # All checks completed
	  return 0;
	}
	# Wait for next process to exit
	next;
      }
      else
unknown's avatar
unknown committed
3337
      {
3338 3339 3340
	if ( $mode eq "after" and $res == 1 )
	{
	  # Test failed, grab the report mysqltest has created
3341
	  my $report= mtr_grab_file($err_file);
3342
	  $tinfo->{check}.=
3343 3344 3345 3346 3347 3348
	    "\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.
This is the diff of the states of the servers before and after the
test case was executed:\n";
3349 3350 3351 3352 3353 3354 3355 3356
	  $tinfo->{check}.= $report;

	  # Check failed, mark the test case with that info
	  $tinfo->{'check_testcase_failed'}= 1;
	  $result= 1;
	}
	elsif ( $res )
	{
3357
	  my $report= mtr_grab_file($err_file);
3358
	  $tinfo->{comment}.=
3359 3360
	    "Could not execute 'check-testcase' $mode ".
	      "testcase '$tname' (res: $res):\n";
3361 3362 3363 3364
	  $tinfo->{comment}.= $report;

	  $result= 2;
	}
Michael Widenius's avatar
Michael Widenius committed
3365 3366 3367 3368 3369
        else
        {
          # Remove the .result file the check generated
          unlink("$base_file.result");
        }
3370 3371 3372
	# Remove the .err file the check generated
	unlink($err_file);

unknown's avatar
unknown committed
3373 3374
      }
    }
3375 3376 3377
    elsif ( $proc->{timeout} ) {
      $tinfo->{comment}.= "Timeout for 'check-testcase' expired after "
	.check_timeout()." seconds";
3378 3379
      $result= 4;
    }
3380 3381 3382
    else {
      # Unknown process returned, most likley a crash, abort everything
      $tinfo->{comment}=
3383
	"The server $proc crashed while running ".
3384 3385
	"'check testcase $mode test'".
	get_log_from_proc($proc, $tinfo->{name});
3386 3387 3388 3389 3390 3391 3392
      $result= 3;
    }

    # Kill any check processes still running
    map($_->kill(), values(%started));

    return $result;
3393
  }
3394 3395

  mtr_error("INTERNAL_ERROR: check_testcase");
unknown's avatar
unknown committed
3396
}
3397

3398

3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428
# 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, "--skip-safemalloc");
  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,
Magnus Svensson's avatar
Magnus Svensson committed
3429
     verbose       => $opt_verbose,
3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462
    );
  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 );

3463
  my $timeout= start_timer(check_timeout());
3464 3465 3466

  while (1){
    my $result;
3467
    my $proc= My::SafeProcess->wait_any_timeout($timeout);
3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491
    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;
    }
3492 3493 3494
    elsif ($proc->{timeout}) {
      $tinfo->{comment}.= "Timeout for '$run' expired after "
	.check_timeout()." seconds";
3495 3496 3497 3498
    }
    else {
      # Unknown process returned, most likley a crash, abort everything
      $tinfo->{comment}.=
3499 3500
	"The server $proc crashed while running '$run'".
	get_log_from_proc($proc, $tinfo->{name});
3501 3502 3503 3504 3505 3506 3507
    }

    # Kill any check processes still running
    map($_->kill(), values(%started));

    return 1;
  }
3508
  mtr_error("INTERNAL_ERROR: run_on_all");
3509 3510 3511
}


unknown's avatar
unknown committed
3512 3513 3514
sub mark_log {
  my ($log, $tinfo)= @_;
  my $log_msg= "CURRENT_TEST: $tinfo->{name}\n";
3515
  pre_write_errorlog($log, $tinfo->{name});
unknown's avatar
unknown committed
3516
  mtr_tofile($log, $log_msg);
3517 3518
}

unknown's avatar
unknown committed
3519

3520 3521 3522 3523
sub find_testcase_skipped_reason($)
{
  my ($tinfo)= @_;

3524 3525 3526
  # Set default message
  $tinfo->{'comment'}= "Detected by testcase(no log file)";

3527 3528
  # Open the test log file
  my $F= IO::File->new($path_current_testlog)
3529
    or return;
3530 3531 3532 3533
  my $reason;

  while ( my $line= <$F> )
  {
unknown's avatar
unknown committed
3534
    # Look for "reason: <reason for skipping test>"
3535
    if ( $line =~ /reason: (.*)/ )
unknown's avatar
unknown committed
3536
    {
3537 3538 3539
      $reason= $1;
    }
  }
3540

3541 3542
  if ( ! $reason )
  {
3543
    mtr_warning("Could not find reason for skipping test in $path_current_testlog");
3544
    $reason= "Detected by testcase(reason unknown) ";
3545
  }
3546 3547 3548 3549
  $tinfo->{'comment'}= $reason;
}


3550 3551 3552 3553 3554 3555
sub find_analyze_request
{
  # Open the test log file
  my $F= IO::File->new($path_current_testlog)
    or return;
  my $analyze;
3556

3557 3558 3559 3560 3561 3562 3563 3564
  while ( my $line= <$F> )
  {
    # Look for "reason: <reason for skipping test>"
    if ( $line =~ /analyze: (.*)/ )
    {
      $analyze= $1;
    }
  }
3565

3566 3567 3568 3569
  return $analyze;
}


3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589
# The test can leave a file in var/tmp/ to signal
# that all servers should be restarted
sub restart_forced_by_test
{
  my $restart = 0;
  foreach my $mysqld ( mysqlds() )
  {
    my $datadir = $mysqld->value('datadir');
    my $force_restart_file = "$datadir/mtr/force_restart";
    if ( -f $force_restart_file )
    {
      mtr_verbose("Restart of servers forced by test");
      $restart = 1;
      last;
    }
  }
  return $restart;
}


unknown's avatar
unknown committed
3590 3591 3592
# Return timezone value of tinfo or default value
sub timezone {
  my ($tinfo)= @_;
3593 3594
  local $_ = $tinfo->{timezone};
  return 'DEFAULT' unless defined $_;
Sergei Golubchik's avatar
Sergei Golubchik committed
3595 3596 3597
  no warnings 'uninitialized';
  s/\$\{(\w+)\}/$ENV{$1}/ge;
  s/\$(\w+)/$ENV{$1}/ge;
3598
  $_;
unknown's avatar
unknown committed
3599
}
3600

3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662
sub mycnf_create {
  my ($config) = @_;
  my $res;

  foreach my $group ($config->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,
    $suites{$tinfo->{suite}}->config_files()
  );
}

sub _like   { return $config ? $config->like($_[0]) : (); }
sub mysqlds { return _like('mysqld\.'); }
sub ndbds   { return _like('cluster_config\.ndbd\.');}
sub ndb_mgmds { return _like('cluster_config\.ndb_mgmd\.'); }

sub fix_servers($) {
  my ($tinfo) = @_;
  return () unless $config;
  my %servers = (
    qr/mysqld\./ => {
      SORT => 300,
      START => \&mysql_server_start,
      WAIT => \&mysql_server_wait,
    },
    qr/mysql_cluster\./ => {
      SORT => 200,
      START => \&ndbcluster_start,
      WAIT => \&ndbcluster_wait_started,
    },
    qr/cluster_config\.ndb_mgmd\./ => {
      SORT => 210,
      START => undef,
    },
    qr/cluster_config\.ndbd\./ => {
      SORT => 220,
      START => undef,
    },
    $suites{$tinfo->{suite}}->servers()
  );
  for ($config->groups()) {
    while (my ($re,$prop) = each %servers) {
      @$_{keys %$prop} = values %$prop if $_->{name} =~ /^$re/;
    }
  }
unknown's avatar
unknown committed
3663
}
3664

3665 3666 3667 3668 3669
sub all_servers {
  return unless $config;
  ( sort { $a->{SORT} <=> $b->{SORT} }
       grep { defined $_->{SORT} } $config->groups() );
}
3670

unknown's avatar
unknown committed
3671 3672
# Storage for changed environment variables
my %old_env;
3673

unknown's avatar
unknown committed
3674 3675 3676
#
# Run a single test case
#
unknown's avatar
unknown committed
3677 3678 3679 3680
# RETURN VALUE
#  0 OK
#  > 0 failure
#
3681

3682 3683
sub run_testcase ($$) {
  my ($tinfo, $server_socket)= @_;
3684

unknown's avatar
unknown committed
3685 3686
  mtr_verbose("Running test:", $tinfo->{name});

3687 3688
  # Allow only alpanumerics pluss _ - + . in combination names,
  # or anything beginning with -- (the latter comes from --combination)
3689
  my $combination= $tinfo->{combination};
3690 3691
  if ($combination && $combination !~ /^\w[-\w\.\+]+$/
                   && $combination !~ /^--/)
3692 3693 3694
  {
    mtr_error("Combination '$combination' contains illegal characters");
  }
3695 3696 3697
  # -------------------------------------------------------
  # Init variables that can change between each test case
  # -------------------------------------------------------
unknown's avatar
unknown committed
3698
  my $timezone= timezone($tinfo);
3699 3700
  if ($timezone ne 'DEFAULT') {
    $ENV{'TZ'}= $timezone;
3701 3702
  } else {
    delete($ENV{'TZ'});
3703
  }
unknown's avatar
unknown committed
3704
  mtr_verbose("Setting timezone: $timezone");
3705

unknown's avatar
unknown committed
3706
  if ( ! using_extern() )
3707
  {
unknown's avatar
unknown committed
3708 3709
    my @restart= servers_need_restart($tinfo);
    if ( @restart != 0) {
3710 3711
      # Remember that we restarted for this test case (count restarts)
      $tinfo->{'restarted'}= 1;
3712
      stop_servers(reverse @restart);
3713 3714 3715
      if ($opt_warnings) {
        check_warnings_post_shutdown($server_socket);
      }
3716
    }
unknown's avatar
unknown committed
3717

unknown's avatar
unknown committed
3718 3719
    if ( started(all_servers()) == 0 )
    {
3720

3721
      # Remove old datadirs
3722
      clean_datadir() unless $opt_start_dirty;
3723

unknown's avatar
unknown committed
3724 3725 3726 3727 3728
      # Restore old ENV
      while (my ($option, $value)= each( %old_env )) {
	if (defined $value){
	  mtr_verbose("Restoring $option to $value");
	  $ENV{$option}= $value;
Sven Sandberg's avatar
Sven Sandberg committed
3729

unknown's avatar
unknown committed
3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742
	} 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
	( {
	   basedir         => $basedir,
3743
	   testdir         => $glob_mysql_test_dir,
unknown's avatar
unknown committed
3744 3745 3746 3747
	   template_path   => $tinfo->{template_path},
	   extra_template_path => $tinfo->{extra_template_path},
	   vardir          => $opt_vardir,
	   tmpdir          => $opt_tmpdir,
3748
	   baseport        => $baseport,
unknown's avatar
unknown committed
3749 3750
	   user            => $opt_user,
	   password        => '',
3751
	   ssl             => $opt_ssl_supported,
unknown's avatar
unknown committed
3752
	   embedded        => $opt_embedded_server,
unknown's avatar
unknown committed
3753 3754
	  }
	);
3755

3756 3757 3758 3759 3760 3761 3762 3763 3764 3765
      fix_servers($tinfo);

      # Write config files:
      my %config_files = config_files($tinfo);
      while (my ($file, $generate) = each %config_files) {
        my ($path) = "$opt_vardir/$file";
        open (F, '>', $path) or die "Could not open '$path': $!";
        print F &$generate($config);
        close F;
      }
3766

unknown's avatar
unknown committed
3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784
      # 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"))
      {
	# Save old value to restore it before next time
	$old_env{$option->name()}= $ENV{$option->name()};

	mtr_verbose($option->name(), "=",$option->value());
	$ENV{$option->name()}= $option->value();
      }
    }

    # Write start of testcase to log
3785
    mark_log($path_current_testlog, $tinfo);
unknown's avatar
unknown committed
3786

Sergei Golubchik's avatar
Sergei Golubchik committed
3787 3788 3789 3790 3791
    # Make sure the safe_process also exits from now on
    if ($opt_start_exit) {
      My::SafeProcess->start_exit();
    }

unknown's avatar
unknown committed
3792
    if (start_servers($tinfo))
unknown's avatar
unknown committed
3793
    {
3794 3795
      report_failure_and_restart($tinfo);
      return 1;
unknown's avatar
unknown committed
3796
    }
3797
  }
unknown's avatar
unknown committed
3798

unknown's avatar
unknown committed
3799 3800
  # --------------------------------------------------------------------
  # If --start or --start-dirty given, stop here to let user manually
3801
  # run tests
3802 3803
  # If --wait-all is also given, do the same, but don't die if one
  # server exits
unknown's avatar
unknown committed
3804
  # ----------------------------------------------------------------------
3805

3806
  if ( $start_only )
unknown's avatar
unknown committed
3807
  {
unknown's avatar
unknown committed
3808
    mtr_print("\nStarted", started(all_servers()));
3809 3810 3811 3812 3813 3814 3815
    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'));
    }
3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827
    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);
      }
    }
unknown's avatar
unknown committed
3828
    mtr_print("Waiting for server(s) to exit...");
3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841
    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");
3842
      exit(1);
Vladislav Vaintroub's avatar
Vladislav Vaintroub committed
3843
    }
unknown's avatar
unknown committed
3844 3845
  }

3846
  my $test_timeout= start_timer(testcase_timeout());
unknown's avatar
unknown committed
3847 3848 3849

  do_before_run_mysqltest($tinfo);

3850 3851 3852
  if ( $opt_check_testcases and check_testcase($tinfo, "before") ){
    # Failed to record state of server or server crashed
    report_failure_and_restart($tinfo);
unknown's avatar
unknown committed
3853

3854
    return 1;
unknown's avatar
unknown committed
3855
  }
3856

unknown's avatar
unknown committed
3857
  my $test= start_mysqltest($tinfo);
3858 3859
  # Set only when we have to keep waiting after expectedly died server
  my $keep_waiting_proc = 0;
3860

unknown's avatar
unknown committed
3861 3862
  while (1)
  {
3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874
    my $proc;
    if ($keep_waiting_proc)
    {
      # Any other process exited?
      $proc = My::SafeProcess->check_any();
      if ($proc)
      {
	mtr_verbose ("Found exited process $proc");
      }
      else
      {
	$proc = $keep_waiting_proc;
3875 3876 3877 3878 3879
	# Also check if timer has expired, if so cancel waiting
	if ( has_expired($test_timeout) )
	{
	  $keep_waiting_proc = 0;
	}
3880 3881
      }
    }
3882
    if (! $keep_waiting_proc)
3883
    {
3884
      $proc= My::SafeProcess->wait_any_timeout($test_timeout);
3885 3886 3887 3888 3889
    }

    # Will be restored if we need to keep waiting
    $keep_waiting_proc = 0;

unknown's avatar
unknown committed
3890
    unless ( defined $proc )
unknown's avatar
unknown committed
3891
    {
unknown's avatar
unknown committed
3892
      mtr_error("wait_any failed");
unknown's avatar
unknown committed
3893
    }
unknown's avatar
unknown committed
3894 3895 3896 3897 3898 3899
    mtr_verbose("Got $proc");

    # ----------------------------------------------------
    # Was it the test program that exited
    # ----------------------------------------------------
    if ($proc eq $test)
unknown's avatar
unknown committed
3900
    {
unknown's avatar
unknown committed
3901 3902
      my $res= $test->exit_status();

3903
      if ($res == 0 and $opt_warnings and check_warnings($tinfo) )
unknown's avatar
unknown committed
3904
      {
3905 3906 3907 3908
	# Test case suceeded, but it has produced unexpected
	# warnings, continue in $res == 1
	$res= 1;
      }
unknown's avatar
unknown committed
3909

3910 3911
      if ( $res == 0 )
      {
3912
	my $check_res;
3913 3914
	if ( restart_forced_by_test() )
	{
3915
	  stop_all_servers($opt_shutdown_timeout);
3916 3917
	}
	elsif ( $opt_check_testcases and
3918
	     $check_res= check_testcase($tinfo, "after"))
unknown's avatar
unknown committed
3919
	{
3920 3921
	  if ($check_res == 1) {
	    # Test case had sideeffects, not fatal error, just continue
3922 3923 3924
            if ($opt_warnings) {
              # Checking error logs for warnings, so need to stop server
              # gracefully so that memory leaks etc. can be properly detected.
3925
              stop_servers(reverse all_servers());
3926 3927 3928 3929 3930 3931
              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.
3932
	      stop_all_servers($opt_shutdown_timeout);
3933
            }
3934 3935 3936 3937 3938 3939 3940
	    mtr_report("Resuming tests...\n");
	  }
	  else {
	    # Test case check failed fatally, probably a server crashed
	    report_failure_and_restart($tinfo);
	    return 1;
	  }
unknown's avatar
unknown committed
3941
	}
3942
	mtr_report_test_passed($tinfo);
unknown's avatar
unknown committed
3943 3944 3945 3946 3947
      }
      elsif ( $res == 62 )
      {
	# Testcase itself tell us to skip this one
	$tinfo->{skip_detected_by_test}= 1;
3948
	# Try to get reason from test log file
unknown's avatar
unknown committed
3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960
	find_testcase_skipped_reason($tinfo);
	mtr_report_test_skipped($tinfo);
      }
      elsif ( $res == 65 )
      {
	# Testprogram killed by signal
	$tinfo->{comment}=
	  "testprogram crashed(returned code $res)";
	report_failure_and_restart($tinfo);
      }
      elsif ( $res == 1 )
      {
3961 3962 3963 3964 3965 3966 3967
	# 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");
	}

3968 3969 3970 3971 3972 3973 3974 3975
	# 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;
	}

unknown's avatar
unknown committed
3976 3977 3978 3979 3980 3981 3982
	# Test case failure reported by mysqltest
	report_failure_and_restart($tinfo);
      }
      else
      {
	# mysqltest failed, probably crashed
	$tinfo->{comment}=
3983
	  "mysqltest failed with unexpected return code $res\n";
unknown's avatar
unknown committed
3984 3985 3986 3987
	report_failure_and_restart($tinfo);
      }

      # Save info from this testcase run to mysqltest.log
3988 3989 3990 3991 3992
      if( -f $path_current_testlog)
      {
	mtr_appendfile_to_file($path_current_testlog, $path_testlog);
	unlink($path_current_testlog);
      }
unknown's avatar
unknown committed
3993

unknown's avatar
unknown committed
3994
      return ($res == 62) ? 0 : $res;
3995

unknown's avatar
unknown committed
3996
    }
unknown's avatar
unknown committed
3997 3998 3999 4000

    # ----------------------------------------------------
    # Check if it was an expected crash
    # ----------------------------------------------------
4001
    SRVDIED:
4002 4003
    my $check_crash = check_expected_crash_and_restart($proc);
    if ($check_crash)
4004
    {
4005 4006 4007
      # Keep waiting if it returned 2, if 1 don't wait or stop waiting.
      $keep_waiting_proc = 0 if $check_crash == 1;
      $keep_waiting_proc = $proc if $check_crash == 2;
unknown's avatar
unknown committed
4008
      next;
4009
    }
unknown's avatar
unknown committed
4010

4011 4012 4013
    # ----------------------------------------------------
    # Stop the test case timer
    # ----------------------------------------------------
4014
    $test_timeout= 0;
4015

unknown's avatar
unknown committed
4016 4017 4018 4019
    # ----------------------------------------------------
    # Check if it was a server that died
    # ----------------------------------------------------
    if ( grep($proc eq $_, started(all_servers())) )
unknown's avatar
unknown committed
4020
    {
unknown's avatar
unknown committed
4021 4022
      # Server failed, probably crashed
      $tinfo->{comment}=
4023 4024
	"Server $proc failed during test run" .
	get_log_from_proc($proc, $tinfo->{name});
unknown's avatar
unknown committed
4025

4026 4027 4028 4029 4030
      # ----------------------------------------------------
      # It's not mysqltest that has exited, kill it
      # ----------------------------------------------------
      $test->kill();

unknown's avatar
unknown committed
4031
      report_failure_and_restart($tinfo);
unknown's avatar
unknown committed
4032
      return 1;
unknown's avatar
unknown committed
4033
    }
unknown's avatar
unknown committed
4034

4035 4036
    # Try to dump core for mysqltest and all servers
    foreach my $proc ($test, started(all_servers())) 
unknown's avatar
unknown committed
4037
    {
4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049
      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();

unknown's avatar
unknown committed
4050 4051 4052
    # ----------------------------------------------------
    # Check if testcase timer expired
    # ----------------------------------------------------
4053
    if ( $proc->{timeout} )
unknown's avatar
unknown committed
4054
    {
Serge Kozlov's avatar
Serge Kozlov committed
4055
      my $log_file_name= $opt_vardir."/log/".$tinfo->{shortname}.".log";
unknown's avatar
unknown committed
4056
      $tinfo->{comment}=
4057 4058
        "Test case timeout after ".testcase_timeout().
	  " seconds\n\n";
4059
      # Add 20 last executed commands from test case log file
Serge Kozlov's avatar
Serge Kozlov committed
4060 4061 4062
      if  (-e $log_file_name)
      {
        $tinfo->{comment}.=
4063 4064
	   "== $log_file_name == \n".
	     mtr_lastlinesfromfile($log_file_name, 20)."\n";
Serge Kozlov's avatar
Serge Kozlov committed
4065
      }
4066
      $tinfo->{'timeout'}= testcase_timeout(); # Mark as timeout
4067
      run_on_all($tinfo, 'analyze-timeout');
4068

unknown's avatar
unknown committed
4069
      report_failure_and_restart($tinfo);
unknown's avatar
unknown committed
4070
      return 1;
unknown's avatar
unknown committed
4071
    }
unknown's avatar
unknown committed
4072

unknown's avatar
unknown committed
4073
    mtr_error("Unhandled process $proc exited");
4074
  }
unknown's avatar
unknown committed
4075
  mtr_error("Should never come here");
unknown's avatar
unknown committed
4076
}
unknown's avatar
unknown committed
4077

4078

4079 4080 4081 4082
# We want to preserve the error log between server restarts, as it may contain
# valuable debugging information even if there is no test failure recorded.
sub _preserve_error_log_names {
  my ($mysqld)= @_;
4083
  my $error_log_file= $mysqld->if_exist('#log-error');
4084
  return (undef, undef) unless $error_log_file;
4085 4086 4087 4088 4089 4090 4091 4092
  my $error_log_dir= dirname($error_log_file);
  my $save_name= $error_log_dir ."/../". $mysqld->name() .".error.log";
  return ($error_log_file, $save_name);
}

sub preserve_error_log {
  my ($mysqld)= @_;
  my ($error_log_file, $save_name)= _preserve_error_log_names($mysqld);
4093
  rename($error_log_file, $save_name) if $save_name;
4094 4095 4096 4097 4098 4099
  # Ignore any errors, as it's just a best-effort to keep the log if possible.
}

sub restore_error_log {
  my ($mysqld)= @_;
  my ($error_log_file, $save_name)= _preserve_error_log_names($mysqld);
4100
  rename($save_name, $error_log_file) if $save_name;
4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137
}

# 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.
my $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}= [];
    }
  }
}

4138 4139
# Extract server log from after the last occurrence of named test
# Return as an array of lines
4140
#
4141 4142

sub extract_server_log ($$) {
4143
  my ($error_log, $tname) = @_;
4144 4145
  
  return unless $error_log;
Magnus Svensson's avatar
Magnus Svensson committed
4146 4147

  # Open the servers .err log file and read all lines
4148
  # belonging to current test into @lines
Magnus Svensson's avatar
Magnus Svensson committed
4149
  my $Ferr = IO::File->new($error_log)
4150
    or mtr_error("Could not open file '$error_log' for reading: $!");
4151

4152 4153 4154
  my @lines;
  my $found_test= 0;		# Set once we've found the log of this test
  while ( my $line = <$Ferr> )
4155
  {
4156
    if ($found_test)
Magnus Svensson's avatar
Magnus Svensson committed
4157
    {
4158 4159 4160 4161 4162
      # If test wasn't last after all, discard what we found, test again.
      if ( $line =~ /^CURRENT_TEST:/)
      {
	@lines= ();
	$found_test= $line =~ /^CURRENT_TEST: $tname/;
Magnus Svensson's avatar
Magnus Svensson committed
4163
      }
4164 4165 4166
      else
      {
	push(@lines, $line);
Magnus Svensson's avatar
Magnus Svensson committed
4167 4168
      }
    }
4169 4170 4171 4172 4173
    else
    {
      # Search for beginning of test, until found
      $found_test= 1 if ($line =~ /^CURRENT_TEST: $tname/);
    }
Magnus Svensson's avatar
Magnus Svensson committed
4174
  }
4175 4176
  $Ferr = undef; # Close error log file

4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187
  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= "";

4188
  foreach my $mysqld (all_servers()) {
4189
    if ($mysqld->{proc} eq $proc) {
4190
      my @srv_lines= extract_server_log($mysqld->if_exist('#log-error'), $name);
4191 4192 4193 4194 4195 4196
      $srv_log= "\nServer log from this test:\n" . join ("", @srv_lines);
      last;
    }
  }
  return $srv_log;
}
Magnus Svensson's avatar
Magnus Svensson committed
4197

4198
#
4199 4200 4201 4202
# Perform a rough examination of the servers
# error log and write all lines that look
# suspicious into $error_log.warnings
#
4203 4204
sub extract_warning_lines ($) {
  my ($error_log) = @_;
4205

4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237
  # 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";
      }
    }
  }
Magnus Svensson's avatar
Magnus Svensson committed
4238

4239
  # Write all suspicious lines to $error_log.warnings file
Magnus Svensson's avatar
Magnus Svensson committed
4240 4241 4242 4243 4244 4245 4246
  my $warning_log = "$error_log.warnings";
  my $Fwarn = IO::File->new($warning_log, "w")
    or die("Could not open file '$warning_log' for writing: $!");
  print $Fwarn "Suspicious lines from $error_log\n";

  my @patterns =
    (
4247 4248
     qr/^Warning:|mysqld: Warning|\[Warning\]/,
     qr/^Error:|\[ERROR\]/,
4249
     qr/^==\d+==\s+\S/, # valgrind errors
Magnus Svensson's avatar
Magnus Svensson committed
4250 4251 4252 4253 4254 4255
     qr/InnoDB: Warning|InnoDB: Error/,
     qr/^safe_mutex:|allocated at line/,
     qr/missing DBUG_RETURN/,
     qr/Attempting backtrace/,
     qr/Assertion .* failed/,
    );
4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267
  # 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 =
    (
4268
     qr/error .*connecting to master/,
4269
     qr/Plugin 'ndbcluster' will be forced to shutdown/,
4270 4271
     qr/InnoDB: Error: in ALTER TABLE `test`.`t[12]`/,
     qr/InnoDB: Error: table `test`.`t[12]` does not exist in the InnoDB internal/,
4272 4273 4274
     qr/Slave: Unknown table 't1' Error_code: 1051/,
     qr/Slave SQL:.*(Error_code: [[:digit:]]+|Query:.*)/,
     qr/slave SQL thread aborted/,
4275 4276
     qr/unknown option '--loose[-_]/,
     qr/unknown variable 'loose[-_]/,
4277
     qr/Invalid .*old.* table or database name/,
4278
     qr/Now setting lower_case_table_names to [02]/,
4279
     qr/Setting lower_case_table_names=2/,
4280
     qr/You have forced lower_case_table_names to 0/,
4281
     qr/Plugin 'ndbcluster' will be forced to shutdow/,
4282
     qr/deprecated/,
4283
     qr/Slave SQL thread retried transaction/,
4284 4285
     qr/Slave \(additional info\)/,
     qr/Incorrect information in file/,
4286 4287 4288 4289 4290
     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: error reconnecting to master '.*' - retry-time: [1-3]  retries/,
4291
     qr/Slave I\/0: Master command COM_BINLOG_DUMP failed/,
4292
     qr/Error reading packet/,
4293 4294
     qr/Lost connection to MySQL server at 'reading initial communication packet'/,
     qr/Failed on request_dump/,
4295
     qr/Slave: Can't drop database.* database doesn't exist/,
Michael Widenius's avatar
Michael Widenius committed
4296
     qr/Slave: Operation DROP USER failed for 'create_rout_db'/,
unknown's avatar
unknown committed
4297
     qr|Checking table:   '\./mtr/test_suppressions'|,
4298
     qr|Table \./test/bug53592 has a primary key in InnoDB data dictionary, but not in MySQL|,
Sergei Golubchik's avatar
Sergei Golubchik committed
4299 4300
     qr|mysqld: Table '\./mtr/test_suppressions' is marked as crashed and should be repaired|,
     qr|InnoDB: Error: table 'test/bug39438'|,
4301
    );
Magnus Svensson's avatar
Magnus Svensson committed
4302

4303
  my $matched_lines= [];
4304
  LINE: foreach my $line ( @lines )
Magnus Svensson's avatar
Magnus Svensson committed
4305
  {
4306
    PAT: foreach my $pat ( @patterns )
Magnus Svensson's avatar
Magnus Svensson committed
4307 4308 4309
    {
      if ( $line =~ /$pat/ )
      {
4310 4311 4312 4313
        foreach my $apat (@antipatterns)
        {
          next LINE if $line =~ $apat;
        }
Magnus Svensson's avatar
Magnus Svensson committed
4314
	print $Fwarn $line;
4315
        push @$matched_lines, $line;
4316
	last PAT;
Magnus Svensson's avatar
Magnus Svensson committed
4317 4318
      }
    }
4319
  }
Magnus Svensson's avatar
Magnus Svensson committed
4320 4321
  $Fwarn = undef; # Close file

4322
  if (scalar(@$matched_lines) > 0 &&
4323
      defined($last_warning_position->{$error_log}{test_names})) {
4324
    return ($last_warning_position->{$error_log}{test_names}, $matched_lines);
4325
  } else {
4326
    return ([], $matched_lines);
4327
  }
4328 4329
}

4330

4331
# Run include/check-warnings.test
4332
#
4333 4334 4335
# RETURN VALUE
#  0 OK
#  1 Check failed
4336
#
4337
sub start_check_warnings ($$) {
4338 4339 4340 4341 4342
  my $tinfo=    shift;
  my $mysqld=   shift;

  my $name= "warnings-".$mysqld->name();

4343 4344 4345
  my $log_error= $mysqld->value('#log-error');
  # To be communicated to the test
  $ENV{MTR_LOG_ERROR}= $log_error;
4346
  extract_warning_lines($log_error);
4347

4348 4349 4350 4351 4352 4353 4354 4355 4356
  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, "--skip-safemalloc");
  mtr_add_arg($args, "--test-file=%s", "include/check-warnings.test");

4357
  if ( $opt_embedded_server )
4358
  {
4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373

    # 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;
  }

4374
  my $errfile= "$opt_vardir/tmp/$name.err";
4375
  my $proc= My::SafeProcess->new
4376 4377 4378 4379 4380 4381
    (
     name          => $name,
     path          => $exe_mysqltest,
     error         => $errfile,
     output        => $errfile,
     args          => \$args,
4382
     user_data     => [$errfile, $mysqld],
Magnus Svensson's avatar
Magnus Svensson committed
4383
     verbose       => $opt_verbose,
4384
    );
4385 4386
  mtr_verbose("Started $proc");
  return $proc;
4387 4388
}

unknown's avatar
unknown committed
4389

4390
#
4391
# Loop through our list of processes and check the error log
4392
# for unexpected errors and warnings
4393
#
4394 4395 4396
sub check_warnings ($) {
  my ($tinfo)= @_;
  my $res= 0;
4397

4398
  my $tname= $tinfo->{name};
4399

4400
  # Clear previous warnings
4401
  delete($tinfo->{warnings});
4402

4403 4404 4405
  # 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;
4406 4407
  foreach my $mysqld ( mysqlds() )
  {
4408
    if ( defined $mysqld->{'proc'} )
4409
    {
4410 4411
      my $proc= start_check_warnings($tinfo, $mysqld);
      $started{$proc->pid()}= $proc;
4412 4413 4414
    }
  }

4415 4416
  # Return immediately if no check proceess was started
  return 0 unless ( keys %started );
unknown's avatar
unknown committed
4417

4418
  my $timeout= start_timer(check_timeout());
4419

4420 4421
  while (1){
    my $result= 0;
4422
    my $proc= My::SafeProcess->wait_any_timeout($timeout);
4423
    mtr_report("Got $proc");
unknown's avatar
unknown committed
4424

4425 4426 4427
    if ( delete $started{$proc->pid()} ) {
      # One check warning process returned
      my $res= $proc->exit_status();
4428
      my ($err_file, $mysqld)= @{$proc->user_data()};
4429

4430
      if ( $res == 0 or $res == 62 ){
unknown's avatar
unknown committed
4431

4432 4433
	if ( $res == 0 ) {
	  # Check completed with problem
4434
	  my $report= mtr_grab_file($err_file);
4435 4436 4437
	  # Log to var/log/warnings file
	  mtr_tofile("$opt_vardir/log/warnings",
		     $tname."\n".$report);
unknown's avatar
unknown committed
4438

4439 4440 4441
	  $tinfo->{'warnings'}.= $report;
	  $result= 1;
	}
unknown's avatar
unknown committed
4442

4443 4444
	if ( $res == 62 ) {
	  # Test case was ok and called "skip"
4445 4446
	  # Remove the .err file the check generated
	  unlink($err_file);
4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457
	}

	if ( keys(%started) == 0){
	  # All checks completed
	  return $result;
	}
	# Wait for next process to exit
	next;
      }
      else
      {
4458
	my $report= mtr_grab_file($err_file);
4459
	$tinfo->{comment}.=
4460
	  "Could not execute 'check-warnings' for ".
4461 4462
	    "testcase '$tname' (res: $res) server: '".
              $mysqld->name() .":\n";
4463 4464 4465 4466 4467
	$tinfo->{comment}.= $report;

	$result= 2;
      }
    }
4468 4469 4470
    elsif ( $proc->{timeout} ) {
      $tinfo->{comment}.= "Timeout for 'check warnings' expired after "
	.check_timeout()." seconds";
4471 4472
      $result= 4;
    }
4473 4474 4475
    else {
      # Unknown process returned, most likley a crash, abort everything
      $tinfo->{comment}=
4476 4477
	"The server $proc crashed while running 'check warnings'".
	get_log_from_proc($proc, $tinfo->{name});
4478
      $result= 3;
unknown's avatar
unknown committed
4479
    }
4480 4481 4482 4483 4484

    # Kill any check processes still running
    map($_->kill(), values(%started));

    return $result;
unknown's avatar
unknown committed
4485
  }
4486

4487
  mtr_error("INTERNAL_ERROR: check_warnings");
unknown's avatar
unknown committed
4488 4489
}

4490
# Check for warnings generated during shutdown of a mysqld server.
4491 4492 4493
# If any, report them to master server, and return true; else just return
# false.

4494 4495 4496
sub check_warnings_post_shutdown {
  my ($server_socket)= @_;
  my $testname_hash= { };
4497
  my $report= '';
4498 4499
  foreach my $mysqld ( mysqlds())
  {
4500 4501
    my ($testlist, $match_lines)=
        extract_warning_lines($mysqld->value('#log-error'));
4502
    $testname_hash->{$_}= 1 for @$testlist;
4503
    $report.= join('', @$match_lines);
4504 4505 4506 4507
  }
  my @warning_tests= keys(%$testname_hash);
  if (@warning_tests) {
    my $fake_test= My::Test->new(testnames => \@warning_tests);
4508
    $fake_test->{'warnings'}= $report;
4509 4510 4511
    $fake_test->write_test($server_socket, 'WARNINGS');
  }
}
unknown's avatar
unknown committed
4512

unknown's avatar
unknown committed
4513
#
unknown's avatar
unknown committed
4514 4515 4516
# 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.
unknown's avatar
unknown committed
4517
#
unknown's avatar
unknown committed
4518 4519
sub check_expected_crash_and_restart {
  my ($proc)= @_;
unknown's avatar
unknown committed
4520

unknown's avatar
unknown committed
4521
  foreach my $mysqld ( mysqlds() )
4522
  {
4523
    next unless ( $mysqld->{proc} and $mysqld->{proc} eq $proc );
unknown's avatar
unknown committed
4524

unknown's avatar
unknown committed
4525 4526 4527 4528 4529
    # 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 )
    {
4530
      mtr_verbose("Crash was expected, file '$expect_file' exists");
4531

4532 4533
      for (my $waits = 0;  $waits < 50;  $waits++)
      {
4534 4535 4536
	# 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
4537
	# up again. Keep trying for up to 5s at a time.
Serge Kozlov's avatar
Serge Kozlov committed
4538
	my $last_line= mtr_lastlinesfromfile($expect_file, 1);
4539 4540
	if ($last_line =~ /^wait/ )
	{
4541
	  mtr_verbose("Test says wait before restart") if $waits == 0;
4542 4543 4544
	  mtr_milli_sleep(100);
	  next;
	}
unknown's avatar
unknown committed
4545

4546 4547 4548 4549
	# 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.
4550 4551 4552 4553 4554 4555
	if ($last_line =~ /restart:(.+)/) {
	  my @rest_opt= split(' ', $1);
	  $mysqld->{'restart_opts'}= \@rest_opt;
	} else {
	  delete $mysqld->{'restart_opts'};
	}
4556
	unlink($expect_file);
4557

4558 4559 4560
	# Start server with same settings as last time
	mysqld_start($mysqld, $mysqld->{'started_opts'});

4561
	return 1;
4562
      }
4563 4564
      # Loop ran through: we should keep waiting after a re-check
      return 2;
unknown's avatar
unknown committed
4565
    }
unknown's avatar
unknown committed
4566 4567
  }

unknown's avatar
unknown committed
4568 4569
  # Not an expected crash
  return 0;
4570 4571
}

unknown's avatar
unknown committed
4572

4573 4574 4575
# Remove all files and subdirectories of a directory
sub clean_dir {
  my ($dir)= @_;
unknown's avatar
unknown committed
4576
  mtr_verbose("clean_dir: $dir");
4577 4578 4579 4580 4581 4582 4583 4584 4585
  finddepth(
	  { no_chdir => 1,
	    wanted => sub {
	      if (-d $_){
		# A dir
		if ($_ eq $dir){
		  # The dir to clean
		  return;
		} else {
unknown's avatar
unknown committed
4586
		  mtr_verbose("rmdir: '$_'");
unknown's avatar
unknown committed
4587
		  rmdir($_) or mtr_warning("rmdir($_) failed: $!");
4588 4589 4590
		}
	      } else {
		# Hopefully a file
unknown's avatar
unknown committed
4591
		mtr_verbose("unlink: '$_'");
unknown's avatar
unknown committed
4592
		unlink($_) or mtr_warning("unlink($_) failed: $!");
4593 4594 4595 4596
	      }
	    }
	  },
	    $dir);
unknown's avatar
unknown committed
4597 4598
}

unknown's avatar
unknown committed
4599

4600 4601
sub clean_datadir {
  mtr_verbose("Cleaning datadirs...");
unknown's avatar
unknown committed
4602

unknown's avatar
unknown committed
4603 4604 4605
  if (started(all_servers()) != 0){
    mtr_error("Trying to clean datadir before all servers stopped");
  }
4606

4607
  for (all_servers())
unknown's avatar
unknown committed
4608
  {
4609 4610 4611 4612
    preserve_error_log($_); # or at least, try to
    my $dir= "$opt_vardir/".$_->{name};
    mtr_verbose(" - removing '$dir'");
    rmtree($dir);
unknown's avatar
unknown committed
4613 4614
  }

4615
  # Remove all files in tmp and var/tmp
4616
  clean_dir("$opt_vardir/tmp");
4617
  if ($opt_tmpdir ne "$opt_vardir/tmp"){
4618
    clean_dir($opt_tmpdir);
unknown's avatar
unknown committed
4619
  }
unknown's avatar
unknown committed
4620 4621
}

unknown's avatar
unknown committed
4622

4623 4624 4625 4626 4627
#
# Save datadir before it's removed
#
sub save_datadir_after_failure($$) {
  my ($dir, $savedir)= @_;
unknown's avatar
unknown committed
4628

4629 4630 4631
  mtr_report(" - saving '$dir'");
  my $dir_name= basename($dir);
  rename("$dir", "$savedir/$dir_name");
4632
}
unknown's avatar
unknown committed
4633

unknown's avatar
unknown committed
4634

4635 4636
sub after_failure ($) {
  my ($tinfo)= @_;
unknown's avatar
unknown committed
4637

4638
  mtr_report("Saving datadirs...");
4639

4640 4641 4642
  my $save_dir= "$opt_vardir/log/";
  $save_dir.= $tinfo->{name};
  # Add combination name if any
unknown's avatar
unknown committed
4643
  $save_dir.= "-$tinfo->{combination}"
4644
    if defined $tinfo->{combination};
unknown's avatar
unknown committed
4645

4646 4647
  # Save savedir  path for server
  $tinfo->{savedir}= $save_dir;
unknown's avatar
unknown committed
4648

4649
  mkpath($save_dir) if ! -d $save_dir;
4650

4651 4652 4653 4654 4655
  # Save the used config files
  my %config_files = config_files($tinfo);
  while (my ($file, $generate) = each %config_files) {
    copy("$opt_vardir/$file", $save_dir);
  }
4656

4657 4658
  # Copy the tmp dir
  copytree("$opt_vardir/tmp/", "$save_dir/tmp/");
unknown's avatar
unknown committed
4659

4660 4661 4662
  foreach (all_servers()) {
    my $dir= "$opt_vardir/".$_->{name};
    save_datadir_after_failure($dir, $save_dir);
unknown's avatar
unknown committed
4663
  }
4664
}
unknown's avatar
unknown committed
4665

4666

unknown's avatar
unknown committed
4667 4668 4669
sub report_failure_and_restart ($) {
  my $tinfo= shift;

4670
  stop_all_servers();
4671

4672
  $tinfo->{'result'}= 'MTR_RES_FAILED';
4673

4674 4675
  my $test_failures= $tinfo->{'failures'} || 0;
  $tinfo->{'failures'}=  $test_failures + 1;
4676 4677


4678
  if ( $tinfo->{comment} )
4679
  {
4680 4681 4682 4683
    # 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"
    ;
4684 4685
  }

4686
  if ( !defined $tinfo->{logfile} )
unknown's avatar
unknown committed
4687
  {
4688
    my $logfile= $path_current_testlog;
4689
    if ( defined $logfile )
4690
    {
4691 4692 4693 4694 4695 4696
      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);
4697
	# If no newlines in the test log:
Bjorn Munch's avatar
Bjorn Munch committed
4698
	# (it will contain the CURRENT_TEST written by mtr, so is not empty)
4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710
	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, 20)."\n";
	  }
	}
4711 4712 4713 4714 4715 4716 4717
      }
      else
      {
	# The test tool report didn't exist, display an
	# error message
	$tinfo->{logfile}= "Could not open test tool report '$logfile'";
      }
4718
    }
unknown's avatar
unknown committed
4719
  }
4720

4721
  after_failure($tinfo);
4722

4723
  mtr_report_test($tinfo);
4724

unknown's avatar
unknown committed
4725
}
unknown's avatar
unknown committed
4726

unknown's avatar
unknown committed
4727

unknown's avatar
unknown committed
4728 4729
sub run_sh_script {
  my ($script)= @_;
unknown's avatar
unknown committed
4730

unknown's avatar
unknown committed
4731
  return 0 unless defined $script;
unknown's avatar
unknown committed
4732

unknown's avatar
unknown committed
4733 4734 4735
  mtr_verbose("Running '$script'");
  my $ret= system("/bin/sh $script") >> 8;
  return $ret;
unknown's avatar
unknown committed
4736
}
unknown's avatar
unknown committed
4737

4738

unknown's avatar
unknown committed
4739 4740
sub mysqld_stop {
  my $mysqld= shift or die "usage: mysqld_stop(<mysqld>)";
unknown's avatar
unknown committed
4741

unknown's avatar
unknown committed
4742 4743
  my $args;
  mtr_init_args(\$args);
4744

unknown's avatar
unknown committed
4745
  mtr_add_arg($args, "--no-defaults");
4746
  mtr_add_arg($args, "--character-sets-dir=%s", $mysqld->value('character-sets-dir'));
unknown's avatar
unknown committed
4747 4748 4749 4750 4751 4752
  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");
unknown's avatar
unknown committed
4753

unknown's avatar
unknown committed
4754
  mtr_add_arg($args, "shutdown");
4755

unknown's avatar
unknown committed
4756 4757 4758 4759 4760
  My::SafeProcess->run
    (
     name          => "mysqladmin shutdown ".$mysqld->name(),
     path          => $exe_mysqladmin,
     args          => \$args,
4761
     error         => "$opt_vardir/log/mysqladmin.err",
unknown's avatar
unknown committed
4762

unknown's avatar
unknown committed
4763
    );
unknown's avatar
unknown committed
4764 4765
}

unknown's avatar
unknown committed
4766

unknown's avatar
unknown committed
4767
sub mysqld_arguments ($$$) {
unknown's avatar
unknown committed
4768
  my $args=              shift;
4769
  my $mysqld=            shift;
4770
  my $extra_opts=        shift;
unknown's avatar
unknown committed
4771

unknown's avatar
unknown committed
4772
  mtr_add_arg($args, "--defaults-file=%s",  $path_config_file);
4773

unknown's avatar
unknown committed
4774
  # When mysqld is run by a root user(euid is 0), it will fail
unknown's avatar
unknown committed
4775 4776
  # to start unless we specify what user to run as, see BUG#30630
  my $euid= $>;
unknown's avatar
unknown committed
4777
  if (!IS_WINDOWS and $euid == 0 and
4778
      (grep(/^--user/, @$extra_opts)) == 0) {
unknown's avatar
unknown committed
4779
    mtr_add_arg($args, "--user=root");
unknown's avatar
unknown committed
4780 4781
  }

unknown's avatar
unknown committed
4782
  if ( $opt_valgrind_mysqld )
unknown's avatar
unknown committed
4783
  {
unknown's avatar
unknown committed
4784
    mtr_add_arg($args, "--skip-safemalloc");
4785 4786

    if ( $mysql_version_id < 50100 )
unknown's avatar
unknown committed
4787
    {
unknown's avatar
unknown committed
4788
      mtr_add_arg($args, "--skip-bdb");
unknown's avatar
unknown committed
4789
    }
unknown's avatar
unknown committed
4790 4791
  }

Michael Widenius's avatar
Michael Widenius committed
4792
  mtr_add_arg($args, "%s--disable-sync-frm");
unknown's avatar
unknown committed
4793

Sergei Golubchik's avatar
Sergei Golubchik committed
4794
  if (!using_extern() and $mysql_version_id >= 50106 && !$opt_user_args)
unknown's avatar
unknown committed
4795
  {
4796
    # Turn on logging to file and tables
Michael Widenius's avatar
Michael Widenius committed
4797
    mtr_add_arg($args, "%s--log-output=table,file");
unknown's avatar
unknown committed
4798 4799
  }

4800 4801
  # Check if "extra_opt" contains --log-bin
  my $skip_binlog= not grep /^--(loose-)?log-bin/, @$extra_opts;
unknown's avatar
unknown committed
4802

unknown's avatar
unknown committed
4803
  # Indicate to mysqld it will be debugged in debugger
unknown's avatar
unknown committed
4804
  if ( $glob_debugger )
unknown's avatar
unknown committed
4805
  {
unknown's avatar
unknown committed
4806
    mtr_add_arg($args, "--gdb");
unknown's avatar
unknown committed
4807 4808
  }

unknown's avatar
unknown committed
4809
  my $found_skip_core= 0;
4810
  foreach my $arg ( @$extra_opts )
unknown's avatar
unknown committed
4811
  {
4812
    # Allow --skip-core-file to be set in <testname>-[master|slave].opt file
unknown's avatar
unknown committed
4813 4814 4815 4816
    if ($arg eq "--skip-core-file")
    {
      $found_skip_core= 1;
    }
4817 4818 4819 4820
    elsif ($skip_binlog and mtr_match_prefix($arg, "--binlog-format"))
    {
      ; # Dont add --binlog-format when running without binlog
    }
4821 4822 4823 4824 4825
    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
    }
unknown's avatar
unknown committed
4826 4827
    else
    {
unknown's avatar
unknown committed
4828
      mtr_add_arg($args, "%s", $arg);
unknown's avatar
unknown committed
4829 4830
    }
  }
4831
  $opt_skip_core = $found_skip_core;
4832
  if ( !$found_skip_core && !$opt_user_args )
unknown's avatar
unknown committed
4833
  {
unknown's avatar
unknown committed
4834
    mtr_add_arg($args, "%s", "--core-file");
unknown's avatar
unknown committed
4835 4836
  }

4837 4838 4839
  # 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",
4840
              $opt_debug_sync_timeout) unless $opt_user_args;
unknown's avatar
unknown committed
4841 4842 4843 4844 4845 4846

  return $args;
}



unknown's avatar
unknown committed
4847
sub mysqld_start ($$) {
unknown's avatar
unknown committed
4848
  my $mysqld=            shift;
4849
  my $extra_opts=        shift;
unknown's avatar
unknown committed
4850

4851
  mtr_verbose(My::Options::toStr("mysqld_start", @$extra_opts));
unknown's avatar
unknown committed
4852

4853
  my $exe= find_mysqld($mysqld->value('basedir'));
unknown's avatar
unknown committed
4854
  my $wait_for_pid_file= 1;
unknown's avatar
unknown committed
4855

4856
  mtr_error("Internal error: mysqld should never be started for embedded")
unknown's avatar
unknown committed
4857
    if $opt_embedded_server;
unknown's avatar
unknown committed
4858

unknown's avatar
unknown committed
4859
  my $args;
unknown's avatar
unknown committed
4860 4861
  mtr_init_args(\$args);

unknown's avatar
unknown committed
4862
  if ( $opt_valgrind_mysqld )
unknown's avatar
unknown committed
4863
  {
unknown's avatar
unknown committed
4864
    valgrind_arguments($args, \$exe);
unknown's avatar
unknown committed
4865
  }
4866 4867 4868 4869
  if ( $opt_strace)
  {
    strace_arguments($args, \$exe, $mysqld->name());
  }
unknown's avatar
unknown committed
4870

unknown's avatar
unknown committed
4871
  mtr_add_arg($args, "--defaults-group-suffix=%s", $mysqld->after('mysqld'));
4872 4873 4874 4875 4876 4877 4878

  # 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'}});
  }
  mysqld_arguments($args,$mysqld,\@all_opts);
unknown's avatar
unknown committed
4879

unknown's avatar
unknown committed
4880
  if ( $opt_debug )
unknown's avatar
unknown committed
4881
  {
unknown's avatar
unknown committed
4882 4883 4884 4885
    mtr_add_arg($args, "--debug=d:t:i:A,%s/log/%s.trace",
		$path_vardir_trace, $mysqld->name());
  }

4886 4887 4888
  if (IS_WINDOWS)
  {
    # Trick the server to send output to stderr, with --console
4889
    if (!(grep(/^--log-error/, @$args))) {
4890 4891
      mtr_add_arg($args, "--console");
    }
4892 4893
  }

unknown's avatar
unknown committed
4894
  if ( $opt_gdb || $opt_manual_gdb )
unknown's avatar
unknown committed
4895
  {
unknown's avatar
unknown committed
4896
    gdb_arguments(\$args, \$exe, $mysqld->name());
unknown's avatar
unknown committed
4897 4898 4899
  }
  elsif ( $opt_ddd || $opt_manual_ddd )
  {
unknown's avatar
unknown committed
4900
    ddd_arguments(\$args, \$exe, $mysqld->name());
unknown's avatar
unknown committed
4901
  }
4902 4903
  elsif ( $opt_debugger )
  {
unknown's avatar
unknown committed
4904
    debugger_arguments(\$args, \$exe, $mysqld->name());
unknown's avatar
unknown committed
4905
  }
4906 4907
  elsif ( $opt_manual_debug )
  {
4908
     print "\nStart " .$mysqld->name()." in your debugger\n" .
4909 4910 4911 4912 4913 4914 4915 4916
           "dir: $glob_mysql_test_dir\n" .
           "exe: $exe\n" .
	   "args:  " . join(" ", @$args)  . "\n\n" .
	   "Waiting ....\n";

     # Indicate the exe should not be started
    $exe= undef;
  }
unknown's avatar
unknown committed
4917 4918 4919 4920 4921
  else
  {
    # Default to not wait until pid file has been created
    $wait_for_pid_file= 0;
  }
unknown's avatar
unknown committed
4922

unknown's avatar
unknown committed
4923 4924
  # Remove the old pidfile if any
  unlink($mysqld->value('pid-file'));
unknown's avatar
unknown committed
4925

4926
  my $output= $mysqld->value('#log-error');
unknown's avatar
unknown committed
4927
  if ( $opt_valgrind and $opt_debug )
unknown's avatar
unknown committed
4928
  {
unknown's avatar
unknown committed
4929 4930 4931
    # 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
unknown's avatar
unknown committed
4932

4933 4934 4935 4936 4937 4938 4939 4940 4941
    # 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;
unknown's avatar
unknown committed
4942

unknown's avatar
unknown committed
4943
  }
4944 4945
  # Remember this log file for valgrind error report search
  $mysqld_logs{$output}= 1 if $opt_valgrind;
4946 4947
  # Remember data dir for gmon.out files if using gprof
  $gprof_dirs{$mysqld->value('datadir')}= 1 if $opt_gprof;
unknown's avatar
unknown committed
4948

unknown's avatar
unknown committed
4949
  if ( defined $exe )
4950
  {
4951
    pre_write_errorlog($output);
unknown's avatar
unknown committed
4952 4953 4954 4955 4956 4957 4958 4959 4960
    $mysqld->{'proc'}= My::SafeProcess->new
      (
       name          => $mysqld->name(),
       path          => $exe,
       args          => \$args,
       output        => $output,
       error         => $output,
       append        => 1,
       verbose       => $opt_verbose,
4961
       nocore        => $opt_skip_core,
unknown's avatar
unknown committed
4962 4963 4964 4965
       host          => undef,
       shutdown      => sub { mysqld_stop($mysqld) },
      );
    mtr_verbose("Started $mysqld->{proc}");
4966
  }
unknown's avatar
unknown committed
4967

unknown's avatar
unknown committed
4968 4969 4970 4971
  if ( $wait_for_pid_file &&
       !sleep_until_file_created($mysqld->value('pid-file'),
				 $opt_start_timeout,
				 $mysqld->{'proc'}))
unknown's avatar
unknown committed
4972
  {
4973 4974
    my $mname= $mysqld->name();
    mtr_error("Failed to start mysqld $mname with command $exe");
unknown's avatar
unknown committed
4975 4976
  }

4977
  # Remember options used when starting
4978
  $mysqld->{'started_opts'}= $extra_opts;
unknown's avatar
unknown committed
4979

unknown's avatar
unknown committed
4980
  return;
unknown's avatar
unknown committed
4981 4982
}

unknown's avatar
unknown committed
4983

unknown's avatar
unknown committed
4984
sub stop_all_servers () {
4985
  my $shutdown_timeout = $_[0] or 0;
unknown's avatar
unknown committed
4986

unknown's avatar
unknown committed
4987
  mtr_verbose("Stopping all servers...");
unknown's avatar
unknown committed
4988

unknown's avatar
unknown committed
4989
  # Kill all started servers
4990
  My::SafeProcess::shutdown($shutdown_timeout,
unknown's avatar
unknown committed
4991
			    started(all_servers()));
unknown's avatar
unknown committed
4992

unknown's avatar
unknown committed
4993 4994
  # Remove pidfiles
  foreach my $server ( all_servers() )
unknown's avatar
unknown committed
4995
  {
unknown's avatar
unknown committed
4996 4997
    my $pid_file= $server->if_exist('pid-file');
    unlink($pid_file) if defined $pid_file;
unknown's avatar
unknown committed
4998
  }
unknown's avatar
unknown committed
4999

unknown's avatar
unknown committed
5000 5001
  # Mark servers as stopped
  map($_->{proc}= undef, all_servers());
unknown's avatar
unknown committed
5002

unknown's avatar
unknown committed
5003 5004 5005
}


unknown's avatar
unknown committed
5006 5007 5008
# Find out if server should be restarted for this test
sub server_need_restart {
  my ($tinfo, $server)= @_;
unknown's avatar
unknown committed
5009

unknown's avatar
unknown committed
5010
  if ( using_extern() )
5011
  {
unknown's avatar
unknown committed
5012
    mtr_verbose_restart($server, "no restart for --extern server");
unknown's avatar
unknown committed
5013
    return 0;
unknown's avatar
unknown committed
5014
  }
unknown's avatar
unknown committed
5015 5016

  if ( $tinfo->{'force_restart'} ) {
unknown's avatar
unknown committed
5017
    mtr_verbose_restart($server, "forced in .opt file");
unknown's avatar
unknown committed
5018
    return 1;
unknown's avatar
unknown committed
5019
  }
unknown's avatar
unknown committed
5020 5021

  if ( $tinfo->{template_path} ne $current_config_name)
5022
  {
unknown's avatar
unknown committed
5023
    mtr_verbose_restart($server, "using different config file");
unknown's avatar
unknown committed
5024
    return 1;
5025
  }
unknown's avatar
unknown committed
5026 5027

  if ( $tinfo->{'master_sh'}  || $tinfo->{'slave_sh'} )
unknown's avatar
unknown committed
5028
  {
unknown's avatar
unknown committed
5029
    mtr_verbose_restart($server, "sh script to run");
unknown's avatar
unknown committed
5030
    return 1;
unknown's avatar
unknown committed
5031
  }
unknown's avatar
unknown committed
5032 5033

  if ( ! started($server) )
5034
  {
unknown's avatar
unknown committed
5035
    mtr_verbose_restart($server, "not started");
unknown's avatar
unknown committed
5036
    return 1;
5037
  }
unknown's avatar
unknown committed
5038 5039 5040

  my $started_tinfo= $server->{'started_tinfo'};
  if ( defined $started_tinfo )
5041
  {
unknown's avatar
unknown committed
5042 5043 5044 5045

    # Check if timezone of  test that server was started
    # with differs from timezone of next test
    if ( timezone($started_tinfo) ne timezone($tinfo) )
5046
    {
unknown's avatar
unknown committed
5047
      mtr_verbose_restart($server, "different timezone");
unknown's avatar
unknown committed
5048
      return 1;
5049
    }
5050
  }
5051

5052 5053 5054 5055 5056 5057 5058 5059 5060
  # Temporary re-enable the "always restart slave" hack
  # this should be removed asap, but will require that each rpl
  # testcase cleanup better after itself - ie. stop and reset
  # replication
  # Use the "#!use-slave-opt" marker to detect that this is a "slave"
  # server
  if ( $server->option("#!use-slave-opt") ){
    mtr_verbose_restart($server, "Always restart slave(s)");
    return 1;
unknown's avatar
unknown committed
5061
  }
5062

5063
  if ($server->name() =~ /^mysqld\./)
5064
  {
unknown's avatar
unknown committed
5065

5066 5067
    # Check that running process was started with same options
    # as the current test requires
5068
    my $extra_opts= get_extra_opts($server, $tinfo);
5069
    my $started_opts= $server->{'started_opts'};
5070

5071 5072 5073 5074
    # 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'})
5075
    {
5076
      my $use_dynamic_option_switch= 0;
unknown's avatar
unknown committed
5077
      if (!$use_dynamic_option_switch)
5078
      {
unknown's avatar
unknown committed
5079 5080 5081 5082
	mtr_verbose_restart($server, "running with different options '" .
			    join(" ", @{$extra_opts}) . "' != '" .
			    join(" ", @{$started_opts}) . "'" );
	return 1;
5083
      }
unknown's avatar
unknown committed
5084

5085 5086 5087 5088 5089 5090 5091 5092 5093 5094
      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)){
5095
	mtr_verbose("Restart: running with different options '" .
5096
		    join(" ", @{$extra_opts}) . "' != '" .
unknown's avatar
unknown committed
5097
		    join(" ", @{$started_opts}) . "'" );
5098 5099
	return 1;
      }
5100 5101 5102

      # Remember the dynamically set options
      $server->{'started_opts'}= $extra_opts;
5103
    }
unknown's avatar
unknown committed
5104
  }
5105

unknown's avatar
unknown committed
5106 5107
  # Default, no restart
  return 0;
5108 5109 5110
}


unknown's avatar
unknown committed
5111 5112 5113 5114
sub servers_need_restart($) {
  my ($tinfo)= @_;
  return grep { server_need_restart($tinfo, $_); } all_servers();
}
unknown's avatar
unknown committed
5115

unknown's avatar
unknown committed
5116

unknown's avatar
unknown committed
5117

5118
############################################
unknown's avatar
unknown committed
5119

5120
############################################
unknown's avatar
unknown committed
5121

unknown's avatar
unknown committed
5122 5123 5124 5125 5126 5127 5128 5129 5130
#
# Filter a list of servers and return only those that are part
# of the specified cluster
#
sub in_cluster {
  my ($cluster)= shift;
  # Return only processes for a specific cluster
  return grep { $_->suffix() eq $cluster->suffix() } @_;
}
unknown's avatar
unknown committed
5131 5132 5133



unknown's avatar
unknown committed
5134 5135 5136 5137 5138 5139
#
# 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}, @_)); }
unknown's avatar
unknown committed
5140 5141


5142
sub get_extra_opts {
5143 5144 5145
  # No extra options if --user-args
  return \@opt_extra_mysqld_opt if $opt_user_args;

unknown's avatar
unknown committed
5146
  my ($mysqld, $tinfo)= @_;
unknown's avatar
unknown committed
5147

5148
  my $opts=
unknown's avatar
unknown committed
5149 5150
    $mysqld->option("#!use-slave-opt") ?
      $tinfo->{slave_opt} : $tinfo->{master_opt};
unknown's avatar
unknown committed
5151

5152 5153 5154
  # Expand environment variables
  foreach my $opt ( @$opts )
  {
Sergei Golubchik's avatar
Sergei Golubchik committed
5155 5156 5157
    no warnings 'uninitialized';
    $opt =~ s/\$\{(\w+)\}/$ENV{$1}/ge;
    $opt =~ s/\$(\w+)/$ENV{$1}/ge;
5158 5159
  }
  return $opts;
unknown's avatar
unknown committed
5160
}
unknown's avatar
unknown committed
5161 5162


unknown's avatar
unknown committed
5163
sub stop_servers($$) {
5164
  my (@servers)= @_;
5165

5166
  mtr_report("Restarting ", started(@servers));
unknown's avatar
unknown committed
5167

5168 5169
  My::SafeProcess::shutdown($opt_shutdown_timeout,
                             started(@servers));
unknown's avatar
unknown committed
5170

unknown's avatar
unknown committed
5171
  foreach my $server (@servers)
unknown's avatar
unknown committed
5172
  {
unknown's avatar
unknown committed
5173 5174 5175 5176 5177 5178 5179
    # Mark server as stopped
    $server->{proc}= undef;

    # Forget history
    delete $server->{'started_tinfo'};
    delete $server->{'started_opts'};
    delete $server->{'started_cnf'};
unknown's avatar
unknown committed
5180
  }
unknown's avatar
unknown committed
5181 5182
}

5183

5184
#
unknown's avatar
unknown committed
5185
# start_servers
5186
#
unknown's avatar
unknown committed
5187
# Start servers not already started
5188 5189 5190 5191 5192
#
# RETURN
#  0 OK
#  1 Start failed
#
unknown's avatar
unknown committed
5193 5194
sub start_servers($) {
  my ($tinfo)= @_;
5195

5196 5197
  for (all_servers()) {
    $_->{START}->($_, $tinfo) if $_->{START};
unknown's avatar
unknown committed
5198 5199
  }

5200 5201 5202 5203
  for (all_servers()) {
    next unless $_->{WAIT} and started($_);
    if ($_->{WAIT}->($_)) {
      $tinfo->{comment}= "Failed to start ".$_->name();
5204
      return 1;
5205
    }
unknown's avatar
unknown committed
5206
  }
5207
  return 0;
unknown's avatar
unknown committed
5208 5209
}

unknown's avatar
unknown committed
5210

5211 5212
#
# Run include/check-testcase.test
unknown's avatar
unknown committed
5213
# Before a testcase, run in record mode and save result file to var/tmp
5214 5215
# After testcase, run and compare with the recorded file, they should be equal!
#
5216
# RETURN VALUE
5217
#  The newly started process
5218
#
5219
sub start_check_testcase ($$$) {
unknown's avatar
unknown committed
5220
  my $tinfo=    shift;
5221
  my $mode=     shift;
5222 5223
  my $mysqld=   shift;

unknown's avatar
unknown committed
5224
  my $name= "check-".$mysqld->name();
5225 5226 5227
  # Replace dots in name with underscore to avoid that mysqltest
  # misinterpret's what the filename extension is :(
  $name=~ s/\./_/g;
5228 5229 5230 5231

  my $args;
  mtr_init_args(\$args);

5232 5233
  mtr_add_arg($args, "--defaults-file=%s", $path_config_file);
  mtr_add_arg($args, "--defaults-group-suffix=%s", $mysqld->after('mysqld'));
5234 5235 5236

  mtr_add_arg($args, "--skip-safemalloc");

unknown's avatar
unknown committed
5237 5238
  mtr_add_arg($args, "--result-file=%s", "$opt_vardir/tmp/$name.result");
  mtr_add_arg($args, "--test-file=%s", "include/check-testcase.test");
5239
  mtr_add_arg($args, "--verbose");
5240 5241 5242 5243 5244

  if ( $mode eq "before" )
  {
    mtr_add_arg($args, "--record");
  }
unknown's avatar
unknown committed
5245
  my $errfile= "$opt_vardir/tmp/$name.err";
5246
  my $proc= My::SafeProcess->new
unknown's avatar
unknown committed
5247 5248 5249 5250
    (
     name          => $name,
     path          => $exe_mysqltest,
     error         => $errfile,
5251
     output        => $errfile,
unknown's avatar
unknown committed
5252
     args          => \$args,
5253
     user_data     => $errfile,
5254
     verbose       => $opt_verbose,
unknown's avatar
unknown committed
5255
    );
5256

5257 5258
  mtr_report("Started $proc");
  return $proc;
5259 5260
}

5261

unknown's avatar
unknown committed
5262 5263 5264
sub run_mysqltest ($) {
  my $proc= start_mysqltest(@_);
  $proc->wait();
5265
}
unknown's avatar
unknown committed
5266

5267

unknown's avatar
unknown committed
5268
sub start_mysqltest ($) {
5269
  my ($tinfo)= @_;
unknown's avatar
unknown committed
5270 5271
  my $exe= $exe_mysqltest;
  my $args;
unknown's avatar
unknown committed
5272 5273 5274

  mtr_init_args(\$args);

unknown's avatar
unknown committed
5275
  mtr_add_arg($args, "--defaults-file=%s", $path_config_file);
unknown's avatar
unknown committed
5276 5277 5278
  mtr_add_arg($args, "--silent");
  mtr_add_arg($args, "--skip-safemalloc");
  mtr_add_arg($args, "--tmpdir=%s", $opt_tmpdir);
5279
  mtr_add_arg($args, "--character-sets-dir=%s", $path_charsetsdir);
5280
  mtr_add_arg($args, "--logdir=%s/log", $opt_vardir);
5281

5282 5283 5284 5285
  # Log line number and time  for each line in .test file
  mtr_add_arg($args, "--mark-progress")
    if $opt_mark_progress;

unknown's avatar
unknown committed
5286
  mtr_add_arg($args, "--database=test");
unknown's avatar
unknown committed
5287

unknown's avatar
unknown committed
5288 5289 5290 5291 5292
  if ( $opt_ps_protocol )
  {
    mtr_add_arg($args, "--ps-protocol");
  }

5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307
  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");
  }

unknown's avatar
unknown committed
5308 5309
  if ( $opt_strace_client )
  {
unknown's avatar
unknown committed
5310
    $exe=  $opt_strace_client || "strace";
unknown's avatar
unknown committed
5311
    mtr_add_arg($args, "-o");
5312
    mtr_add_arg($args, "%s/log/mysqltest.strace", $opt_vardir);
unknown's avatar
unknown committed
5313 5314 5315
    mtr_add_arg($args, "$exe_mysqltest");
  }

unknown's avatar
unknown committed
5316
  mtr_add_arg($args, "--timer-file=%s/log/timer", $opt_vardir);
unknown's avatar
unknown committed
5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327

  if ( $opt_compress )
  {
    mtr_add_arg($args, "--compress");
  }

  if ( $opt_sleep )
  {
    mtr_add_arg($args, "--sleep=%d", $opt_sleep);
  }

5328 5329
  if ( $opt_ssl )
  {
5330
    # Turn on SSL for _all_ test cases if option --ssl was used
5331
    mtr_add_arg($args, "--ssl");
5332
  }
unknown's avatar
unknown committed
5333

5334 5335 5336 5337
  foreach my $arg ( @opt_extra_mysqltest_opt )
  {
    mtr_add_arg($args, "%s", $arg);
  }
5338 5339 5340
  if ( $opt_max_connections ) {
    mtr_add_arg($args, "--max-connections=%d", $opt_max_connections);
  }
5341

unknown's avatar
unknown committed
5342
  if ( $opt_embedded_server )
unknown's avatar
unknown committed
5343
  {
unknown's avatar
unknown committed
5344 5345 5346 5347

    # Get the args needed for the embedded server
    # and append them to args prefixed
    # with --sever-arg=
unknown's avatar
unknown committed
5348

unknown's avatar
unknown committed
5349 5350 5351 5352 5353 5354 5355 5356
    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;
5357 5358 5359 5360

    if (IS_WINDOWS)
    {
      # Trick the server to send output to stderr, with --console
5361
      if (!(grep(/^--server-arg=--log-error/, @$args))) {
5362 5363
        mtr_add_arg($args, "--server-arg=--console");
      }
5364
    }
unknown's avatar
unknown committed
5365 5366
  }

5367 5368 5369 5370 5371
  foreach my $arg ( @opt_extra_mysqltest_opt )
  {
    mtr_add_arg($args, "%s", $arg);
  }

5372 5373 5374
  # ----------------------------------------------------------------------
  # export MYSQL_TEST variable containing <path>/mysqltest <args>
  # ----------------------------------------------------------------------
unknown's avatar
unknown committed
5375
  $ENV{'MYSQL_TEST'}= mtr_args2str($exe_mysqltest, @$args);
5376

5377
  # ----------------------------------------------------------------------
5378
  # Add arguments that should not go into the MYSQL_TEST env var
5379
  # ----------------------------------------------------------------------
5380
  if ( $opt_valgrind_mysqltest )
5381 5382 5383 5384 5385 5386 5387 5388 5389 5390
  {
    # Prefix the Valgrind options to the argument list.
    # We do this here, since we do not want to Valgrind the nested invocations
    # of mysqltest; that would mess up the stderr output causing test failure.
    my @args_saved = @$args;
    mtr_init_args(\$args);
    valgrind_arguments($args, \$exe);
    mtr_add_arg($args, "%s", $_) for @args_saved;
  }

5391
  mtr_add_arg($args, "--test-file=%s", $tinfo->{'path'});
unknown's avatar
unknown committed
5392

5393 5394 5395
  # Number of lines of resut to include in failure report
  mtr_add_arg($args, "--tail-lines=20");

5396
  if ( defined $tinfo->{'result_file'} ) {
5397
    mtr_add_arg($args, "--result-file=%s", $tinfo->{'result_file'});
5398
  }
5399

5400 5401
  client_debug_arg($args, "mysqltest");

5402 5403 5404
  if ( $opt_record )
  {
    mtr_add_arg($args, "--record");
5405

5406 5407 5408 5409 5410
    # 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});
    }
5411 5412
  }

unknown's avatar
unknown committed
5413 5414 5415 5416 5417 5418 5419 5420
  if ( $opt_client_gdb )
  {
    gdb_arguments(\$args, \$exe, "client");
  }
  elsif ( $opt_client_ddd )
  {
    ddd_arguments(\$args, \$exe, "client");
  }
5421 5422 5423
  elsif ( $opt_client_debugger )
  {
    debugger_arguments(\$args, \$exe, "client");
5424
  }
5425

unknown's avatar
unknown committed
5426 5427 5428 5429 5430
  my $proc= My::SafeProcess->new
    (
     name          => "mysqltest",
     path          => $exe,
     args          => \$args,
5431 5432
     append        => 1,
     error         => $path_current_testlog,
unknown's avatar
unknown committed
5433 5434 5435 5436
     verbose       => $opt_verbose,
    );
  mtr_verbose("Started $proc");
  return $proc;
unknown's avatar
unknown committed
5437
}
unknown's avatar
unknown committed
5438

unknown's avatar
unknown committed
5439

unknown's avatar
unknown committed
5440 5441 5442 5443 5444 5445 5446 5447 5448
#
# Modify the exe and args so that program is run in gdb in xterm
#
sub gdb_arguments {
  my $args= shift;
  my $exe=  shift;
  my $type= shift;

  # Write $args to gdb init file
5449
  my $str= join " ", map { s/"/\\"/g; "\"$_\""; } @$$args;
5450
  my $gdb_init_file= "$opt_vardir/tmp/gdbinit.$type";
unknown's avatar
unknown committed
5451

5452 5453 5454
  # Remove the old gdbinit file
  unlink($gdb_init_file);

unknown's avatar
unknown committed
5455 5456 5457
  if ( $type eq "client" )
  {
    # write init file for client
5458
    mtr_tofile($gdb_init_file, "set args $str\n");
unknown's avatar
unknown committed
5459 5460 5461 5462
  }
  else
  {
    # write init file for mysqld
5463
    mtr_tofile($gdb_init_file, "set args $str\n");
5464 5465 5466 5467
  }

  if ( $opt_manual_gdb )
  {
5468
     print "\nTo start gdb for $type, type in another window:\n";
unknown's avatar
unknown committed
5469
     print "gdb -cd $glob_mysql_test_dir -x $gdb_init_file $$exe\n";
5470 5471 5472 5473

     # Indicate the exe should not be started
     $$exe= undef;
     return;
unknown's avatar
unknown committed
5474 5475 5476 5477 5478 5479
  }

  $$args= [];
  mtr_add_arg($$args, "-title");
  mtr_add_arg($$args, "$type");
  mtr_add_arg($$args, "-e");
5480

5481
  if ( $exe_libtool )
unknown's avatar
unknown committed
5482
  {
5483
    mtr_add_arg($$args, $exe_libtool);
unknown's avatar
unknown committed
5484 5485 5486 5487 5488 5489 5490 5491 5492
    mtr_add_arg($$args, "--mode=execute");
  }

  mtr_add_arg($$args, "gdb");
  mtr_add_arg($$args, "-x");
  mtr_add_arg($$args, "$gdb_init_file");
  mtr_add_arg($$args, "$$exe");

  $$exe= "xterm";
unknown's avatar
unknown committed
5493
}
unknown's avatar
unknown committed
5494

unknown's avatar
unknown committed
5495

unknown's avatar
unknown committed
5496 5497 5498 5499 5500 5501 5502 5503 5504
#
# Modify the exe and args so that program is run in ddd
#
sub ddd_arguments {
  my $args= shift;
  my $exe=  shift;
  my $type= shift;

  # Write $args to ddd init file
5505
  my $str= join " ", map { s/"/\\"/g; "\"$_\""; } @$$args;
5506
  my $gdb_init_file= "$opt_vardir/tmp/gdbinit.$type";
unknown's avatar
unknown committed
5507

5508 5509 5510
  # Remove the old gdbinit file
  unlink($gdb_init_file);

unknown's avatar
unknown committed
5511 5512 5513
  if ( $type eq "client" )
  {
    # write init file for client
5514
    mtr_tofile($gdb_init_file, "set args $str\n");
unknown's avatar
unknown committed
5515 5516 5517 5518
  }
  else
  {
    # write init file for mysqld
5519
    mtr_tofile($gdb_init_file, "file $$exe\nset args $str\n");
5520 5521 5522 5523
  }

  if ( $opt_manual_ddd )
  {
5524
     print "\nTo start ddd for $type, type in another window:\n";
unknown's avatar
unknown committed
5525
     print "ddd -cd $glob_mysql_test_dir -x $gdb_init_file $$exe\n";
5526 5527 5528 5529

     # Indicate the exe should not be started
     $$exe= undef;
     return;
unknown's avatar
unknown committed
5530
  }
unknown's avatar
unknown committed
5531

unknown's avatar
unknown committed
5532 5533
  my $save_exe= $$exe;
  $$args= [];
5534
  if ( $exe_libtool )
unknown's avatar
unknown committed
5535
  {
5536
    $$exe= $exe_libtool;
unknown's avatar
unknown committed
5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547
    mtr_add_arg($$args, "--mode=execute");
    mtr_add_arg($$args, "ddd");
  }
  else
  {
    $$exe= "ddd";
  }
  mtr_add_arg($$args, "--command=$gdb_init_file");
  mtr_add_arg($$args, "$save_exe");
}

5548 5549 5550 5551 5552 5553 5554 5555 5556

#
# Modify the exe and args so that program is run in the selected debugger
#
sub debugger_arguments {
  my $args= shift;
  my $exe=  shift;
  my $debugger= $opt_debugger || $opt_client_debugger;

5557
  if ( $debugger =~ /vcexpress|vc|devenv/ )
5558 5559 5560
  {
    # vc[express] /debugexe exe arg1 .. argn

5561
    # Add name of the exe and /debugexe before args
5562
    unshift(@$$args, "$$exe");
5563
    unshift(@$$args, "/debugexe");
5564

5565 5566 5567
    # Set exe to debuggername
    $$exe= $debugger;

5568
  }
5569
  elsif ( $debugger =~ /windbg/ )
5570 5571 5572 5573 5574 5575
  {
    # windbg exe arg1 .. argn

    # Add name of the exe before args
    unshift(@$$args, "$$exe");

5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590
    # Set exe to debuggername
    $$exe= $debugger;

  }
  elsif ( $debugger eq "dbx" )
  {
    # xterm -e dbx -r exe arg1 .. argn

    unshift(@$$args, $$exe);
    unshift(@$$args, "-r");
    unshift(@$$args, $debugger);
    unshift(@$$args, "-e");

    $$exe= "xterm";

5591 5592 5593 5594 5595 5596 5597 5598
  }
  else
  {
    mtr_error("Unknown argument \"$debugger\" passed to --debugger");
  }
}


unknown's avatar
unknown committed
5599 5600 5601
#
# Modify the exe and args so that program is run in valgrind
#
unknown's avatar
unknown committed
5602 5603 5604 5605
sub valgrind_arguments {
  my $args= shift;
  my $exe=  shift;

5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618
  if ( $opt_callgrind)
  {
    mtr_add_arg($args, "--tool=callgrind");
    mtr_add_arg($args, "--base=$opt_vardir/log");
  }
  else
  {
    mtr_add_arg($args, "--tool=memcheck"); # From >= 2.1.2 needs this option
    mtr_add_arg($args, "--leak-check=yes");
    mtr_add_arg($args, "--num-callers=16");
    mtr_add_arg($args, "--suppressions=%s/valgrind.supp", $glob_mysql_test_dir)
      if -f "$glob_mysql_test_dir/valgrind.supp";
  }
unknown's avatar
unknown committed
5619

5620
  # Add valgrind options, can be overriden by user
5621
  mtr_add_arg($args, '%s', $_) for (@valgrind_args);
5622

unknown's avatar
unknown committed
5623 5624
  mtr_add_arg($args, $$exe);

unknown's avatar
unknown committed
5625
  $$exe= $opt_valgrind_path || "valgrind";
5626 5627 5628 5629 5630 5631 5632 5633

  if ($exe_libtool)
  {
    # Add "libtool --mode-execute" before the test to execute
    # if running in valgrind(to avoid valgrinding bash)
    unshift(@$args, "--mode=execute", $$exe);
    $$exe= $exe_libtool;
  }
unknown's avatar
unknown committed
5634 5635
}

5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662
#
# Modify the exe and args so that program is run in strace
#
sub strace_arguments {
  my $args= shift;
  my $exe=  shift;
  my $mysqld_name= shift;

  mtr_add_arg($args, "-f");
  mtr_add_arg($args, "-o%s/var/log/%s.strace", $glob_mysql_test_dir, $mysqld_name);

  # Add strace options, can be overriden by user
  mtr_add_arg($args, '%s', $_) for (@strace_args);

  mtr_add_arg($args, $$exe);

  $$exe= "strace";

  if ($exe_libtool)
  {
    # Add "libtool --mode-execute" before the test to execute
    # if running in valgrind(to avoid valgrinding bash)
    unshift(@$args, "--mode=execute", $$exe);
    $$exe= $exe_libtool;
  }
}

unknown's avatar
unknown committed
5663

unknown's avatar
unknown committed
5664
#
unknown's avatar
unknown committed
5665
# Usage
unknown's avatar
unknown committed
5666
#
unknown's avatar
unknown committed
5667
sub usage ($) {
Magnus Svensson's avatar
Magnus Svensson committed
5668
  my ($message)= @_;
5669 5670 5671

  if ( $message )
  {
unknown's avatar
unknown committed
5672
    print STDERR "$message\n";
5673 5674
    print STDERR "For full list of options, use $0 --help\n";
    exit;      
5675 5676
  }

unknown's avatar
unknown committed
5677
  print <<HERE;
unknown's avatar
unknown committed
5678

unknown's avatar
unknown committed
5679
$0 [ OPTIONS ] [ TESTCASE ]
unknown's avatar
unknown committed
5680 5681 5682 5683 5684

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
5685 5686 5687 5688
  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
5689 5690
  compress              Use the compressed protocol between client and server
  ssl                   Use ssl protocol between client and server
5691
  skip-ssl              Dont start server with support for ssl connections
5692 5693
  vs-config             Visual Studio configuration used to create executables
                        (default: MTR_VS_CONFIG environment variable)
5694
  parallel=#            How many parallell test should be run
5695
  defaults-file=<config template> Use fixed config template for all
unknown's avatar
unknown committed
5696
                        tests
5697
  defaults_extra_file=<config template> Extra config template to add to
unknown's avatar
unknown committed
5698
                        all generated configs
Sergey Petrunya's avatar
Sergey Petrunya committed
5699
  combination=<opt>     Use at least twice to run tests with specified
5700 5701
                        options to mysqld
  skip-combinations     Ignore combination file (or options)
unknown's avatar
unknown committed
5702

5703 5704 5705
Options to control directories to use
  tmpdir=DIR            The directory where temporary files are stored
                        (default: ./var/tmp).
5706 5707 5708
  vardir=DIR            The directory where files generated from the test run
                        is stored (default: ./var). Specifying a ramdisk or
                        tmpfs will speed up tests.
5709 5710 5711
  mem                   Run testsuite in "memory" using tmpfs or ramdisk
                        Attempts to find a suitable location
                        using a builtin list of standard locations
5712 5713 5714
                        for tmpfs (/dev/shm)
                        The option can also be set using environment
                        variable MTR_MEM=[DIR]
unknown's avatar
unknown committed
5715 5716 5717
  client-bindir=PATH    Path to the directory where client binaries are located
  client-libdir=PATH    Path to the directory where client libraries are located

5718

unknown's avatar
unknown committed
5719 5720 5721
Options to control what test suites or cases to run

  force                 Continue to run the suite after failure
5722
  with-ndbcluster-only  Run only tests that include "ndb" in the filename
unknown's avatar
unknown committed
5723
  skip-ndb[cluster]     Skip all tests that need cluster
5724 5725 5726 5727 5728 5729
  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
5730 5731 5732 5733
  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
5734
                        list of suite names.
5735
                        The default is: "$DEFAULT_SUITES"
unknown's avatar
unknown committed
5736
  skip-rpl              Skip the replication test cases.
5737
  big-test              Also run tests marked as "big"
5738 5739
  staging-run           Run a limited number of tests (no slow tests). Used
                        for running staging trees with valgrind.
5740
  enable-disabled       Run also tests marked as disabled
5741
  print-testcases       Don't run the tests but print details about all the
5742
                        selected tests, in the order they would be run.
unknown's avatar
unknown committed
5743 5744 5745

Options that specify ports

5746 5747 5748 5749 5750
  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.
unknown's avatar
unknown committed
5751
  mtr-build-thread=#    Specify unique number to calculate port number(s) from.
unknown's avatar
unknown committed
5752
  build-thread=#        Can be set in environment variable MTR_BUILD_THREAD.
unknown's avatar
unknown committed
5753 5754
                        Set  MTR_BUILD_THREAD="auto" to automatically aquire
                        a build thread id that is unique to current host
unknown's avatar
unknown committed
5755 5756 5757 5758

Options for test case authoring

  record TESTNAME       (Re)genereate the result file for TESTNAME
5759
  check-testcases       Check testcases for sideeffects
5760
  mark-progress         Log line number and elapsed time to <testname>.progress
unknown's avatar
unknown committed
5761 5762 5763 5764

Options that pass on options

  mysqld=ARGS           Specify additional arguments to "mysqld"
5765
  mysqltest=ARGS        Specify additional arguments to "mysqltest"
unknown's avatar
unknown committed
5766 5767 5768

Options to run test on running server

unknown's avatar
unknown committed
5769 5770 5771 5772 5773
  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
unknown's avatar
unknown committed
5774 5775 5776

Options for debugging the product

5777 5778
  client-ddd            Start mysqltest client in ddd
  client-debugger=NAME  Start mysqltest in the selected debugger
unknown's avatar
unknown committed
5779 5780
  client-gdb            Start mysqltest client in gdb
  ddd                   Start mysqld in ddd
5781
  debug                 Dump trace output for all servers and client programs
5782
  debugger=NAME         Start mysqld in the selected debugger
5783 5784 5785 5786 5787
  gdb                   Start the mysqld(s) in gdb
  manual-debug          Let user manually start mysqld in debugger, before
                        running test(s)
  manual-gdb            Let user manually start mysqld in gdb, before running
                        test(s)
unknown's avatar
unknown committed
5788 5789
  manual-ddd            Let user manually start mysqld in ddd, before running
                        test(s)
5790 5791
  max-save-core         Limit the number of core files saved (to avoid filling
                        up disks for heavily crashing server). Defaults to
5792 5793 5794 5795 5796 5797
                        $opt_max_save_core, set to 0 for no limit. Set
                        it's 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 to 0 for no limit. Set
                        it's default with MTR_MAX_SAVE_DATDIR
5798 5799 5800 5801
  max-test-fail         Limit the number of test failurs 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
unknown's avatar
unknown committed
5802

unknown's avatar
unknown committed
5803
Options for valgrind
unknown's avatar
unknown committed
5804

5805
  valgrind              Run the "mysqltest" and "mysqld" executables using
5806
                        valgrind with default options
5807
  valgrind-all          Synonym for --valgrind
5808 5809
  valgrind-mysqltest    Run the "mysqltest" and "mysql_client_test" executable
                        with valgrind
unknown's avatar
unknown committed
5810
  valgrind-mysqld       Run the "mysqld" executable with valgrind
5811 5812 5813
  valgrind-options=ARGS Deprecated, use --valgrind-option
  valgrind-option=ARGS  Option to give valgrind, replaces default option(s),
                        can be specified more then once
5814
  valgrind-path=<EXE>   Path to the valgrind executable
5815
  callgrind             Instruct valgrind to use callgrind
unknown's avatar
unknown committed
5816

5817 5818 5819 5820 5821 5822 5823 5824 5825
Options for strace

  strace                Run the "mysqld" executables using strace. Default
                        options are -f -o var/log/'mysqld-name'.strace
  strace-option=ARGS    Option to give strace, replaces default option(s),
  strace-client=[path]  Create strace output for mysqltest client, optionally
                        specifying name and path to the trace program to use.
                        Example: $0 --strace-client=ktrace

unknown's avatar
unknown committed
5826
Misc options
5827
  user=USER             User for connecting to mysqld(default: $opt_user)
5828
  comment=STR           Write STR to the output
5829
  notimer               Don't show test case execution time
unknown's avatar
unknown committed
5830
  verbose               More verbose output(use multiple times for even more)
5831
  verbose-restart       Write when and why servers are restarted
unknown's avatar
unknown committed
5832 5833 5834 5835
  start                 Only initialize and start the servers, using the
                        startup settings for the first specified test case
                        Example:
                         $0 --start alias &
5836 5837
  start-and-exit        Same as --start, but mysql-test-run terminates and
                        leaves just the server running
5838
  start-dirty           Only start the servers (without initialization) for
unknown's avatar
unknown committed
5839
                        the first specified test case
5840 5841 5842
  user-args             In combination with start* and no test name, drops
                        arguments to mysqld except those speficied with
                        --mysqld (if any)
5843 5844
  wait-all              If --start or --start-dirty option is used, wait for all
                        servers to exit before finishing the process
unknown's avatar
unknown committed
5845 5846
  fast                  Run as fast as possible, dont't wait for servers
                        to shutdown etc.
unknown's avatar
unknown committed
5847
  parallel=N            Run tests in N parallel threads (default 1)
5848
                        Use parallel=auto for auto-setting of N
unknown's avatar
unknown committed
5849
  repeat=N              Run each test N number of times
unknown's avatar
unknown committed
5850 5851 5852 5853 5854 5855
  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 occured (default $opt_retry_failure)
5856
  reorder               Reorder tests to get fewer server restarts
unknown's avatar
unknown committed
5857 5858
  help                  Get this help text

unknown's avatar
unknown committed
5859 5860 5861 5862 5863 5864
  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.
5865

5866 5867 5868 5869 5870 5871 5872 5873
  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)

5874
  sleep=SECONDS         Passed to mysqltest, will be used as fixed sleep time
5875 5876
  debug-sync-timeout=NUM Set default timeout for WAIT_FOR debug sync
                        actions. Disable facility with NUM=0.
5877 5878
  gcov                  Collect coverage information after the test.
                        The result is a gcov file per source and header file.
Sergey Petrunya's avatar
Sergey Petrunya committed
5879 5880 5881
  gcov-src-dir=subdir   Colllect coverage only within the given subdirectory.
                        For example, if you're only developing the SQL layer, 
                        it makes sense to use --gcov-src-dir=sql
5882 5883 5884 5885 5886 5887
  experimental=<file>   Refer to list of tests considered experimental;
                        failures will be marked exp-fail instead of fail.
  report-features       First run a "test" that reports mysql features
  timestamp             Print timestamp before each test report line
  timediff              With --timestamp, also print time passed since
                        *previous* test started
5888
  max-connections=N     Max number of open connection to server in mysqltest
5889

unknown's avatar
unknown committed
5890
HERE
unknown's avatar
unknown committed
5891
  exit(1);
5892

unknown's avatar
unknown committed
5893
}
5894 5895 5896 5897 5898

sub list_options ($) {
  my $hash= shift;

  for (keys %$hash) {
5899
    s/([:=].*|[+!])$//;
5900 5901 5902 5903
    s/\|/\n--/g;
    print "--$_\n";
  }

Michael Widenius's avatar
Michael Widenius committed
5904
  exit(1);
5905
}
5906 5907 5908 5909 5910 5911 5912 5913

sub time_format($) {
  sprintf '%d:%02d:%02d', $_[0]/3600, ($_[0]/60)%60, $_[0]%60;
}

my $num_tests;

sub xterm_stat {
5914
  if (-t STDOUT and defined $ENV{TERM} and $ENV{TERM} =~ /xterm/) {
5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927
    my ($left) = @_;

    # 2.5 -> best by test
    $num_tests = $left + 2.5 unless $num_tests;

    my $done = $num_tests - $left;
    my $spent = time - $^T;

    printf "\e];mtr: spent %s on %d tests. %s (%d tests) left\a",
           time_format($spent), $done,
           time_format($spent/$done * $left), $left;
  }
}