1#!/usr/bin/perl
2# -*- cperl -*-
3
4# Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved.
5#
6# This program is free software; you can redistribute it and/or modify
7# it under the terms of the GNU General Public License, version 2.0,
8# as published by the Free Software Foundation.
9#
10# This program is also distributed with certain software (including
11# but not limited to OpenSSL) that is licensed under separate terms,
12# as designated in a particular file or component or in included license
13# documentation.  The authors of MySQL hereby grant you an additional
14# permission to link the program and your derivative works with the
15# separately licensed software that they have included with MySQL.
16#
17# This program is distributed in the hope that it will be useful,
18# but WITHOUT ANY WARRANTY; without even the implied warranty of
19# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20# GNU General Public License, version 2.0, for more details.
21#
22# You should have received a copy of the GNU General Public License
23# along with this program; if not, write to the Free Software
24# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
25
26#
27##############################################################################
28#
29#  mysql-test-run.pl
30#
31#  Tool used for executing a suite of .test files
32#
33#  See the "MySQL Test framework manual" for more information
34#  http://dev.mysql.com/doc/mysqltest/en/index.html
35#
36#
37##############################################################################
38
39use strict;
40use warnings;
41
42BEGIN {
43  # Check that mysql-test-run.pl is started from mysql-test/
44  unless ( -f "mysql-test-run.pl" )
45  {
46    print "**** ERROR **** ",
47      "You must start mysql-test-run from the mysql-test/ directory\n";
48    exit(1);
49  }
50  # Check that lib exist
51  unless ( -d "lib/" )
52  {
53    print "**** ERROR **** ",
54      "Could not find the lib/ directory \n";
55    exit(1);
56  }
57}
58
59BEGIN {
60  # Check backward compatibility support
61  # By setting the environment variable MTR_VERSION
62  # it's possible to use a previous version of
63  # mysql-test-run.pl
64  my $version= $ENV{MTR_VERSION} || 2;
65  if ( $version == 1 )
66  {
67    print "=======================================================\n";
68    print "  WARNING: Using mysql-test-run.pl version 1!  \n";
69    print "=======================================================\n";
70    # Should use exec() here on *nix but this appears not to work on Windows
71    exit(system($^X, "lib/v1/mysql-test-run.pl", @ARGV) >> 8);
72  }
73  elsif ( $version == 2 )
74  {
75    # This is the current version, just continue
76    ;
77  }
78  else
79  {
80    print "ERROR: Version $version of mysql-test-run does not exist!\n";
81    exit(1);
82  }
83}
84
85use lib "lib";
86
87use Cwd;
88use Cwd "abs_path";
89use Getopt::Long;
90use My::File::Path; # Patched version of File::Path
91use File::Basename;
92use File::Copy;
93use File::Find;
94use File::Temp qw/tempdir/;
95use File::Spec::Functions qw/splitdir/;
96use My::Constants;
97use My::Platform;
98use My::SafeProcess;
99use My::ConfigFactory;
100use My::Options;
101use My::Find;
102use My::SysInfo;
103use My::CoreDump;
104use mtr_cases;
105use mtr_report;
106use mtr_report_junit;
107use mtr_match;
108use mtr_unique;
109use mtr_results;
110use IO::Socket::INET;
111use IO::Select;
112use Subunit;
113
114push @INC, ".";
115
116require "lib/mtr_process.pl";
117require "lib/mtr_io.pl";
118require "lib/mtr_gcov.pl";
119require "lib/mtr_gprof.pl";
120require "lib/mtr_misc.pl";
121
122$SIG{INT}= sub { mtr_error("Got ^C signal"); };
123
124our $mysql_version_id;
125my $mysql_version_extra;
126our $glob_mysql_test_dir;
127our $basedir;
128our $bindir;
129
130our $path_charsetsdir;
131our $path_client_bindir;
132our $path_client_libdir;
133our $path_language;
134
135our $path_current_testlog;
136our $path_testlog;
137
138our $default_vardir;
139our $opt_vardir;                # Path to use for var/ dir
140my $path_vardir_trace;          # unix formatted opt_vardir for trace files
141my $opt_tmpdir;                 # Path to use for tmp/ dir
142my $opt_tmpdir_pid;
143
144my $opt_start;
145my $opt_start_dirty;
146my $opt_start_exit;
147my $start_only;
148
149my $auth_plugin;                # the path to the authentication test plugin
150
151END {
152  if ( defined $opt_tmpdir_pid and $opt_tmpdir_pid == $$ )
153  {
154    if (!$opt_start_exit)
155    {
156      # Remove the tempdir this process has created
157      mtr_verbose("Removing tmpdir $opt_tmpdir");
158      rmtree($opt_tmpdir);
159    }
160    else
161    {
162      mtr_warning("tmpdir $opt_tmpdir should be removed after the server has finished");
163    }
164  }
165}
166
167sub env_or_val($$) { defined $ENV{$_[0]} ? $ENV{$_[0]} : $_[1] }
168
169# set_term_args(user_specified_string, term_exe_variable, term_args_arr, title)
170sub set_term_args {
171  my $term_cmd = $_[0];
172  if ($term_cmd =~ /^ *$/) {
173    mtr_error("MTR_TERM is defined, but empty");
174  }
175  my @term_args = split / /, $term_cmd;
176  $_[1] = shift @term_args;
177  foreach my $t_arg (@term_args) {
178    if ($t_arg eq "%title%") {
179      mtr_add_arg($_[2], "$_[3]");
180    } else {
181      mtr_add_arg($_[2], $t_arg);
182    }
183  }
184
185}
186
187my $path_config_file;           # The generated config file, var/my.cnf
188
189# Visual Studio produces executables in different sub-directories based on the
190# configuration used to build them.  To make life easier, an environment
191# variable or command-line option may be specified to control which set of
192# executables will be used by the test suite.
193our $opt_vs_config = $ENV{'MTR_VS_CONFIG'};
194
195# If you add a new suite, please check TEST_DIRS in Makefile.am.
196#
197my $DEFAULT_SUITES= "main,sys_vars,binlog,federated,rpl,innodb,innodb_fts,"
198  ."innodb_zip,perfschema,funcs_1,funcs_2,opt_trace,parts,auth_sec,"
199  ."connection_control,jp,stress,engines/iuds,engines/funcs,"
200  ."query_response_time,innodb_stress,tokudb.add_index,tokudb.alter_table,"
201  ."tokudb,tokudb.bugs,tokudb.parts,tokudb.rpl,tokudb.perfschema,"
202  ."percona-pam-for-mysql";
203my $opt_suites;
204
205our $opt_verbose= 0;  # Verbose output, enable with --verbose
206our $exe_mysql;
207our $exe_mysql_plugin;
208our $exe_mysqladmin;
209our $exe_mysqltest;
210our $exe_libtool;
211our $exe_mysql_embedded;
212
213our $opt_big_test= 0;
214
215our @opt_combinations;
216
217our @opt_extra_mysqld_opt;
218our @opt_mysqld_envs;
219
220my $opt_stress;
221
222my $opt_compress;
223my $opt_ssl;
224my $opt_skip_ssl;
225my @opt_skip_test_list;
226our $opt_ssl_supported;
227my $opt_ps_protocol;
228my $opt_sp_protocol;
229my $opt_cursor_protocol;
230my $opt_view_protocol;
231my $opt_trace_protocol;
232my $opt_explain_protocol;
233my $opt_json_explain_protocol;
234
235our $opt_debug;
236my $debug_d= "d";
237my $opt_debug_common;
238our $opt_debug_server;
239our @opt_cases;                  # The test cases names in argv
240our $opt_embedded_server;
241# -1 indicates use default, override with env.var.
242our $opt_ctest= env_or_val(MTR_UNIT_TESTS => -1);
243our $opt_ctest_report;
244# Unit test report stored here for delayed printing
245my $ctest_report;
246
247# Options used when connecting to an already running server
248my %opts_extern;
249sub using_extern { return (keys %opts_extern > 0);};
250
251our $opt_fast= 0;
252our $opt_force;
253our $opt_mem= $ENV{'MTR_MEM'};
254our $opt_clean_vardir= $ENV{'MTR_CLEAN_VARDIR'};
255
256our $opt_gcov;
257our $opt_gcov_exe= "gcov";
258our $opt_gcov_err= "mysql-test-gcov.err";
259our $opt_gcov_msg= "mysql-test-gcov.msg";
260
261our $opt_gprof;
262our %gprof_dirs;
263
264our $glob_debugger= 0;
265our $opt_gdb;
266our $opt_client_gdb;
267my $opt_boot_gdb;
268our $opt_lldb;
269our $opt_dbx;
270our $opt_client_dbx;
271my $opt_boot_dbx;
272our $opt_ddd;
273our $opt_client_ddd;
274my $opt_boot_ddd;
275our $opt_manual_gdb;
276our $opt_manual_lldb;
277our $opt_manual_dbx;
278our $opt_manual_ddd;
279our $opt_manual_debug;
280our $opt_debugger;
281our $opt_client_debugger;
282
283my $config; # The currently running config
284my $current_config_name; # The currently running config file template
285
286our @opt_experimentals;
287our $experimental_test_cases= [];
288
289my $baseport;
290# $opt_build_thread may later be set from $opt_port_base
291my $opt_build_thread= $ENV{'MTR_BUILD_THREAD'} || "auto";
292my $opt_port_base= $ENV{'MTR_PORT_BASE'} || "auto";
293my $build_thread= 0;
294
295my $opt_record;
296my $opt_report_features;
297
298our $opt_resfile= $ENV{'MTR_RESULT_FILE'} || 0;
299
300my $opt_skip_core;
301
302our $opt_check_testcases= 1;
303my $opt_mark_progress;
304my $opt_max_connections;
305our $opt_report_times= 0;
306
307my $opt_sleep;
308
309my $opt_testcase_timeout= $ENV{MTR_TESTCASE_TIMEOUT} ||  15; # minutes
310my $opt_suite_timeout   = $ENV{MTR_SUITE_TIMEOUT}    || 300; # minutes
311my $opt_shutdown_timeout= $ENV{MTR_SHUTDOWN_TIMEOUT} ||  20; # seconds
312my $opt_start_timeout   = $ENV{MTR_START_TIMEOUT}    || 180; # seconds
313
314sub suite_timeout { return $opt_suite_timeout * 60; };
315
316my $opt_wait_all;
317my $opt_user_args;
318my $opt_repeat= 1;
319my $opt_retry= 3;
320my $opt_retry_failure= env_or_val(MTR_RETRY_FAILURE => 2);
321my $opt_reorder= 1;
322my $opt_force_restart= 0;
323
324my $opt_strace_client;
325my $opt_strace_server;
326
327our $opt_user = "root";
328
329our $opt_valgrind= 0;
330my $shutdown_report= 0;
331my $shutdown_report_text= '';
332my $opt_valgrind_mysqld= 0;
333my $opt_valgrind_mysqltest= 0;
334my @valgrind_args;
335my $opt_valgrind_path;
336my $opt_callgrind;
337my $opt_helgrind;
338my %mysqld_logs;
339my $opt_debug_sync_timeout= 600; # Default timeout for WAIT_FOR actions.
340my $opt_mtr_term_args = env_or_val(MTR_TERM => "xterm -title %title% -e");
341my $opt_lldb_cmd = env_or_val(MTR_LLDB => "lldb");
342
343sub testcase_timeout ($) {
344  my ($tinfo)= @_;
345  if (exists $tinfo->{'case-timeout'}) {
346    # Return test specific timeout if *longer* that the general timeout
347    my $test_to= $tinfo->{'case-timeout'};
348    $test_to*= 10 if $opt_valgrind;
349    return $test_to * 60 if $test_to > $opt_testcase_timeout;
350  }
351  return $opt_testcase_timeout * 60;
352}
353
354sub check_timeout ($) { return testcase_timeout($_[0]) / 10; }
355
356our $opt_warnings= 1;
357
358our $ndbcluster_enabled= 0;
359my $opt_include_ndbcluster= 0;
360my $opt_skip_ndbcluster= 0;
361
362our $opt_junit_output= undef;
363our $opt_junit_package= undef;
364
365my $exe_ndbd;
366my $exe_ndbmtd;
367my $exe_ndb_mgmd;
368my $exe_ndb_waiter;
369my $exe_ndb_mgm;
370
371our $debug_compiled_binaries;
372
373our %mysqld_variables;
374
375my $source_dist= 0;
376
377my $opt_max_save_core= env_or_val(MTR_MAX_SAVE_CORE => 5);
378my $opt_max_save_datadir= env_or_val(MTR_MAX_SAVE_DATADIR => 20);
379my $opt_max_test_fail= env_or_val(MTR_MAX_TEST_FAIL => 10);
380
381my $opt_parallel= $ENV{MTR_PARALLEL} || 1;
382
383select(STDOUT);
384$| = 1; # Automatically flush STDOUT
385
386main();
387
388sub is_core_dump {
389  my $core_name= shift;
390  # Name beginning with core, not ending in .gz, .c, nor .log, or ending with
391  # .dmp on Windows
392  return (($core_name =~ /^core/ and $core_name !~ /\.gz$|\.c$|\.log$/)
393          or (IS_WINDOWS and $core_name =~ /\.dmp$/));
394}
395
396sub main {
397  # Default, verbosity on
398  report_option('verbose', 0);
399
400  # This is needed for test log evaluation in "gen-build-status-page"
401  # in all cases where the calling tool does not log the commands
402  # directly before it executes them, like "make test-force-pl" in RPM builds.
403  mtr_report("Logging: $0 ", join(" ", @ARGV));
404
405  command_line_setup();
406
407  # --help will not reach here, so now it's safe to assume we have binaries
408  My::SafeProcess::find_bin();
409
410  if ( $opt_gcov ) {
411    gcov_prepare($basedir);
412  }
413
414  if (!$opt_suites) {
415    $opt_suites= $DEFAULT_SUITES;
416  }
417  mtr_report("Using suites: $opt_suites") unless @opt_cases;
418
419  init_timers();
420
421  mtr_report("Collecting tests...");
422  my $tests= collect_test_cases($opt_reorder, $opt_suites, \@opt_cases, \@opt_skip_test_list);
423  my $all_tests;
424  @$all_tests = @$tests;
425  mark_time_used('collect');
426
427  if ( $opt_report_features ) {
428    # Put "report features" as the first test to run
429    my $tinfo = My::Test->new
430      (
431       name           => 'report_features',
432       # No result_file => Prints result
433       path           => 'include/report-features.test',
434       template_path  => "include/default_my.cnf",
435       master_opt     => [],
436       slave_opt      => [],
437      );
438    unshift(@$tests, $tinfo);
439  }
440
441  initialize_servers();
442
443  #######################################################################
444  my $num_tests= @$tests;
445  if ( $opt_parallel eq "auto" ) {
446    # Try to find a suitable value for number of workers
447    my $sys_info= My::SysInfo->new();
448
449    $opt_parallel= $sys_info->num_cpus();
450    for my $limit (2000, 1500, 1000, 500){
451      $opt_parallel-- if ($sys_info->min_bogomips() < $limit);
452    }
453    if(defined $ENV{MTR_MAX_PARALLEL}) {
454      my $max_par= $ENV{MTR_MAX_PARALLEL};
455      $opt_parallel= $max_par if ($opt_parallel > $max_par);
456    }
457    $opt_parallel= 1 if ($opt_parallel < 1);
458  }
459  # Limit parallel workers to number of tests to avoid idle workers
460  $opt_parallel= $num_tests if ($num_tests > 0 and $opt_parallel > $num_tests);
461  $ENV{MTR_PARALLEL} = $opt_parallel;
462  mtr_report("Using parallel: $opt_parallel");
463
464  if ($opt_parallel > 1 && ($opt_start_exit || $opt_stress)) {
465    mtr_warning("Parallel cannot be used with --start-and-exit or --stress\n" .
466               "Setting parallel to 1");
467    $opt_parallel= 1;
468  }
469
470  # Create server socket on any free port
471  my $server = new IO::Socket::INET
472    (
473     LocalAddr => 'localhost',
474     Proto => 'tcp',
475     Listen => $opt_parallel,
476    );
477  mtr_error("Could not create testcase server port: $!") unless $server;
478  my $server_port = $server->sockport();
479
480  if ($opt_resfile) {
481    resfile_init("$opt_vardir/mtr-results.txt");
482    print_global_resfile();
483  }
484
485  # --------------------------------------------------------------------------
486  # Read definitions from include/plugin.defs
487  #
488  read_plugin_defs("include/plugin.defs");
489
490  # Also read from any plugin local or suite specific plugin.defs
491  for (glob "$basedir/plugin/*/tests/mtr/plugin.defs".
492            " $basedir/internal/plugin/*/tests/mtr/plugin.defs".
493            " suite/*/plugin.defs") {
494    read_plugin_defs($_);
495  }
496
497  # Simplify reference to semisync plugins
498  $ENV{'SEMISYNC_PLUGIN_OPT'}= $ENV{'SEMISYNC_MASTER_PLUGIN_OPT'};
499
500  # Create child processes
501  my %children;
502  for my $child_num (1..$opt_parallel){
503    my $child_pid= My::SafeProcess::Base::_safe_fork();
504    if ($child_pid == 0){
505      $server= undef; # Close the server port in child
506      $tests= {}; # Don't need the tests list in child
507
508      # Use subdir of var and tmp unless only one worker
509      if ($opt_parallel > 1) {
510	set_vardir("$opt_vardir/$child_num");
511	$opt_tmpdir= "$opt_tmpdir/$child_num";
512      }
513
514      init_timers();
515      run_worker($server_port, $child_num);
516      exit(1);
517    }
518
519    $children{$child_pid}= 1;
520  }
521  #######################################################################
522
523  mtr_report();
524  mtr_print_thick_line();
525  mtr_print_header($opt_parallel > 1);
526
527  mark_time_used('init');
528
529  my $completed= run_test_server($server, $tests, $opt_parallel);
530
531  exit(0) if $opt_start_exit;
532
533  # Send Ctrl-C to any children still running
534  kill("INT", keys(%children));
535
536  if (!IS_WINDOWS) {
537    # Wait for children to exit
538    foreach my $pid (keys %children)
539    {
540      my $ret_pid= waitpid($pid, 0);
541      if ($ret_pid != $pid){
542        mtr_report("Unknown process $ret_pid exited");
543      }
544      else {
545        delete $children{$ret_pid};
546      }
547    }
548  }
549
550  if ( not $completed ) {
551    mtr_error("Test suite aborted");
552  }
553
554  my $aggregated_shutdown_report = '';
555  my $aggregated_valgrind_report = '';
556  foreach my $t (@$completed) {
557    if ($t->{name} eq "shutdown_report") {
558      if (defined $t->{comment} && $t->{comment} ne '') {
559        $aggregated_shutdown_report .= $t->{comment};
560      }
561      if ($opt_valgrind && defined $t->{valgrind_comment}
562            && $t->{valgrind_comment} ne '') {
563        $aggregated_valgrind_report .= $t->{valgrind_comment};
564      }
565    }
566  }
567
568  @$completed = grep {$_->{name} ne "shutdown_report"} @$completed;
569
570  if (@$completed != $num_tests) {
571    # Not all tests completed
572    mtr_report();
573    mtr_report("Only ", int(@$completed), " of $num_tests completed.");
574    mtr_report("Not all tests completed. This means that a test scheduled for a worker did not report anything, the worker most likely crashed.");
575
576    my %comp;
577
578    foreach ( @$completed ) {
579      $comp{$_->{name}} = 1;
580    }
581    for (my $i = 0 ; $i <= @$all_tests ; $i++) {
582      my $t = $all_tests->[$i];
583      if (exists $t->{name} && !exists $comp{$t->{name}}) {
584        mtr_report("Missing result for testcase: ", $t->{name});
585      }
586    }
587  }
588
589  mark_time_used('init');
590
591  push @$completed, run_ctest() if $opt_ctest;
592
593  # Create minimalistic "test" for the reporting failures at shutdown
594  my $tinfo = My::Test->new(
595    name      => 'shutdown_report',
596    shortname => 'shutdown_report',
597    );
598
599  # Set dummy worker id to align report with normal tests
600  $tinfo->{worker} = 0 if $opt_parallel > 1;
601  if ($shutdown_report && $aggregated_shutdown_report ne '') {
602    $tinfo->{result} = 'MTR_RES_FAILED';
603    $tinfo->{comment} = "Mysqld reported failures at shutdown: \n$aggregated_shutdown_report";
604    $tinfo->{failures} = 1;
605  } else {
606    $tinfo->{result} = 'MTR_RES_PASSED';
607  }
608  mtr_report_test($tinfo);
609  report_option('prev_report_length', 0);
610  push @$completed, $tinfo;
611
612  if ($opt_valgrind) {
613    # Create minimalistic "test" for the reporting
614    my $tinfo = My::Test->new
615      (
616       name           => 'valgrind_report',
617      );
618    # Set dummy worker id to align report with normal tests
619    $tinfo->{worker} = 0 if $opt_parallel > 1;
620    if ($aggregated_valgrind_report ne '') {
621      $tinfo->{result}= 'MTR_RES_FAILED';
622      $tinfo->{comment}= "Valgrind reported failures at shutdown: \n$aggregated_valgrind_report";
623      $tinfo->{failures}= 1;
624    } else {
625      $tinfo->{result}= 'MTR_RES_PASSED';
626    }
627    mtr_report_test($tinfo);
628    mtr_report_test_subunit($tinfo);
629    push @$completed, $tinfo;
630  }
631
632  mtr_print_line();
633
634  if ( $opt_gcov ) {
635    gcov_collect($bindir, $opt_gcov_exe,
636		 $opt_gcov_msg, $opt_gcov_err);
637  }
638
639  if ($ctest_report) {
640    print "$ctest_report\n";
641    mtr_print_line();
642  }
643
644  if ($opt_ctest) {
645    find({ wanted => sub {
646             my $core_file= $File::Find::name;
647             my $core_name= basename($core_file);
648
649             if (is_core_dump($core_name)) {
650               mtr_report(" - found '$core_file'");
651
652               My::CoreDump->show($core_file, "", 1);
653             }
654       }}, $bindir);
655  }
656
657  print_total_times($opt_parallel) if $opt_report_times;
658
659  report_stats("Completed", $completed);
660
661  remove_vardir_subs() if $opt_clean_vardir;
662
663  exit(0);
664}
665
666
667sub report_stats($$;$) {
668  my ($prefix, $tests, $skip_error) = @_;
669
670  if ($opt_junit_output) {
671    mtr_report_stats_junit($tests, $opt_junit_output, $opt_junit_package);
672  }
673
674  mtr_report_stats($prefix, $tests, $skip_error);
675}
676
677
678sub run_test_server ($$$) {
679  my ($server, $tests, $childs) = @_;
680
681  my $num_saved_cores= 0;  # Number of core files saved in vardir/log/ so far.
682  my $num_saved_datadir= 0;  # Number of datadirs saved in vardir/log/ so far.
683  my $num_failed_test= 0; # Number of tests failed so far
684
685  # Scheduler variables
686  my $max_ndb= $ENV{MTR_MAX_NDB} || $childs / 2;
687  $max_ndb = $childs if $max_ndb > $childs;
688  $max_ndb = 1 if $max_ndb < 1;
689  my $num_ndb_tests= 0;
690
691  my $completed= [];
692  my %running;
693  my $result;
694  my $exe_mysqld= find_mysqld($basedir) || ""; # Used as hint to CoreDump
695
696  my $suite_timeout= start_timer(suite_timeout());
697
698  my $s= IO::Select->new();
699  $s->add($server);
700  while (1) {
701    mark_time_used('admin');
702    my @ready = $s->can_read(1); # Wake up once every second
703    mark_time_idle();
704    foreach my $sock (@ready) {
705      if ($sock == $server) {
706	# New client connected
707	my $child= $sock->accept();
708	mtr_verbose("Client connected");
709	$s->add($child);
710	print $child "HELLO\n";
711      }
712      else {
713	my $line= <$sock>;
714	if (!defined $line) {
715	  # Client disconnected
716	  mtr_verbose("Child closed socket");
717	  $s->remove($sock);
718	  if (--$childs == 0){
719	    return $completed;
720	  }
721	  next;
722	}
723	chomp($line);
724
725	if ($line eq 'TESTRESULT'){
726	  $result= My::Test::read_test($sock);
727	  # $result->print_test();
728
729	  # Report test status
730	  mtr_report_test($result);
731	  mtr_report_test_subunit($result);
732
733	  if ( $result->is_failed() ) {
734
735	    # Save the workers "savedir" in var/log
736	    my $worker_savedir= $result->{savedir};
737	    my $worker_savename= basename($worker_savedir);
738	    my $savedir= "$opt_vardir/log/$worker_savename";
739
740	    if ($opt_max_save_datadir > 0 &&
741		$num_saved_datadir >= $opt_max_save_datadir)
742	    {
743	      mtr_report(" - skipping '$worker_savedir/'");
744	      rmtree($worker_savedir);
745	    }
746            else
747            {
748              rename($worker_savedir, $savedir) if $worker_savedir ne $savedir;
749
750              # Look for the test log file and put that in savedir location
751              my $logfile= "$result->{shortname}" . ".log";
752              my $logfilepath= dirname($worker_savedir) . "/" . $logfile;
753              move($logfilepath, $savedir);
754              mtr_report(" - the logfile can be found in '$savedir/$logfile'");
755
756	      # Move any core files from e.g. mysqltest
757	      foreach my $coref (glob("core*"), glob("*.dmp"))
758	      {
759		mtr_report(" - found '$coref', moving it to '$savedir'");
760                move($coref, $savedir);
761              }
762	      if ($opt_max_save_core > 0) {
763		# Limit number of core files saved
764		find({ no_chdir => 1,
765		       wanted => sub {
766			 my $core_file= $File::Find::name;
767			 my $core_name= basename($core_file);
768
769                         if (is_core_dump($core_name)) {
770			   mtr_report(" - found '$core_name'",
771				      "($num_saved_cores/$opt_max_save_core)");
772
773			   My::CoreDump->show($core_file, $exe_mysqld, $opt_parallel);
774
775			   if ($num_saved_cores >= $opt_max_save_core) {
776			     mtr_report(" - deleting it, already saved",
777					"$opt_max_save_core");
778			     unlink("$core_file");
779			   } else {
780			     mtr_compress_file($core_file) unless @opt_cases;
781			   }
782			   ++$num_saved_cores;
783			 }
784		       }
785		     },
786		     $savedir);
787	      }
788	    }
789	    resfile_print_test();
790	    $num_saved_datadir++;
791	    $num_failed_test++ unless ($result->{retries} ||
792                                       $result->{exp_fail});
793
794	    if ( !$opt_force ) {
795	      # Test has failed, force is off
796	      push(@$completed, $result);
797	      return $completed unless $result->{'dont_kill_server'};
798	      # Prevent kill of server, to get valgrind report
799	      print $sock "BYE\n";
800	      next;
801	    }
802	    elsif ($opt_max_test_fail > 0 and
803		   $num_failed_test >= $opt_max_test_fail) {
804	      push(@$completed, $result);
805	      report_stats("Too many failed", $completed, 1);
806	      mtr_report("Too many tests($num_failed_test) failed!",
807			 "Terminating...");
808	      return undef;
809	    }
810	  }
811
812	  resfile_print_test();
813	  # Retry test run after test failure
814	  my $retries= $result->{retries} || 2;
815	  my $test_has_failed= $result->{failures} || 0;
816	  if ($test_has_failed and $retries <= $opt_retry){
817	    # Test should be run one more time unless it has failed
818	    # too many times already
819	    my $tname= $result->{name};
820	    my $failures= $result->{failures};
821	    if ($opt_retry > 1 and $failures >= $opt_retry_failure)
822            {
823	      mtr_report("\nTest $tname has failed $failures times,",
824			 "no more retries!\n");
825	    }
826	    else
827            {
828	      mtr_report("\nRetrying test $tname, ".
829			 "attempt($retries/$opt_retry)...\n");
830	      delete($result->{result});
831	      $result->{retries}= $retries + 1;
832	      $result->write_test($sock, 'TESTCASE');
833	      next;
834	    }
835	  }
836
837	  # Repeat test $opt_repeat number of times
838	  my $repeat= $result->{repeat} || 1;
839	  # Don't repeat if test was skipped
840	  if ($repeat < $opt_repeat && $result->{'result'} ne 'MTR_RES_SKIPPED')
841	  {
842	    $result->{retries}= 0;
843	    $result->{rep_failures}++ if $result->{failures};
844	    $result->{failures}= 0;
845	    delete($result->{result});
846	    $result->{repeat}= $repeat+1;
847	    $result->write_test($sock, 'TESTCASE');
848	    next;
849	  }
850
851	  # Remove from list of running
852	  mtr_error("'", $result->{name},"' is not known to be running")
853	    unless delete $running{$result->key()};
854
855	  # Update scheduler variables
856	  $num_ndb_tests-- if ($result->{ndb_test});
857
858	  # Save result in completed list
859	  push(@$completed, $result);
860
861	}
862	elsif ($line eq 'START'){
863	  ; # Send first test
864	}
865	elsif ($line =~ /^SPENT/) {
866	  add_total_times($line);
867	}
868	elsif ($line eq 'SHUTDOWN_REPORT') {
869      # Mysqld detected crash during shutdown
870      $shutdown_report = 1;
871      push(@$completed, My::Test::read_test($sock));
872	} else {
873	  mtr_error("Unknown response: '$line' from client");
874	}
875
876	# Find next test to schedule
877	# - Try to use same configuration as worker used last time
878	# - Limit number of parallel ndb tests
879
880	my $next;
881	my $second_best;
882	for(my $i= 0; $i <= @$tests; $i++)
883	{
884	  my $t= $tests->[$i];
885
886	  last unless defined $t;
887
888	  if (run_testcase_check_skip_test($t)){
889	    # Move the test to completed list
890	    #mtr_report("skip - Moving test $i to completed");
891	    push(@$completed, splice(@$tests, $i, 1));
892
893	    # Since the test at pos $i was taken away, next
894	    # test will also be at $i -> redo
895	    redo;
896	  }
897
898	  # Limit number of parallell NDB tests
899	  if ($t->{ndb_test} and $num_ndb_tests >= $max_ndb){
900	    #mtr_report("Skipping, num ndb is already at max, $num_ndb_tests");
901	    next;
902	  }
903
904	  # Second best choice is the first that does not fulfill
905	  # any of the above conditions
906	  if (!defined $second_best){
907	    #mtr_report("Setting second_best to $i");
908	    $second_best= $i;
909	  }
910
911	  # Smart allocation of next test within this thread.
912
913	  if ($opt_reorder and $opt_parallel > 1 and defined $result)
914	  {
915	    my $wid= $result->{worker};
916	    # Reserved for other thread, try next
917	    next if (defined $t->{reserved} and $t->{reserved} != $wid);
918	    if (! defined $t->{reserved})
919	    {
920	      # Force-restart not relevant when comparing *next* test
921	      $t->{criteria} =~ s/force-restart$/no-restart/;
922	      my $criteria= $t->{criteria};
923	      # Reserve similar tests for this worker, but not too many
924	      my $maxres= (@$tests - $i) / $opt_parallel + 1;
925	      for (my $j= $i+1; $j <= $i + $maxres; $j++)
926	      {
927		my $tt= $tests->[$j];
928		last unless defined $tt;
929		last if $tt->{criteria} ne $criteria;
930		$tt->{reserved}= $wid;
931	      }
932	    }
933	  }
934
935	  # At this point we have found next suitable test
936	  $next= splice(@$tests, $i, 1);
937	  last;
938	}
939
940	# Use second best choice if no other test has been found
941	if (!$next and defined $second_best){
942	  #mtr_report("Take second best choice $second_best");
943	  mtr_error("Internal error, second best too large($second_best)")
944	    if $second_best >  $#$tests;
945	  $next= splice(@$tests, $second_best, 1);
946	  delete $next->{reserved};
947	}
948
949	if ($next) {
950	  # We don't need this any more
951	  delete $next->{criteria};
952	  $next->write_test($sock, 'TESTCASE');
953	  $running{$next->key()}= $next;
954	  $num_ndb_tests++ if ($next->{ndb_test});
955	}
956	else {
957	  # No more test, tell child to exit
958	  #mtr_report("Saying BYE to child");
959	  print $sock "BYE\n";
960	}
961      }
962    }
963
964    # ----------------------------------------------------
965    # Check if test suite timer expired
966    # ----------------------------------------------------
967    if ( has_expired($suite_timeout) )
968    {
969      report_stats("Timeout", $completed, 1);
970      mtr_report("Test suite timeout! Terminating...");
971      return undef;
972    }
973  }
974}
975
976
977sub run_worker ($) {
978  my ($server_port, $thread_num)= @_;
979
980  $SIG{INT}= sub { exit(1); };
981
982  # Connect to server
983  my $server = new IO::Socket::INET
984    (
985     PeerAddr => 'localhost',
986     PeerPort => $server_port,
987     Proto    => 'tcp'
988    );
989  mtr_error("Could not connect to server at port $server_port: $!")
990    unless $server;
991
992  # --------------------------------------------------------------------------
993  # Set worker name
994  # --------------------------------------------------------------------------
995  report_option('name',"worker[$thread_num]");
996
997  # --------------------------------------------------------------------------
998  # Set different ports per thread
999  # --------------------------------------------------------------------------
1000  set_build_thread_ports($thread_num);
1001
1002  # --------------------------------------------------------------------------
1003  # Turn off verbosity in workers, unless explicitly specified
1004  # --------------------------------------------------------------------------
1005  report_option('verbose', undef) if ($opt_verbose == 0);
1006
1007  environment_setup();
1008
1009  # Read hello from server which it will send when shared
1010  # resources have been setup
1011  my $hello= <$server>;
1012
1013  setup_vardir();
1014  check_running_as_root();
1015
1016  if ( using_extern() ) {
1017    create_config_file_for_extern(%opts_extern);
1018  }
1019
1020  # Ask server for first test
1021  print $server "START\n";
1022
1023  mark_time_used('init');
1024
1025  while (my $line= <$server>){
1026    chomp($line);
1027    if ($line eq 'TESTCASE'){
1028      my $test= My::Test::read_test($server);
1029      #$test->print_test();
1030
1031      # Clear comment and logfile, to avoid
1032      # reusing them from previous test
1033      delete($test->{'comment'});
1034      delete($test->{'logfile'});
1035
1036      # A sanity check. Should this happen often we need to look at it.
1037      if (defined $test->{reserved} && $test->{reserved} != $thread_num) {
1038	my $tres= $test->{reserved};
1039	mtr_warning("Test reserved for w$tres picked up by w$thread_num");
1040      }
1041      $test->{worker} = $thread_num if $opt_parallel > 1;
1042
1043      run_testcase($test);
1044      #$test->{result}= 'MTR_RES_PASSED';
1045      # Send it back, now with results set
1046      #$test->print_test();
1047      $test->write_test($server, 'TESTRESULT');
1048      mark_time_used('restart');
1049    }
1050    elsif ($line eq 'BYE'){
1051      mtr_report("Server said BYE");
1052      my $found_err = 0;
1053      my $valgrind_report_text = '';
1054
1055      stop_all_servers($opt_shutdown_timeout);
1056
1057      if ($opt_valgrind_mysqld) {
1058        $valgrind_report_text = valgrind_exit_reports();
1059      }
1060
1061      if ($shutdown_report || $valgrind_report_text) {
1062        my $test = My::Test->new(
1063          name => 'shutdown_report',
1064          comment => $shutdown_report_text,
1065          valgrind_comment => $valgrind_report_text,
1066        );
1067        $test->write_test($server, "SHUTDOWN_REPORT");
1068        $found_err = 1;
1069      }
1070
1071      mark_time_used('restart');
1072
1073      if ( $opt_gprof ) {
1074        gprof_collect (find_mysqld($basedir), keys %gprof_dirs);
1075      }
1076
1077      mark_time_used('admin');
1078      print_times_used($server, $thread_num);
1079      exit($found_err);
1080    }
1081    else {
1082      mtr_error("Could not understand server, '$line'");
1083    }
1084  }
1085
1086  stop_all_servers();
1087
1088  exit(1);
1089}
1090
1091# Search server logs for any crashes during mysqld shutdown
1092sub shutdown_exit_reports() {
1093  my $found_report  = 0;
1094  my $clean_shutdown = 0;
1095  my $all_exit_reports = {};
1096
1097  foreach my $log_file (keys %mysqld_logs) {
1098    my @culprits = ();
1099    my $crash_rep     = "";
1100
1101    my $LOGF = IO::File->new($log_file) or
1102      mtr_error("Could not open file '$log_file' for reading: $!");
1103
1104    while (my $line = <$LOGF>) {
1105      if ($line =~ /^CURRENT_TEST: (.+)$/) {
1106        my $testname = $1;
1107        # If we have a report, report it if needed and start new list of tests
1108        if ($found_report or $clean_shutdown) {
1109          # Make ready to collect new report
1110          @culprits     = ();
1111          $found_report = 0;
1112          $clean_shutdown = 0;
1113          $crash_rep = "";
1114        }
1115        push(@culprits, $testname);
1116        next;
1117      }
1118
1119      # Clean shutdown
1120      $clean_shutdown = 1 if $line =~ /.*Shutdown completed.*/;
1121
1122      # Mysqld crash at shutdown
1123      $found_report = 1 if ($line =~ /.*Assertion.*/ or $line =~ /.*mysqld got signal.*/
1124                            or $line =~ /.*mysqld got exception.*/);
1125
1126      if ($found_report) {
1127        $crash_rep .= $line;
1128      }
1129    }
1130
1131    my $report_text = '';
1132
1133    if ($found_report) {
1134      $report_text = $crash_rep;
1135    } else {
1136      # Print last 100 lines of log file since shutdown failed
1137      # for some reason.
1138      $report_text = mtr_lastlinesfromfile($log_file, 100);
1139    }
1140
1141    $all_exit_reports->{$log_file} = {
1142      text => $report_text,
1143      after_tests => [@culprits],
1144    };
1145    $LOGF = undef;
1146  }
1147
1148  return $all_exit_reports;
1149}
1150
1151sub ignore_option {
1152  my ($opt, $value)= @_;
1153  mtr_report("Ignoring option '$opt'");
1154}
1155
1156
1157
1158# Setup any paths that are $opt_vardir related
1159sub set_vardir {
1160  my ($vardir)= @_;
1161
1162  $opt_vardir= $vardir;
1163
1164  $path_vardir_trace= $opt_vardir;
1165  # Chop off any "c:", DBUG likes a unix path ex: c:/src/... => /src/...
1166  $path_vardir_trace=~ s/^\w://;
1167
1168  # Location of my.cnf that all clients use
1169  $path_config_file= "$opt_vardir/my.cnf";
1170
1171  $path_testlog=         "$opt_vardir/log/mysqltest.log";
1172  $path_current_testlog= "$opt_vardir/log/current_test";
1173
1174}
1175
1176
1177sub print_global_resfile {
1178  resfile_global("start_time", isotime $^T);
1179  resfile_global("user_id", $<);
1180  resfile_global("embedded-server", $opt_embedded_server ? 1 : 0);
1181  resfile_global("ps-protocol", $opt_ps_protocol ? 1 : 0);
1182  resfile_global("sp-protocol", $opt_sp_protocol ? 1 : 0);
1183  resfile_global("view-protocol", $opt_view_protocol ? 1 : 0);
1184  resfile_global("cursor-protocol", $opt_cursor_protocol ? 1 : 0);
1185  resfile_global("ssl", $opt_ssl ? 1 : 0);
1186  resfile_global("compress", $opt_compress ? 1 : 0);
1187  resfile_global("parallel", $opt_parallel);
1188  resfile_global("check-testcases", $opt_check_testcases ? 1 : 0);
1189  resfile_global("mysqld", \@opt_extra_mysqld_opt);
1190  resfile_global("debug", $opt_debug ? 1 : 0);
1191  resfile_global("gcov", $opt_gcov ? 1 : 0);
1192  resfile_global("gprof", $opt_gprof ? 1 : 0);
1193  resfile_global("valgrind", $opt_valgrind ? 1 : 0);
1194  resfile_global("callgrind", $opt_callgrind ? 1 : 0);
1195  resfile_global("helgrind", $opt_helgrind ? 1 : 0);
1196  resfile_global("mem", $opt_mem ? 1 : 0);
1197  resfile_global("tmpdir", $opt_tmpdir);
1198  resfile_global("vardir", $opt_vardir);
1199  resfile_global("fast", $opt_fast ? 1 : 0);
1200  resfile_global("force-restart", $opt_force_restart ? 1 : 0);
1201  resfile_global("reorder", $opt_reorder ? 1 : 0);
1202  resfile_global("sleep", $opt_sleep);
1203  resfile_global("repeat", $opt_repeat);
1204  resfile_global("user", $opt_user);
1205  resfile_global("testcase-timeout", $opt_testcase_timeout);
1206  resfile_global("suite-timeout", $opt_suite_timeout);
1207  resfile_global("shutdown-timeout", $opt_shutdown_timeout ? 1 : 0);
1208  resfile_global("warnings", $opt_warnings ? 1 : 0);
1209  resfile_global("max-connections", $opt_max_connections);
1210#  resfile_global("default-myisam", $opt_default_myisam ? 1 : 0);
1211  resfile_global("product", "MySQL");
1212  # Somewhat hacky code to convert numeric version back to dot notation
1213  my $v1= int($mysql_version_id / 10000);
1214  my $v2= int(($mysql_version_id % 10000)/100);
1215  my $v3= $mysql_version_id % 100;
1216  resfile_global("version", "$v1.$v2.$v3");
1217}
1218
1219
1220
1221sub command_line_setup {
1222  my $opt_comment;
1223  my $opt_usage;
1224  my $opt_list_options;
1225
1226  # Read the command line options
1227  # Note: Keep list in sync with usage at end of this file
1228  Getopt::Long::Configure("pass_through");
1229  my %options=(
1230             # Control what engine/variation to run
1231             'embedded-server'          => \$opt_embedded_server,
1232             'ps-protocol'              => \$opt_ps_protocol,
1233             'sp-protocol'              => \$opt_sp_protocol,
1234             'view-protocol'            => \$opt_view_protocol,
1235             'opt-trace-protocol'       => \$opt_trace_protocol,
1236             'explain-protocol'         => \$opt_explain_protocol,
1237             'json-explain-protocol'    => \$opt_json_explain_protocol,
1238             'cursor-protocol'          => \$opt_cursor_protocol,
1239             'ssl|with-openssl'         => \$opt_ssl,
1240             'skip-ssl'                 => \$opt_skip_ssl,
1241             'compress'                 => \$opt_compress,
1242             'vs-config=s'              => \$opt_vs_config,
1243
1244	     # Max number of parallel threads to use
1245	     'parallel=s'               => \$opt_parallel,
1246
1247             # Config file to use as template for all tests
1248	     'defaults-file=s'          => \&collect_option,
1249	     # Extra config file to append to all generated configs
1250	     'defaults-extra-file=s'    => \&collect_option,
1251
1252             # Control what test suites or cases to run
1253             'force'                    => \$opt_force,
1254             'with-ndbcluster-only'     => \&collect_option,
1255             'ndb|include-ndbcluster'   => \$opt_include_ndbcluster,
1256             'skip-ndbcluster|skip-ndb' => \$opt_skip_ndbcluster,
1257             'suite|suites=s'           => \$opt_suites,
1258             'skip-rpl'                 => \&collect_option,
1259             'skip-test=s'              => \&collect_option,
1260             'do-test=s'                => \&collect_option,
1261             'start-from=s'             => \&collect_option,
1262             'big-test'                 => \$opt_big_test,
1263	     'combination=s'            => \@opt_combinations,
1264             'skip-combinations'        => \&collect_option,
1265             'experimental=s'           => \@opt_experimentals,
1266	     # skip-im is deprecated and silently ignored
1267	     'skip-im'                  => \&ignore_option,
1268
1269             # Specify ports
1270	     'build-thread|mtr-build-thread=i' => \$opt_build_thread,
1271	     'port-base|mtr-port-base=i'       => \$opt_port_base,
1272
1273             # Test case authoring
1274             'record'                   => \$opt_record,
1275             'check-testcases!'         => \$opt_check_testcases,
1276             'mark-progress'            => \$opt_mark_progress,
1277
1278             # Extra options used when starting mysqld
1279             'mysqld=s'                 => \@opt_extra_mysqld_opt,
1280             'mysqld-env=s'             => \@opt_mysqld_envs,
1281
1282             # Run test on running server
1283             'extern=s'                  => \%opts_extern, # Append to hash
1284
1285             # Debugging
1286             'debug'                    => \$opt_debug,
1287             'debug-common'             => \$opt_debug_common,
1288             'debug-server'             => \$opt_debug_server,
1289             'gdb'                      => \$opt_gdb,
1290             'client-gdb'               => \$opt_client_gdb,
1291             'manual-gdb'               => \$opt_manual_gdb,
1292             "lldb"                     => \$opt_lldb,
1293             'manual-lldb'              => \$opt_manual_lldb,
1294	     'boot-gdb'                 => \$opt_boot_gdb,
1295             'manual-debug'             => \$opt_manual_debug,
1296             'ddd'                      => \$opt_ddd,
1297             'client-ddd'               => \$opt_client_ddd,
1298             'manual-ddd'               => \$opt_manual_ddd,
1299	     'boot-ddd'                 => \$opt_boot_ddd,
1300             'dbx'                      => \$opt_dbx,
1301	     'client-dbx'               => \$opt_client_dbx,
1302	     'manual-dbx'               => \$opt_manual_dbx,
1303	     'debugger=s'               => \$opt_debugger,
1304	     'boot-dbx'                 => \$opt_boot_dbx,
1305	     'client-debugger=s'        => \$opt_client_debugger,
1306             'strace-server'            => \$opt_strace_server,
1307             'strace-client'            => \$opt_strace_client,
1308             'max-save-core=i'          => \$opt_max_save_core,
1309             'max-save-datadir=i'       => \$opt_max_save_datadir,
1310             'max-test-fail=i'          => \$opt_max_test_fail,
1311
1312             # Coverage, profiling etc
1313             'gcov'                     => \$opt_gcov,
1314             'gprof'                    => \$opt_gprof,
1315             'valgrind|valgrind-all'    => \$opt_valgrind,
1316             'valgrind-mysqltest'       => \$opt_valgrind_mysqltest,
1317             'valgrind-mysqld'          => \$opt_valgrind_mysqld,
1318             'valgrind-options=s'       => sub {
1319	       my ($opt, $value)= @_;
1320	       # Deprecated option unless it's what we know pushbuild uses
1321	       if ($value eq "--gen-suppressions=all --show-reachable=yes") {
1322		 push(@valgrind_args, $_) for (split(' ', $value));
1323		 return;
1324	       }
1325	       die("--valgrind-options=s is deprecated. Use ",
1326		   "--valgrind-option=s, to be specified several",
1327		   " times if necessary");
1328	     },
1329             'valgrind-option=s'        => \@valgrind_args,
1330             'valgrind-path=s'          => \$opt_valgrind_path,
1331	     'callgrind'                => \$opt_callgrind,
1332             'helgrind'                 => \$opt_helgrind,
1333	     'debug-sync-timeout=i'     => \$opt_debug_sync_timeout,
1334
1335	     # Directories
1336             'tmpdir=s'                 => \$opt_tmpdir,
1337             'vardir=s'                 => \$opt_vardir,
1338             'mem'                      => \$opt_mem,
1339	     'clean-vardir'             => \$opt_clean_vardir,
1340             'client-bindir=s'          => \$path_client_bindir,
1341             'client-libdir=s'          => \$path_client_libdir,
1342
1343             # Misc
1344             'report-features'          => \$opt_report_features,
1345             'comment=s'                => \$opt_comment,
1346             'fast'                     => \$opt_fast,
1347	     'force-restart'            => \$opt_force_restart,
1348             'reorder!'                 => \$opt_reorder,
1349             'enable-disabled'          => \&collect_option,
1350             'verbose+'                 => \$opt_verbose,
1351             'verbose-restart'          => \&report_option,
1352             'sleep=i'                  => \$opt_sleep,
1353             'start-dirty'              => \$opt_start_dirty,
1354             'start-and-exit'           => \$opt_start_exit,
1355             'start'                    => \$opt_start,
1356	     'user-args'                => \$opt_user_args,
1357             'wait-all'                 => \$opt_wait_all,
1358	     'print-testcases'          => \&collect_option,
1359	     'repeat=i'                 => \$opt_repeat,
1360	     'retry=i'                  => \$opt_retry,
1361	     'retry-failure=i'          => \$opt_retry_failure,
1362             'timer!'                   => \&report_option,
1363             'user=s'                   => \$opt_user,
1364             'testcase-timeout=i'       => \$opt_testcase_timeout,
1365             'suite-timeout=i'          => \$opt_suite_timeout,
1366             'shutdown-timeout=i'       => \$opt_shutdown_timeout,
1367             'warnings!'                => \$opt_warnings,
1368	     'timestamp'                => \&report_option,
1369	     'timediff'                 => \&report_option,
1370	     'max-connections=i'        => \$opt_max_connections,
1371	     'default-myisam!'          => \&collect_option,
1372	     'report-times'             => \$opt_report_times,
1373	     'result-file'              => \$opt_resfile,
1374	     'unit-tests!'              => \$opt_ctest,
1375	     'unit-tests-report!'	=> \$opt_ctest_report,
1376	     'stress=s'                 => \$opt_stress,
1377	     'junit-output=s'           => \$opt_junit_output,
1378	     'junit-package=s'          => \$opt_junit_package,
1379
1380             'help|h'                   => \$opt_usage,
1381	     # list-options is internal, not listed in help
1382	     'list-options'             => \$opt_list_options,
1383             'skip-test-list=s'         => \@opt_skip_test_list
1384           );
1385
1386  GetOptions(%options) or usage("Can't read options");
1387
1388  usage("") if $opt_usage;
1389  list_options(\%options) if $opt_list_options;
1390
1391  # Make sure that XML::Simple support exists for JUnit output
1392  if ($opt_junit_output and !mtr_junit_supported()) {
1393    mtr_error("JUnit XML reporting is not supported.  The XML::Simple package",
1394              "could not be loaded.");
1395  }
1396
1397  # --------------------------------------------------------------------------
1398  # Setup verbosity
1399  # --------------------------------------------------------------------------
1400  if ($opt_verbose != 0){
1401    report_option('verbose', $opt_verbose);
1402  }
1403
1404  if ( -d "../sql" )
1405  {
1406    $source_dist=  1;
1407  }
1408
1409  # Find the absolute path to the test directory
1410  $glob_mysql_test_dir= cwd();
1411  if ($glob_mysql_test_dir =~ / /)
1412  {
1413    die("Working directory \"$glob_mysql_test_dir\" contains space\n".
1414	"Bailing out, cannot function properly with space in path");
1415  }
1416  if (IS_CYGWIN)
1417  {
1418    # Use mixed path format i.e c:/path/to/
1419    $glob_mysql_test_dir= mixed_path($glob_mysql_test_dir);
1420  }
1421
1422  # In most cases, the base directory we find everything relative to,
1423  # is the parent directory of the "mysql-test" directory. For source
1424  # distributions, TAR binary distributions and some other packages.
1425  $basedir= dirname($glob_mysql_test_dir);
1426
1427  # In the RPM case, binaries and libraries are installed in the
1428  # default system locations, instead of having our own private base
1429  # directory. And we install "/usr/share/mysql-test". Moving up one
1430  # more directory relative to "mysql-test" gives us a usable base
1431  # directory for RPM installs.
1432  if ( ! $source_dist and ! -d "$basedir/bin" )
1433  {
1434    $basedir= dirname($basedir);
1435  }
1436
1437  # Respect MTR_BINDIR variable, which is typically set in to the
1438  # build directory in out-of-source builds.
1439  $bindir=$ENV{MTR_BINDIR}||$basedir;
1440
1441  # Look for the client binaries directory
1442  if ($path_client_bindir)
1443  {
1444    # --client-bindir=path set on command line, check that the path exists
1445    $path_client_bindir= mtr_path_exists($path_client_bindir);
1446  }
1447  else
1448  {
1449    $path_client_bindir= mtr_path_exists("$bindir/client_release",
1450					 "$bindir/client_debug",
1451					 vs_config_dirs('client', ''),
1452					 "$bindir/client",
1453					 "$bindir/bin");
1454  }
1455
1456  # Look for language files and charsetsdir, use same share
1457  $path_language=   mtr_path_exists("$bindir/share/mysql",
1458                                    "$bindir/sql/share",
1459                                    "$bindir/share");
1460  my $path_share= $path_language;
1461  $path_charsetsdir =   mtr_path_exists("$basedir/share/mysql/charsets",
1462                                    "$basedir/sql/share/charsets",
1463                                    "$basedir/share/charsets");
1464
1465  ($auth_plugin)= find_plugin("auth_test_plugin", "plugin/auth");
1466
1467  # --debug[-common] implies we run debug server
1468  $opt_debug_server= 1 if $opt_debug || $opt_debug_common;
1469
1470  if (using_extern())
1471  {
1472    # Connect to the running mysqld and find out what it supports
1473    collect_mysqld_features_from_running_server();
1474  }
1475  else
1476  {
1477    # Run the mysqld to find out what features are available
1478    collect_mysqld_features();
1479  }
1480
1481  if ( $opt_comment )
1482  {
1483    mtr_report();
1484    mtr_print_thick_line('#');
1485    mtr_report("# $opt_comment");
1486    mtr_print_thick_line('#');
1487  }
1488
1489  if ( @opt_experimentals )
1490  {
1491    # $^O on Windows considered not generic enough
1492    my $plat= (IS_WINDOWS) ? 'windows' : $^O;
1493
1494    # read the list of experimental test cases from the files specified on
1495    # the command line
1496    $experimental_test_cases = [];
1497    foreach my $exp_file (@opt_experimentals)
1498    {
1499      open(FILE, "<", $exp_file)
1500	or mtr_error("Can't read experimental file: $exp_file");
1501      mtr_report("Using experimental file: $exp_file");
1502      while(<FILE>) {
1503	chomp;
1504	# remove comments (# foo) at the beginning of the line, or after a
1505	# blank at the end of the line
1506	s/(\s+|^)#.*$//;
1507	# If @ platform specifier given, use this entry only if it contains
1508	# @<platform> or @!<xxx> where xxx != platform
1509	if (/\@.*/)
1510	{
1511	  next if (/\@!$plat/);
1512	  next unless (/\@$plat/ or /\@!/);
1513	  # Then remove @ and everything after it
1514	  s/\@.*$//;
1515	}
1516	# remove whitespace
1517	s/^\s+//;
1518	s/\s+$//;
1519	# if nothing left, don't need to remember this line
1520	if ( $_ eq "" ) {
1521	  next;
1522	}
1523	# remember what is left as the name of another test case that should be
1524	# treated as experimental
1525	print " - $_\n";
1526	push @$experimental_test_cases, $_;
1527      }
1528      close FILE;
1529    }
1530  }
1531
1532  foreach my $arg ( @ARGV )
1533  {
1534    if ( $arg =~ /^--skip-/ )
1535    {
1536      push(@opt_extra_mysqld_opt, $arg);
1537    }
1538    elsif ( $arg =~ /^--$/ )
1539    {
1540      # It is an effect of setting 'pass_through' in option processing
1541      # that the lone '--' separating options from arguments survives,
1542      # simply ignore it.
1543    }
1544    elsif ( $arg =~ /^-/ )
1545    {
1546      usage("Invalid option \"$arg\"");
1547    }
1548    else
1549    {
1550      push(@opt_cases, $arg);
1551    }
1552  }
1553
1554  # --------------------------------------------------------------------------
1555  # Find out type of logging that are being used
1556  # --------------------------------------------------------------------------
1557  foreach my $arg ( @opt_extra_mysqld_opt )
1558  {
1559    if ( $arg =~ /binlog[-_]format=(\S+)/ )
1560    {
1561      # Save this for collect phase
1562      collect_option('binlog-format', $1);
1563      mtr_report("Using binlog format '$1'");
1564    }
1565  }
1566
1567
1568  # --------------------------------------------------------------------------
1569  # Find out default storage engine being used(if any)
1570  # --------------------------------------------------------------------------
1571  foreach my $arg ( @opt_extra_mysqld_opt )
1572  {
1573    if ( $arg =~ /default-storage-engine=(\S+)/ )
1574    {
1575      # Save this for collect phase
1576      collect_option('default-storage-engine', $1);
1577      mtr_report("Using default engine '$1'")
1578    }
1579    if ( $arg =~ /default-tmp-storage-engine=(\S+)/ )
1580    {
1581      # Save this for collect phase
1582      collect_option('default-tmp-storage-engine', $1);
1583      mtr_report("Using default tmp engine '$1'")
1584    }
1585  }
1586
1587  if (IS_WINDOWS and defined $opt_mem) {
1588    mtr_report("--mem not supported on Windows, ignored");
1589    $opt_mem= undef;
1590  }
1591
1592  if ($opt_port_base ne "auto")
1593  {
1594    if (my $rem= $opt_port_base % 10)
1595    {
1596      mtr_warning ("Port base $opt_port_base rounded down to multiple of 10");
1597      $opt_port_base-= $rem;
1598    }
1599    $opt_build_thread= $opt_port_base / 10 - 1000;
1600  }
1601
1602  # --------------------------------------------------------------------------
1603  # Check if we should speed up tests by trying to run on tmpfs
1604  # --------------------------------------------------------------------------
1605  if ( defined $opt_mem)
1606  {
1607    mtr_error("Can't use --mem and --vardir at the same time ")
1608      if $opt_vardir;
1609    mtr_error("Can't use --mem and --tmpdir at the same time ")
1610      if $opt_tmpdir;
1611
1612    # Search through list of locations that are known
1613    # to be "fast disks" to find a suitable location
1614    # Use --mem=<dir> as first location to look.
1615    my @tmpfs_locations= ($opt_mem, "/dev/shm", "/tmp");
1616
1617    foreach my $fs (@tmpfs_locations)
1618    {
1619      if ( -d $fs )
1620      {
1621	my $template= "var_${opt_build_thread}_XXXX";
1622	$opt_mem= tempdir( $template, DIR => $fs, CLEANUP => 0);
1623	last;
1624      }
1625    }
1626  }
1627
1628  # --------------------------------------------------------------------------
1629  # Set the "var/" directory, the base for everything else
1630  # --------------------------------------------------------------------------
1631  if(defined $ENV{MTR_BINDIR})
1632  {
1633    $default_vardir= "$ENV{MTR_BINDIR}/mysql-test/var";
1634  }
1635  else
1636  {
1637    $default_vardir= "$glob_mysql_test_dir/var";
1638  }
1639  if ( ! $opt_vardir )
1640  {
1641    $opt_vardir= $default_vardir;
1642  }
1643
1644  # We make the path absolute, as the server will do a chdir() before usage
1645  unless ( $opt_vardir =~ m,^/, or
1646           (IS_WINDOWS and $opt_vardir =~ m,^[a-z]:[/\\],i) )
1647  {
1648    # Make absolute path, relative test dir
1649    $opt_vardir= "$glob_mysql_test_dir/$opt_vardir";
1650  }
1651
1652  set_vardir($opt_vardir);
1653
1654  # --------------------------------------------------------------------------
1655  # Set the "tmp" directory
1656  # --------------------------------------------------------------------------
1657  if ( ! $opt_tmpdir )
1658  {
1659    $opt_tmpdir=       "$opt_vardir/tmp" unless $opt_tmpdir;
1660
1661    if (check_socket_path_length("$opt_tmpdir/mysql_testsocket.sock"))
1662    {
1663      mtr_report("Too long tmpdir path '$opt_tmpdir'",
1664		 " creating a shorter one...");
1665
1666      # Create temporary directory in standard location for temporary files
1667      $opt_tmpdir= tempdir( TMPDIR => 1, CLEANUP => 0 );
1668      mtr_report(" - using tmpdir: '$opt_tmpdir'\n");
1669
1670      # Remember pid that created dir so it's removed by correct process
1671      $opt_tmpdir_pid= $$;
1672    }
1673  }
1674  $opt_tmpdir =~ s,/+$,,;       # Remove ending slash if any
1675
1676  # --------------------------------------------------------------------------
1677  # fast option
1678  # --------------------------------------------------------------------------
1679  if ($opt_fast){
1680    $opt_shutdown_timeout= 0; # Kill processes instead of nice shutdown
1681  }
1682
1683  # --------------------------------------------------------------------------
1684  # Check parallel value
1685  # --------------------------------------------------------------------------
1686  if ($opt_parallel ne "auto" && $opt_parallel < 1)
1687  {
1688    mtr_error("0 or negative parallel value makes no sense, use 'auto' or positive number");
1689  }
1690
1691  # --------------------------------------------------------------------------
1692  # Record flag
1693  # --------------------------------------------------------------------------
1694  if ( $opt_record and ! @opt_cases )
1695  {
1696    mtr_error("Will not run in record mode without a specific test case");
1697  }
1698
1699  if ( $opt_record ) {
1700    # Use only one worker with --record
1701    $opt_parallel= 1;
1702  }
1703
1704  # --------------------------------------------------------------------------
1705  # Embedded server flag
1706  # --------------------------------------------------------------------------
1707  if ( $opt_embedded_server )
1708  {
1709    if ( IS_WINDOWS )
1710    {
1711      # Add the location for libmysqld.dll to the path.
1712      my $separator= ";";
1713      my $lib_mysqld=
1714        mtr_path_exists("$bindir/lib", vs_config_dirs('libmysqld',''));
1715      if ( IS_CYGWIN )
1716      {
1717	$lib_mysqld= posix_path($lib_mysqld);
1718	$separator= ":";
1719      }
1720      $ENV{'PATH'}= "$ENV{'PATH'}".$separator.$lib_mysqld;
1721    }
1722    $opt_skip_ssl= 1;              # Turn off use of SSL
1723
1724    # Turn off use of bin log
1725    push(@opt_extra_mysqld_opt, "--skip-log-bin");
1726
1727    if ( using_extern() )
1728    {
1729      mtr_error("Can't use --extern with --embedded-server");
1730    }
1731
1732
1733    if ($opt_gdb)
1734    {
1735      mtr_warning("Silently converting --gdb to --client-gdb in embedded mode");
1736      $opt_client_gdb= $opt_gdb;
1737      $opt_gdb= undef;
1738    }
1739
1740    if ($opt_ddd)
1741    {
1742      mtr_warning("Silently converting --ddd to --client-ddd in embedded mode");
1743      $opt_client_ddd= $opt_ddd;
1744      $opt_ddd= undef;
1745    }
1746
1747    if ($opt_dbx) {
1748      mtr_warning("Silently converting --dbx to --client-dbx in embedded mode");
1749      $opt_client_dbx= $opt_dbx;
1750      $opt_dbx= undef;
1751    }
1752
1753    if ($opt_debugger)
1754    {
1755      mtr_warning("Silently converting --debugger to --client-debugger in embedded mode");
1756      $opt_client_debugger= $opt_debugger;
1757      $opt_debugger= undef;
1758    }
1759
1760    if ( $opt_gdb || $opt_ddd || $opt_manual_gdb || $opt_lldb || $opt_manual_lldb ||
1761         $opt_manual_ddd || $opt_manual_debug || $opt_debugger || $opt_dbx ||
1762         $opt_manual_dbx)
1763    {
1764      mtr_error("You need to use the client debug options for the",
1765		"embedded server. Ex: --client-gdb");
1766    }
1767  }
1768
1769  # --------------------------------------------------------------------------
1770  # Big test flags
1771  # --------------------------------------------------------------------------
1772   if ( $opt_big_test )
1773   {
1774     $ENV{'BIG_TEST'}= 1;
1775   }
1776
1777  # --------------------------------------------------------------------------
1778  # Gcov flag
1779  # --------------------------------------------------------------------------
1780  if ( ($opt_gcov or $opt_gprof) and ! $source_dist )
1781  {
1782    mtr_error("Coverage test needs the source - please use source dist");
1783  }
1784
1785  # --------------------------------------------------------------------------
1786  # Check debug related options
1787  # --------------------------------------------------------------------------
1788  if ( $opt_gdb || $opt_client_gdb || $opt_ddd || $opt_client_ddd ||
1789       $opt_manual_gdb || $opt_lldb || $opt_manual_lldb || $opt_manual_ddd ||
1790       $opt_manual_debug || $opt_dbx || $opt_client_dbx || $opt_manual_dbx ||
1791       $opt_debugger || $opt_client_debugger )
1792  {
1793    # Indicate that we are using debugger
1794    $glob_debugger= 1;
1795    if ( using_extern() )
1796    {
1797      mtr_error("Can't use --extern when using debugger");
1798    }
1799    # Set one week timeout (check-testcase timeout will be 1/10th)
1800    $opt_testcase_timeout= 7 * 24 * 60;
1801    $opt_suite_timeout= 7 * 24 * 60;
1802    # One day to shutdown
1803    $opt_shutdown_timeout= 24 * 60;
1804    # One day for PID file creation (this is given in seconds not minutes)
1805    $opt_start_timeout= 24 * 60 * 60;
1806  }
1807
1808  # --------------------------------------------------------------------------
1809  # Modified behavior with --start options
1810  # --------------------------------------------------------------------------
1811  if ($opt_start or $opt_start_dirty or $opt_start_exit) {
1812    collect_option ('quick-collect', 1);
1813    $start_only= 1;
1814  }
1815
1816  # --------------------------------------------------------------------------
1817  # Check use of user-args
1818  # --------------------------------------------------------------------------
1819
1820  if ($opt_user_args) {
1821    mtr_error("--user-args only valid with --start options")
1822      unless $start_only;
1823    mtr_error("--user-args cannot be combined with named suites or tests")
1824      if $opt_suites || @opt_cases;
1825  }
1826
1827  # --------------------------------------------------------------------------
1828  # Set default values for opt_ctest (--unit-tests)
1829  # --------------------------------------------------------------------------
1830
1831  if ($opt_ctest == -1) {
1832    if (defined $opt_ctest_report && $opt_ctest_report) {
1833      # Turn on --unit-tests by default if --unit-tests-report is used
1834      $opt_ctest= 1;
1835    } elsif ($opt_suites || @opt_cases) {
1836      # Don't run ctest if tests or suites named
1837      $opt_ctest= 0;
1838    } elsif (defined $ENV{PB2WORKDIR}) {
1839      # Override: disable if running in the PB test environment
1840      $opt_ctest= 0;
1841    }
1842  }
1843
1844  # --------------------------------------------------------------------------
1845  # Check use of wait-all
1846  # --------------------------------------------------------------------------
1847
1848  if ($opt_wait_all && ! $start_only)
1849  {
1850    mtr_error("--wait-all can only be used with --start options");
1851  }
1852
1853  # --------------------------------------------------------------------------
1854  # Gather stress-test options and modify behavior
1855  # --------------------------------------------------------------------------
1856
1857  if ($opt_stress)
1858  {
1859    $opt_stress=~ s/,/ /g;
1860    $opt_user_args= 1;
1861    mtr_error("--stress cannot be combined with named ordinary suites or tests")
1862      if $opt_suites || @opt_cases;
1863    $opt_suites="stress";
1864    @opt_cases= ("wrapper");
1865    $ENV{MST_OPTIONS}= $opt_stress;
1866    $opt_ctest= 0;
1867  }
1868
1869  # --------------------------------------------------------------------------
1870  # Check timeout arguments
1871  # --------------------------------------------------------------------------
1872
1873  mtr_error("Invalid value '$opt_testcase_timeout' supplied ".
1874	    "for option --testcase-timeout")
1875    if ($opt_testcase_timeout <= 0);
1876  mtr_error("Invalid value '$opt_suite_timeout' supplied ".
1877	    "for option --testsuite-timeout")
1878    if ($opt_suite_timeout <= 0);
1879
1880  # --------------------------------------------------------------------------
1881  # Check trace protocol option
1882  # --------------------------------------------------------------------------
1883  if ( $opt_trace_protocol )
1884  {
1885    push(@opt_extra_mysqld_opt, "--optimizer_trace=enabled=on,one_line=off");
1886    # Some queries yield big traces:
1887    push(@opt_extra_mysqld_opt, "--optimizer-trace-max-mem-size=1000000");
1888  }
1889
1890  # --------------------------------------------------------------------------
1891  # Check valgrind arguments
1892  # --------------------------------------------------------------------------
1893  if ( $opt_valgrind or $opt_valgrind_path or @valgrind_args)
1894  {
1895    mtr_report("Turning on valgrind for all executables");
1896    $opt_valgrind= 1;
1897    $opt_valgrind_mysqld= 1;
1898    $opt_valgrind_mysqltest= 1;
1899
1900    # Increase the timeouts when running with valgrind
1901    $opt_testcase_timeout*= 10;
1902    $opt_suite_timeout*= 6;
1903    $opt_start_timeout*= 10;
1904    $opt_debug_sync_timeout*= 10;
1905  }
1906  elsif ( $opt_valgrind_mysqld )
1907  {
1908    mtr_report("Turning on valgrind for mysqld(s) only");
1909    $opt_valgrind= 1;
1910  }
1911  elsif ( $opt_valgrind_mysqltest )
1912  {
1913    mtr_report("Turning on valgrind for mysqltest and mysql_client_test only");
1914    $opt_valgrind= 1;
1915  }
1916
1917  if ( $opt_helgrind )
1918  {
1919    mtr_report("Turning on valgrind with helgrind for mysqld(s)");
1920    $opt_valgrind= 1;
1921    $opt_valgrind_mysqld= 1;
1922
1923    push(@valgrind_args, "--tool=helgrind");
1924  }
1925
1926  if ( $opt_callgrind )
1927  {
1928    mtr_report("Turning on valgrind with callgrind for mysqld(s)");
1929    $opt_valgrind= 1;
1930    $opt_valgrind_mysqld= 1;
1931
1932    push(@valgrind_args, "--tool=callgrind", "--trace-children=yes");
1933
1934    # Increase the timeouts when running with callgrind
1935    $opt_testcase_timeout*= 10;
1936    $opt_suite_timeout*= 6;
1937    $opt_start_timeout*= 10;
1938    $opt_debug_sync_timeout*= 10;
1939  }
1940
1941  if ($opt_valgrind)
1942  {
1943    # Default to --tool=memcheck if no other tool has been explicitly
1944    # specified. From >= 2.1.2, this option is needed
1945    if (!@valgrind_args or !grep(/^--tool=/, @valgrind_args))
1946    {
1947      # Set default valgrind options for memcheck, can be overriden by user
1948      unshift(@valgrind_args, ("--tool=memcheck", "--num-callers=16",
1949                               "--show-reachable=yes"));
1950    }
1951
1952    # Add suppression file if not specified
1953    if (!grep(/^--suppressions=/, @valgrind_args))
1954    {
1955      push(@valgrind_args,"--suppressions=${glob_mysql_test_dir}/valgrind.supp")
1956           if -f "$glob_mysql_test_dir/valgrind.supp";
1957    }
1958
1959    # Don't add --quiet; you will loose the summary reports.
1960    mtr_report("Running valgrind with options \"",
1961               join(" ", @valgrind_args), "\"");
1962
1963    # Turn off check testcases to save time
1964    mtr_report("Turning off --check-testcases to save time when valgrinding");
1965    $opt_check_testcases = 0;
1966  }
1967
1968  if ($opt_debug_common)
1969  {
1970    $opt_debug= 1;
1971    $debug_d= "d,query,info,error,enter,exit";
1972  }
1973
1974  if ( $opt_strace_server && ($^O ne "linux") )
1975  {
1976    $opt_strace_server=0;
1977    mtr_warning("Strace only supported in Linux ");
1978  }
1979
1980  if ( $opt_strace_client && ($^O ne "linux") )
1981  {
1982    $opt_strace_client=0;
1983    mtr_warning("Strace only supported in Linux ");
1984  }
1985
1986
1987  mtr_report("Checking supported features...");
1988
1989  check_ndbcluster_support(\%mysqld_variables);
1990  check_ssl_support(\%mysqld_variables);
1991  check_debug_support(\%mysqld_variables);
1992
1993  executable_setup();
1994
1995}
1996
1997
1998#
1999# To make it easier for different devs to work on the same host,
2000# an environment variable can be used to control all ports. A small
2001# number is to be used, 0 - 16 or similar.
2002#
2003# Note the MASTER_MYPORT has to be set the same in all 4.x and 5.x
2004# versions of this script, else a 4.0 test run might conflict with a
2005# 5.1 test run, even if different MTR_BUILD_THREAD is used. This means
2006# all port numbers might not be used in this version of the script.
2007#
2008# Also note the limitation of ports we are allowed to hand out. This
2009# differs between operating systems and configuration, see
2010# http://www.ncftp.com/ncftpd/doc/misc/ephemeral_ports.html
2011# But a fairly safe range seems to be 5001 - 32767
2012#
2013sub set_build_thread_ports($) {
2014  my $thread= shift || 0;
2015
2016  if ( lc($opt_build_thread) eq 'auto' ) {
2017    my $found_free = 0;
2018    $build_thread = 300;	# Start attempts from here
2019
2020    my $build_thread_upper = $build_thread + ($opt_parallel > 39
2021                             ? $opt_parallel + int($opt_parallel / 4)
2022                             : 49);
2023    while (! $found_free)
2024    {
2025      $build_thread= mtr_get_unique_id($build_thread, $build_thread_upper);
2026      if ( !defined $build_thread ) {
2027        mtr_error("Could not get a unique build thread id");
2028      }
2029      $found_free= check_ports_free($build_thread);
2030      # If not free, release and try from next number
2031      if (! $found_free) {
2032        mtr_release_unique_id();
2033        $build_thread++;
2034      }
2035    }
2036  }
2037  else
2038  {
2039    $build_thread = $opt_build_thread + $thread - 1;
2040    if (! check_ports_free($build_thread)) {
2041      # Some port was not free(which one has already been printed)
2042      mtr_error("Some port(s) was not free")
2043    }
2044  }
2045  $ENV{MTR_BUILD_THREAD}= $build_thread;
2046
2047  # Calculate baseport
2048  $baseport= $build_thread * 10 + 10000;
2049  if ( $baseport < 5001 or $baseport + 9 >= 32767 )
2050  {
2051    mtr_error("MTR_BUILD_THREAD number results in a port",
2052              "outside 5001 - 32767",
2053              "($baseport - $baseport + 9)");
2054  }
2055
2056  mtr_report("Using MTR_BUILD_THREAD $build_thread,",
2057	     "with reserved ports $baseport..".($baseport+9));
2058
2059}
2060
2061
2062sub collect_mysqld_features {
2063  my $found_variable_list_start= 0;
2064  my $use_tmpdir;
2065  if ( defined $opt_tmpdir and -d $opt_tmpdir){
2066    # Create the tempdir in $opt_tmpdir
2067    $use_tmpdir= $opt_tmpdir;
2068  }
2069  my $tmpdir= tempdir(CLEANUP => 0, # Directory removed by this function
2070		      DIR => $use_tmpdir);
2071
2072  #
2073  # Execute "mysqld --no-defaults --help --verbose" to get a
2074  # list of all features and settings
2075  #
2076  # --no-defaults and --skip-grant-tables are to avoid loading
2077  # system-wide configs and plugins
2078  #
2079  # --datadir must exist, mysqld will chdir into it
2080  #
2081  my $args;
2082  mtr_init_args(\$args);
2083  mtr_add_arg($args, "--no-defaults");
2084  mtr_add_arg($args, "--basedir=%s", $basedir);
2085  mtr_add_arg($args, "--datadir=%s", mixed_path($tmpdir));
2086  mtr_add_arg($args, "--secure-file-priv=\"\"");
2087  mtr_add_arg($args, "--lc-messages-dir=%s", $path_language);
2088  mtr_add_arg($args, "--skip-grant-tables");
2089  mtr_add_arg($args, "--verbose");
2090  mtr_add_arg($args, "--help");
2091
2092  # Need --user=root if running as *nix root user
2093  if (!IS_WINDOWS and $> == 0)
2094  {
2095    mtr_add_arg($args, "--user=root");
2096  }
2097
2098  foreach my $extra_opt (@opt_extra_mysqld_opt) {
2099    if ($extra_opt =~ /--plugin-load/) {
2100      mtr_add_arg($args, $extra_opt);
2101    }
2102  }
2103
2104  my $exe_mysqld= find_mysqld($basedir);
2105  my $cmd= join(" ", $exe_mysqld, @$args);
2106  my $list= `$cmd`;
2107
2108  foreach my $line (split('\n', $list))
2109  {
2110    # First look for version
2111    if ( !$mysql_version_id )
2112    {
2113      # Look for version
2114      my $exe_name= basename($exe_mysqld);
2115      mtr_verbose("exe_name: $exe_name");
2116      if ( $line =~ /^\S*$exe_name\s\sVer\s([0-9]*)\.([0-9]*)\.([0-9]*)([^\s]*)/ )
2117      {
2118	#print "Major: $1 Minor: $2 Build: $3\n";
2119	$mysql_version_id= $1*10000 + $2*100 + $3;
2120	#print "mysql_version_id: $mysql_version_id\n";
2121	mtr_report("MySQL Version $1.$2.$3");
2122	$mysql_version_extra= $4;
2123      }
2124    }
2125    else
2126    {
2127      if (!$found_variable_list_start)
2128      {
2129	# Look for start of variables list
2130	if ( $line =~ /[\-]+\s[\-]+/ )
2131	{
2132	  $found_variable_list_start= 1;
2133	}
2134      }
2135      else
2136      {
2137	# Put variables into hash
2138	if ( $line =~ /^([\S]+)[ \t]+(.*?)\r?$/ )
2139	{
2140	  # print "$1=\"$2\"\n";
2141	  $mysqld_variables{$1}= $2;
2142	}
2143	else
2144	{
2145	  # The variable list is ended with a blank line
2146	  if ( $line =~ /^[\s]*$/ )
2147	  {
2148	    last;
2149	  }
2150	  else
2151	  {
2152	    # Send out a warning, we should fix the variables that has no
2153	    # space between variable name and it's value
2154	    # or should it be fixed width column parsing? It does not
2155	    # look like that in function my_print_variables in my_getopt.c
2156	    mtr_warning("Could not parse variable list line : $line");
2157	  }
2158	}
2159      }
2160    }
2161  }
2162  rmtree($tmpdir);
2163  mtr_error("Could not find version of MySQL") unless $mysql_version_id;
2164  mtr_error("Could not find variabes list") unless $found_variable_list_start;
2165
2166}
2167
2168
2169
2170sub collect_mysqld_features_from_running_server ()
2171{
2172  my $mysql= mtr_exe_exists("$path_client_bindir/mysql");
2173
2174  my $args;
2175  mtr_init_args(\$args);
2176
2177  mtr_add_arg($args, "--no-defaults");
2178  mtr_add_arg($args, "--user=%s", $opt_user);
2179
2180  while (my ($option, $value)= each( %opts_extern )) {
2181    mtr_add_arg($args, "--$option=$value");
2182  }
2183
2184  mtr_add_arg($args, "--silent"); # Tab separated output
2185  mtr_add_arg($args, "-e '%s'", "use mysql; SHOW VARIABLES");
2186  my $cmd= "$mysql " . join(' ', @$args);
2187  mtr_verbose("cmd: $cmd");
2188
2189  my $list = `$cmd` or
2190    mtr_error("Could not connect to extern server using command: '$cmd'");
2191  foreach my $line (split('\n', $list ))
2192  {
2193    # Put variables into hash
2194    if ( $line =~ /^([\S]+)[ \t]+(.*?)\r?$/ )
2195    {
2196      # print "$1=\"$2\"\n";
2197      $mysqld_variables{$1}= $2;
2198    }
2199  }
2200
2201  # "Convert" innodb flag
2202  $mysqld_variables{'innodb'}= "ON"
2203    if ($mysqld_variables{'have_innodb'} eq "YES");
2204
2205  # Parse version
2206  my $version_str= $mysqld_variables{'version'};
2207  if ( $version_str =~ /^([0-9]*)\.([0-9]*)\.([0-9]*)([^\s]*)/ )
2208  {
2209    #print "Major: $1 Minor: $2 Build: $3\n";
2210    $mysql_version_id= $1*10000 + $2*100 + $3;
2211    #print "mysql_version_id: $mysql_version_id\n";
2212    mtr_report("MySQL Version $1.$2.$3");
2213    $mysql_version_extra= $4;
2214  }
2215  mtr_error("Could not find version of MySQL") unless $mysql_version_id;
2216}
2217
2218sub find_mysqld {
2219
2220  my ($mysqld_basedir)= $ENV{MTR_BINDIR}|| @_;
2221
2222  my @mysqld_names= ("mysqld", "mysqld-max-nt", "mysqld-max",
2223		     "mysqld-nt");
2224
2225  if ( $opt_debug_server ){
2226    # Put mysqld-debug first in the list of binaries to look for
2227    mtr_verbose("Adding mysqld-debug first in list of binaries to look for");
2228    unshift(@mysqld_names, "mysqld-debug");
2229  }
2230
2231  return my_find_bin($mysqld_basedir,
2232		     ["sql", "libexec", "sbin", "bin"],
2233		     [@mysqld_names]);
2234}
2235
2236
2237sub executable_setup () {
2238
2239  #
2240  # Check if libtool is available in this distribution/clone
2241  # we need it when valgrinding or debugging non installed binary
2242  # Otherwise valgrind will valgrind the libtool wrapper or bash
2243  # and gdb will not find the real executable to debug
2244  #
2245  if ( -x "../libtool")
2246  {
2247    $exe_libtool= "../libtool";
2248    if ($opt_valgrind or $glob_debugger)
2249    {
2250      mtr_report("Using \"$exe_libtool\" when running valgrind or debugger");
2251    }
2252  }
2253
2254  # Look for the client binaries
2255  $exe_mysqladmin=     mtr_exe_exists("$path_client_bindir/mysqladmin");
2256  $exe_mysql=          mtr_exe_exists("$path_client_bindir/mysql");
2257  $exe_mysql_plugin=   mtr_exe_exists("$path_client_bindir/mysql_plugin");
2258
2259  $exe_mysql_embedded=
2260    mtr_exe_maybe_exists(vs_config_dirs('libmysqld/examples','mysql_embedded'),
2261                         "$bindir/libmysqld/examples/mysql_embedded",
2262                         "$bindir/bin/mysql_embedded");
2263
2264  if ( $ndbcluster_enabled )
2265  {
2266    # Look for single threaded NDB
2267    $exe_ndbd=
2268      my_find_bin($bindir,
2269		  ["storage/ndb/src/kernel", "libexec", "sbin", "bin"],
2270		  "ndbd");
2271
2272    # Look for multi threaded NDB
2273    $exe_ndbmtd=
2274      my_find_bin($bindir,
2275		  ["storage/ndb/src/kernel", "libexec", "sbin", "bin"],
2276		  "ndbmtd", NOT_REQUIRED);
2277    if ($exe_ndbmtd)
2278    {
2279      my $mtr_ndbmtd = $ENV{MTR_NDBMTD};
2280      if ($mtr_ndbmtd)
2281      {
2282	mtr_report(" - multi threaded ndbd found, will be used always");
2283	$exe_ndbd = $exe_ndbmtd;
2284      }
2285      else
2286      {
2287	mtr_report(" - multi threaded ndbd found, will be ".
2288		   "used \"round robin\"");
2289      }
2290    }
2291
2292    $exe_ndb_mgmd=
2293      my_find_bin($bindir,
2294		  ["storage/ndb/src/mgmsrv", "libexec", "sbin", "bin"],
2295		  "ndb_mgmd");
2296
2297    $exe_ndb_mgm=
2298      my_find_bin($bindir,
2299                  ["storage/ndb/src/mgmclient", "bin"],
2300                  "ndb_mgm");
2301
2302    $exe_ndb_waiter=
2303      my_find_bin($bindir,
2304		  ["storage/ndb/tools/", "bin"],
2305		  "ndb_waiter");
2306
2307  }
2308
2309  # Look for mysqltest executable
2310  if ( $opt_embedded_server )
2311  {
2312    $exe_mysqltest=
2313      mtr_exe_exists(vs_config_dirs('libmysqld/examples','mysqltest_embedded'),
2314                     "$basedir/libmysqld/examples/mysqltest_embedded",
2315                     "$path_client_bindir/mysqltest_embedded");
2316  }
2317  else
2318  {
2319    if ( defined $ENV{'MYSQL_TEST'} )
2320    {
2321      $exe_mysqltest=$ENV{'MYSQL_TEST'};
2322      print "===========================================================\n";
2323      print "WARNING:The mysqltest binary is fetched from $exe_mysqltest\n";
2324      print "===========================================================\n";
2325    }
2326    else
2327    {
2328      $exe_mysqltest= mtr_exe_exists("$path_client_bindir/mysqltest");
2329    }
2330  }
2331
2332}
2333
2334
2335sub client_debug_arg($$) {
2336  my ($args, $client_name)= @_;
2337
2338  # Workaround for Bug #50627: drop any debug opt
2339  return if $client_name =~ /^mysqlbinlog/;
2340
2341  if ( $opt_debug ) {
2342    mtr_add_arg($args,
2343		"--loose-debug=$debug_d:t:A,%s/log/%s.trace",
2344		$path_vardir_trace, $client_name)
2345  }
2346}
2347
2348
2349sub client_arguments ($;$) {
2350 my $client_name= shift;
2351  my $group_suffix= shift;
2352  my $client_exe= mtr_exe_exists("$path_client_bindir/$client_name");
2353
2354  my $args;
2355  mtr_init_args(\$args);
2356  mtr_add_arg($args, "--defaults-file=%s", $path_config_file);
2357  if (defined($group_suffix)) {
2358    mtr_add_arg($args, "--defaults-group-suffix=%s", $group_suffix);
2359    client_debug_arg($args, "$client_name-$group_suffix");
2360  }
2361  else
2362  {
2363    client_debug_arg($args, $client_name);
2364  }
2365  return mtr_args2str($client_exe, @$args);
2366}
2367
2368sub client_arguments_no_grp_suffix($) {
2369  my $client_name= shift;
2370  my $client_exe= mtr_exe_exists("$path_client_bindir/$client_name");
2371  my $args;
2372
2373  return mtr_args2str($client_exe, @$args);
2374}
2375
2376
2377sub mysqlslap_arguments () {
2378  my $exe= mtr_exe_maybe_exists("$path_client_bindir/mysqlslap");
2379  if ( $exe eq "" ) {
2380    # mysqlap was not found
2381
2382    if (defined $mysql_version_id and $mysql_version_id >= 50100 ) {
2383      mtr_error("Could not find the mysqlslap binary");
2384    }
2385    return ""; # Don't care about mysqlslap
2386  }
2387
2388  my $args;
2389  mtr_init_args(\$args);
2390  mtr_add_arg($args, "--defaults-file=%s", $path_config_file);
2391  client_debug_arg($args, "mysqlslap");
2392  return mtr_args2str($exe, @$args);
2393}
2394
2395
2396sub mysqldump_arguments ($) {
2397  my($group_suffix) = @_;
2398  my $exe= mtr_exe_exists("$path_client_bindir/mysqldump");
2399
2400  my $args;
2401  mtr_init_args(\$args);
2402  mtr_add_arg($args, "--defaults-file=%s", $path_config_file);
2403  mtr_add_arg($args, "--defaults-group-suffix=%s", $group_suffix);
2404  client_debug_arg($args, "mysqldump-$group_suffix");
2405  return mtr_args2str($exe, @$args);
2406}
2407
2408
2409sub mysql_client_test_arguments(){
2410  my $exe;
2411  # mysql_client_test executable may _not_ exist
2412  $exe= mtr_exe_maybe_exists(vs_config_dirs('tests', 'mysql_client_test'),
2413			     "$basedir/tests/mysql_client_test",
2414			     "$basedir/bin/mysql_client_test");
2415  return "" unless $exe;
2416  my $args;
2417  mtr_init_args(\$args);
2418  if ( $opt_valgrind_mysqltest ) {
2419    valgrind_arguments($args, \$exe);
2420  }
2421  mtr_add_arg($args, "--defaults-file=%s", $path_config_file);
2422  mtr_add_arg($args, "--testcase");
2423  mtr_add_arg($args, "--vardir=$opt_vardir");
2424  client_debug_arg($args,"mysql_client_test");
2425
2426  return mtr_args2str($exe, @$args);
2427}
2428
2429
2430#
2431# Set environment to be used by childs of this process for
2432# things that are constant during the whole lifetime of mysql-test-run
2433#
2434
2435sub find_plugin($$)
2436{
2437  my ($plugin, $location)  = @_;
2438  my $plugin_filename;
2439
2440  if (IS_WINDOWS)
2441  {
2442     $plugin_filename = $plugin.".dll";
2443  }
2444  else
2445  {
2446     $plugin_filename = $plugin.".so";
2447  }
2448
2449  my $lib_plugin=
2450    mtr_file_exists(vs_config_dirs($location,$plugin_filename),
2451                    "$basedir/lib/plugin/".$plugin_filename,
2452                    "$basedir/lib64/plugin/".$plugin_filename,
2453                    "$basedir/$location/.libs/".$plugin_filename,
2454                    "$basedir/lib/mysql/plugin/".$plugin_filename,
2455                    "$basedir/lib64/mysql/plugin/".$plugin_filename,
2456                    );
2457  return $lib_plugin;
2458}
2459
2460#
2461# Read plugin defintions file
2462#
2463
2464sub read_plugin_defs($)
2465{
2466  my ($defs_file)= @_;
2467  my $running_debug= 0;
2468
2469  open(PLUGDEF, '<', $defs_file)
2470    or mtr_error("Can't read plugin defintions file $defs_file");
2471
2472  # Need to check if we will be running mysqld-debug
2473  if ($opt_debug_server) {
2474    $running_debug= 1 if find_mysqld($basedir) =~ /mysqld-debug/;
2475  }
2476
2477  while (<PLUGDEF>) {
2478    next if /^#/;
2479    my ($plug_file, $plug_loc, $plug_var, $plug_names)= split;
2480    # Allow empty lines
2481    next unless $plug_file;
2482    mtr_error("Lines in $defs_file must have 3 or 4 items") unless $plug_var;
2483
2484    # If running debug server, plugins will be in 'debug' subdirectory
2485    $plug_file= "debug/$plug_file" if $running_debug && !$source_dist;
2486
2487    my ($plugin)= find_plugin($plug_file, $plug_loc);
2488
2489    # Set env. variables that tests may use, set to empty if plugin
2490    # listed in def. file but not found.
2491
2492    if ($plugin) {
2493      my $plug_dir= dirname($plugin);
2494      $ENV{$plug_var}= basename($plugin);
2495      $ENV{$plug_var.'_DIR'}= $plug_dir;
2496      $ENV{$plug_var.'_OPT'}= "--plugin-dir=".$plug_dir;
2497      if ($plug_names) {
2498	my $lib_name= basename($plugin);
2499	my $load_var= "--plugin_load=";
2500	my $load_add_var= "--plugin_load_add=";
2501	my $load_var_with_path = "--plugin_load=";
2502	my $load_add_var_with_path = "--plugin_load_add=";
2503	my $semi= '';
2504	foreach my $plug_name (split (',', $plug_names)) {
2505	  $load_var .= $semi . "$plug_name=$lib_name";
2506	  $load_add_var .= $semi . "$plug_name=$lib_name";
2507	  $load_var_with_path .= $semi . "$plug_name=$plug_dir/$lib_name";
2508	  $load_add_var_with_path .= $semi . "$plug_name=$plug_dir/$lib_name";
2509	  $semi= ';';
2510	}
2511	$ENV{$plug_var.'_LOAD'}= $load_var;
2512	$ENV{$plug_var.'_LOAD_ADD'}= $load_add_var;
2513	$ENV{$plug_var.'_LOAD_PATH'}= $load_var_with_path;
2514	$ENV{$plug_var.'_LOAD_ADD_PATH'}= $load_add_var_with_path;
2515      }
2516    } else {
2517      $ENV{$plug_var}= "";
2518      $ENV{$plug_var.'_DIR'}= "";
2519      $ENV{$plug_var.'_OPT'}= "";
2520      $ENV{$plug_var.'_LOAD'}= "" if $plug_names;
2521      $ENV{$plug_var.'_LOAD_ADD'}= "" if $plug_names;
2522      $ENV{$plug_var.'_LOAD_PATH'}= "" if $plug_names;
2523      $ENV{$plug_var.'_LOAD_ADD_PATH'}= "" if $plug_names;
2524    }
2525  }
2526  close PLUGDEF;
2527}
2528
2529sub environment_setup {
2530
2531  umask(022);
2532
2533  my @ld_library_paths;
2534
2535  if ($path_client_libdir)
2536  {
2537    # Use the --client-libdir passed on commandline
2538    push(@ld_library_paths, "$path_client_libdir");
2539  }
2540  else
2541  {
2542    # Setup LD_LIBRARY_PATH so the libraries from this distro/clone
2543    # are used in favor of the system installed ones
2544    if ( $source_dist )
2545    {
2546      push(@ld_library_paths, "$basedir/libmysql/.libs/",
2547	   "$basedir/libmysql_r/.libs/",
2548	   "$basedir/zlib/.libs/");
2549    }
2550    else
2551    {
2552      push(@ld_library_paths, "$basedir/lib", "$basedir/lib/mysql");
2553    }
2554  }
2555
2556  # --------------------------------------------------------------------------
2557  # Add the path where libndbclient can be found
2558  # --------------------------------------------------------------------------
2559  if ( $ndbcluster_enabled )
2560  {
2561    push(@ld_library_paths,
2562	 "$basedir/storage/ndb/src/.libs",
2563	 "$basedir/storage/ndb/src");
2564  }
2565
2566  # Plugin settings should no longer be added here, instead
2567  # place definitions in include/plugin.defs.
2568  # See comment in that file for details.
2569  # --------------------------------------------------------------------------
2570  # Valgrind need to be run with debug libraries otherwise it's almost
2571  # impossible to add correct supressions, that means if "/usr/lib/debug"
2572  # is available, it should be added to
2573  # LD_LIBRARY_PATH
2574  #
2575  # But pthread is broken in libc6-dbg on Debian <= 3.1 (see Debian
2576  # bug 399035, http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=399035),
2577  # so don't change LD_LIBRARY_PATH on that platform.
2578  # --------------------------------------------------------------------------
2579  my $debug_libraries_path= "/usr/lib/debug";
2580  my $deb_version;
2581  if (  $opt_valgrind and -d $debug_libraries_path and
2582        (! -e '/etc/debian_version' or
2583	 ($deb_version=
2584	    mtr_grab_file('/etc/debian_version')) !~ /^[0-9]+\.[0-9]$/ or
2585         $deb_version > 3.1 ) )
2586  {
2587    push(@ld_library_paths, $debug_libraries_path);
2588  }
2589
2590  $ENV{'LD_LIBRARY_PATH'}= join(":", @ld_library_paths,
2591				$ENV{'LD_LIBRARY_PATH'} ?
2592				split(':', $ENV{'LD_LIBRARY_PATH'}) : ());
2593  mtr_debug("LD_LIBRARY_PATH: $ENV{'LD_LIBRARY_PATH'}");
2594
2595  $ENV{'DYLD_LIBRARY_PATH'}= join(":", @ld_library_paths,
2596				  $ENV{'DYLD_LIBRARY_PATH'} ?
2597				  split(':', $ENV{'DYLD_LIBRARY_PATH'}) : ());
2598  mtr_debug("DYLD_LIBRARY_PATH: $ENV{'DYLD_LIBRARY_PATH'}");
2599
2600  # The environment variable used for shared libs on AIX
2601  $ENV{'SHLIB_PATH'}= join(":", @ld_library_paths,
2602                           $ENV{'SHLIB_PATH'} ?
2603                           split(':', $ENV{'SHLIB_PATH'}) : ());
2604  mtr_debug("SHLIB_PATH: $ENV{'SHLIB_PATH'}");
2605
2606  # The environment variable used for shared libs on hp-ux
2607  $ENV{'LIBPATH'}= join(":", @ld_library_paths,
2608                        $ENV{'LIBPATH'} ?
2609                        split(':', $ENV{'LIBPATH'}) : ());
2610  mtr_debug("LIBPATH: $ENV{'LIBPATH'}");
2611
2612  $ENV{'UMASK'}=              "0660"; # The octal *string*
2613  $ENV{'UMASK_DIR'}=          "0770"; # The octal *string*
2614
2615  #
2616  # MySQL tests can produce output in various character sets
2617  # (especially, ctype_xxx.test). To avoid confusing Perl
2618  # with output which is incompatible with the current locale
2619  # settings, we reset the current values of LC_ALL and LC_CTYPE to "C".
2620  # For details, please see
2621  # Bug#27636 tests fails if LC_* variables set to *_*.UTF-8
2622  #
2623  $ENV{'LC_ALL'}=             "C";
2624  $ENV{'LC_CTYPE'}=           "C";
2625
2626  $ENV{'LC_COLLATE'}=         "C";
2627  $ENV{'USE_RUNNING_SERVER'}= using_extern();
2628  $ENV{'MYSQL_TEST_DIR'}=     $glob_mysql_test_dir;
2629  $ENV{'DEFAULT_MASTER_PORT'}= $mysqld_variables{'port'};
2630  $ENV{'MYSQL_TMP_DIR'}=      $opt_tmpdir;
2631  $ENV{'MYSQLTEST_VARDIR'}=   $opt_vardir;
2632  $ENV{'MYSQL_TEST_DIR_ABS'}= getcwd();
2633  $ENV{'MYSQL_BINDIR'}=       "$bindir";
2634  $ENV{'MYSQL_SHAREDIR'}=     $path_language;
2635  $ENV{'MYSQL_CHARSETSDIR'}=  $path_charsetsdir;
2636
2637  if (IS_WINDOWS)
2638  {
2639    $ENV{'SECURE_LOAD_PATH'}= $glob_mysql_test_dir."\\std_data";
2640    $ENV{'MYSQL_TEST_LOGIN_FILE'}= $opt_tmpdir . "\\.mylogin.cnf";
2641    $ENV{'MYSQLTEST_VARDIR_ABS'}= $opt_vardir;
2642  }
2643  else
2644  {
2645    $ENV{'SECURE_LOAD_PATH'}= $glob_mysql_test_dir."/std_data";
2646    $ENV{'MYSQL_TEST_LOGIN_FILE'}= $opt_tmpdir . "/.mylogin.cnf";
2647    $ENV{'MYSQLTEST_VARDIR_ABS'}= abs_path("$opt_vardir");
2648  }
2649
2650
2651  # ----------------------------------------------------
2652  # Setup env for NDB
2653  # ----------------------------------------------------
2654  if ( $ndbcluster_enabled )
2655  {
2656    $ENV{'NDB_MGM'}=
2657      my_find_bin($bindir,
2658		  ["storage/ndb/src/mgmclient", "bin"],
2659		  "ndb_mgm");
2660
2661    $ENV{'NDB_WAITER'}= $exe_ndb_waiter;
2662
2663    $ENV{'NDB_RESTORE'}=
2664      my_find_bin($bindir,
2665		  ["storage/ndb/tools", "bin"],
2666		  "ndb_restore");
2667
2668    $ENV{'NDB_CONFIG'}=
2669      my_find_bin($bindir,
2670		  ["storage/ndb/tools", "bin"],
2671		  "ndb_config");
2672
2673    $ENV{'NDB_SELECT_ALL'}=
2674      my_find_bin($bindir,
2675		  ["storage/ndb/tools", "bin"],
2676		  "ndb_select_all");
2677
2678    $ENV{'NDB_DROP_TABLE'}=
2679      my_find_bin($bindir,
2680		  ["storage/ndb/tools", "bin"],
2681		  "ndb_drop_table");
2682
2683    $ENV{'NDB_DESC'}=
2684      my_find_bin($bindir,
2685		  ["storage/ndb/tools", "bin"],
2686		  "ndb_desc");
2687
2688    $ENV{'NDB_SHOW_TABLES'}=
2689      my_find_bin($bindir,
2690		  ["storage/ndb/tools", "bin"],
2691		  "ndb_show_tables");
2692
2693    $ENV{'NDB_EXAMPLES_DIR'}=
2694      my_find_dir($basedir,
2695		  ["storage/ndb/ndbapi-examples", "bin"]);
2696
2697    $ENV{'NDB_EXAMPLES_BINARY'}=
2698      my_find_bin($bindir,
2699		  ["storage/ndb/ndbapi-examples/ndbapi_simple", "bin"],
2700		  "ndbapi_simple", NOT_REQUIRED);
2701
2702    my $path_ndb_testrun_log= "$opt_vardir/log/ndb_testrun.log";
2703    $ENV{'NDB_TOOLS_OUTPUT'}=         $path_ndb_testrun_log;
2704    $ENV{'NDB_EXAMPLES_OUTPUT'}=      $path_ndb_testrun_log;
2705  }
2706
2707  # ----------------------------------------------------
2708  # mysql clients
2709  # ----------------------------------------------------
2710  $ENV{'MYSQL_CHECK'}=              client_arguments("mysqlcheck");
2711  $ENV{'MYSQL_DUMP'}=               mysqldump_arguments(".1");
2712  $ENV{'MYSQL_DUMP_SLAVE'}=         mysqldump_arguments(".2");
2713  $ENV{'MYSQL_SLAP'}=               mysqlslap_arguments();
2714  $ENV{'MYSQL_IMPORT'}=             client_arguments("mysqlimport");
2715  $ENV{'MYSQL_SHOW'}=               client_arguments("mysqlshow");
2716  $ENV{'MYSQL_CONFIG_EDITOR'}=      client_arguments_no_grp_suffix("mysql_config_editor");
2717  $ENV{'MYSQL_BINLOG'}=             client_arguments("mysqlbinlog");
2718  $ENV{'MYSQL'}=                    client_arguments("mysql");
2719  $ENV{'MYSQL_SLAVE'}=              client_arguments("mysql", ".2");
2720  $ENV{'MYSQL_UPGRADE'}=            client_arguments("mysql_upgrade");
2721  $ENV{'MYSQLADMIN'}=               native_path($exe_mysqladmin);
2722  $ENV{'MYSQL_CLIENT_TEST'}=        mysql_client_test_arguments();
2723  $ENV{'EXE_MYSQL'}=                $exe_mysql;
2724  $ENV{'MYSQL_PLUGIN'}=             $exe_mysql_plugin;
2725  $ENV{'MYSQL_EMBEDDED'}=           $exe_mysql_embedded;
2726  $ENV{'PATH_CONFIG_FILE'}=         $path_config_file;
2727
2728  my $exe_mysqld= find_mysqld($basedir);
2729  $ENV{'MYSQLD'}= $exe_mysqld;
2730  my $extra_opts= join (" ", @opt_extra_mysqld_opt);
2731  $ENV{'MYSQLD_CMD'}= "$exe_mysqld --defaults-group-suffix=.1 ".
2732    "--defaults-file=$path_config_file $extra_opts";
2733
2734  # ----------------------------------------------------
2735  # bug25714 executable may _not_ exist in
2736  # some versions, test using it should be skipped
2737  # ----------------------------------------------------
2738  my $exe_bug25714=
2739      mtr_exe_maybe_exists(vs_config_dirs('tests', 'bug25714'),
2740                           "$basedir/tests/bug25714");
2741  $ENV{'MYSQL_BUG25714'}=  native_path($exe_bug25714);
2742
2743  # ----------------------------------------------------
2744  # Get the bin dir
2745  # ----------------------------------------------------
2746  $ENV{'MYSQL_BIN_PATH'}=  native_path($bindir);
2747
2748  # ----------------------------------------------------
2749  # mysql_fix_privilege_tables.sql
2750  # ----------------------------------------------------
2751  my $file_mysql_fix_privilege_tables=
2752    mtr_file_exists("$basedir/scripts/mysql_fix_privilege_tables.sql",
2753		    "$basedir/share/mysql_fix_privilege_tables.sql",
2754		    "$basedir/share/mysql/mysql_fix_privilege_tables.sql",
2755                    "$bindir/scripts/mysql_fix_privilege_tables.sql",
2756		    "$bindir/share/mysql_fix_privilege_tables.sql",
2757		    "$bindir/share/mysql/mysql_fix_privilege_tables.sql");
2758  $ENV{'MYSQL_FIX_PRIVILEGE_TABLES'}=  $file_mysql_fix_privilege_tables;
2759
2760  # ----------------------------------------------------
2761  # my_print_defaults
2762  # ----------------------------------------------------
2763  my $exe_my_print_defaults=
2764    mtr_exe_exists(vs_config_dirs('extra', 'my_print_defaults'),
2765		   "$path_client_bindir/my_print_defaults",
2766		   "$basedir/extra/my_print_defaults");
2767  $ENV{'MYSQL_MY_PRINT_DEFAULTS'}= native_path($exe_my_print_defaults);
2768
2769  # ----------------------------------------------------
2770  # Setup env so childs can execute innochecksum
2771  # ----------------------------------------------------
2772  my $exe_innochecksum=
2773    mtr_exe_exists(vs_config_dirs('extra', 'innochecksum'),
2774                   "$path_client_bindir/innochecksum",
2775                   "$basedir/extra/innochecksum");
2776  $ENV{'INNOCHECKSUM'}= native_path($exe_innochecksum);
2777
2778  # ----------------------------------------------------
2779  # sst_dump
2780  # ----------------------------------------------------
2781  my $exe_sst_dump=
2782    mtr_exe_maybe_exists(
2783           vs_config_dirs('storage/rocksdb', 'sst_dump'),
2784           "$path_client_bindir/sst_dump",
2785           "$basedir/storage/rocksdb/sst_dump");
2786  $ENV{'MYSQL_SST_DUMP'}= native_path($exe_sst_dump);
2787
2788  # ----------------------------------------------------
2789  # tokuft_dump
2790  # ----------------------------------------------------
2791  my $exe_tokuftdump=
2792    mtr_exe_maybe_exists(
2793           vs_config_dirs('storage/tokudb/PerconaFT/tools', 'tokuftdump'),
2794           "$path_client_bindir/tokuftdump",
2795           "$basedir/storage/tokudb/PerconaFT/tools/tokuftdump");
2796  $ENV{'MYSQL_TOKUFTDUMP'}= native_path($exe_tokuftdump);
2797
2798
2799  # ----------------------------------------------------
2800  # Setup env so childs can execute myisampack and myisamchk
2801  # ----------------------------------------------------
2802  $ENV{'MYISAMCHK'}= native_path(mtr_exe_exists(
2803                       vs_config_dirs('storage/myisam', 'myisamchk'),
2804                       vs_config_dirs('myisam', 'myisamchk'),
2805                       "$path_client_bindir/myisamchk",
2806                       "$basedir/storage/myisam/myisamchk",
2807                       "$basedir/myisam/myisamchk"));
2808  $ENV{'MYISAMPACK'}= native_path(mtr_exe_exists(
2809                        vs_config_dirs('storage/myisam', 'myisampack'),
2810                        vs_config_dirs('myisam', 'myisampack'),
2811                        "$path_client_bindir/myisampack",
2812                        "$basedir/storage/myisam/myisampack",
2813                        "$basedir/myisam/myisampack"));
2814
2815  # ----------------------------------------------------
2816  # mysqlaccess
2817  # ----------------------------------------------------
2818  my $mysqlaccess=
2819    mtr_pl_maybe_exists("$bindir/scripts/mysqlaccess") ||
2820    mtr_pl_maybe_exists("$path_client_bindir/mysqlaccess");
2821  if ($mysqlaccess)
2822  {
2823    $ENV{'MYSQLACCESS'}= $mysqlaccess;
2824  }
2825
2826  # ----------------------------------------------------
2827  # mysqlhotcopy
2828  # ----------------------------------------------------
2829  my $mysqlhotcopy=
2830    mtr_pl_maybe_exists("$bindir/scripts/mysqlhotcopy") ||
2831    mtr_pl_maybe_exists("$path_client_bindir/mysqlhotcopy");
2832  if ($mysqlhotcopy)
2833  {
2834    $ENV{'MYSQLHOTCOPY'}= $mysqlhotcopy;
2835  }
2836
2837  # ----------------------------------------------------
2838  # perror
2839  # ----------------------------------------------------
2840  my $exe_perror= mtr_exe_exists(vs_config_dirs('extra', 'perror'),
2841				 "$basedir/extra/perror",
2842				 "$path_client_bindir/perror");
2843  $ENV{'MY_PERROR'}= native_path($exe_perror);
2844
2845  # ----------------------------------------------------
2846  # replace
2847  # ----------------------------------------------------
2848  my $exe_replace= mtr_exe_exists(vs_config_dirs('extra', 'replace'),
2849                                 "$basedir/extra/replace",
2850                                 "$path_client_bindir/replace");
2851  $ENV{'REPLACE'}= native_path($exe_replace);
2852
2853  # Create an environment variable to make it possible
2854  # to detect that valgrind is being used from test cases
2855  $ENV{'VALGRIND_TEST'}= $opt_valgrind;
2856
2857  # Add dir of this perl to aid mysqltest in finding perl
2858  my $perldir= dirname($^X);
2859  my $pathsep= ":";
2860  $pathsep= ";" if IS_WINDOWS && ! IS_CYGWIN;
2861  $ENV{'PATH'}= "$ENV{'PATH'}".$pathsep.$perldir;
2862}
2863
2864
2865sub remove_vardir_subs() {
2866  foreach my $sdir ( glob("$opt_vardir/*") ) {
2867    mtr_verbose("Removing subdir $sdir");
2868    rmtree($sdir);
2869  }
2870}
2871
2872#
2873# Remove var and any directories in var/ created by previous
2874# tests
2875#
2876sub remove_stale_vardir () {
2877
2878  mtr_report("Removing old var directory...");
2879
2880  # Safety!
2881  mtr_error("No, don't remove the vardir when running with --extern")
2882    if using_extern();
2883
2884  mtr_verbose("opt_vardir: $opt_vardir");
2885  if ( $opt_vardir eq $default_vardir )
2886  {
2887    #
2888    # Running with "var" in mysql-test dir
2889    #
2890    if ( -l $opt_vardir)
2891    {
2892      # var is a symlink
2893
2894      if ( $opt_mem )
2895      {
2896	# Remove the directory which the link points at
2897	mtr_verbose("Removing " . readlink($opt_vardir));
2898	rmtree(readlink($opt_vardir));
2899
2900	# Remove the "var" symlink
2901	mtr_verbose("unlink($opt_vardir)");
2902	unlink($opt_vardir);
2903      }
2904      else
2905      {
2906	# Some users creates a soft link in mysql-test/var to another area
2907	# - allow it, but remove all files in it
2908
2909	mtr_report(" - WARNING: Using the 'mysql-test/var' symlink");
2910
2911	# Make sure the directory where it points exist
2912	mtr_error("The destination for symlink $opt_vardir does not exist")
2913	  if ! -d readlink($opt_vardir);
2914
2915	remove_vardir_subs();
2916      }
2917    }
2918    else
2919    {
2920      # Remove the entire "var" dir
2921      mtr_verbose("Removing $opt_vardir/");
2922      rmtree("$opt_vardir/");
2923    }
2924
2925    if ( $opt_mem )
2926    {
2927      # A symlink from var/ to $opt_mem will be set up
2928      # remove the $opt_mem dir to assure the symlink
2929      # won't point at an old directory
2930      mtr_verbose("Removing $opt_mem");
2931      rmtree($opt_mem);
2932    }
2933
2934  }
2935  else
2936  {
2937    #
2938    # Running with "var" in some other place
2939    #
2940
2941    # Remove the var/ dir in mysql-test dir if any
2942    # this could be an old symlink that shouldn't be there
2943    mtr_verbose("Removing $default_vardir");
2944    rmtree($default_vardir);
2945
2946    # Remove the "var" dir
2947    mtr_verbose("Removing $opt_vardir/");
2948    rmtree("$opt_vardir/");
2949  }
2950  # Remove the "tmp" dir
2951  mtr_verbose("Removing $opt_tmpdir/");
2952  rmtree("$opt_tmpdir/");
2953}
2954
2955
2956
2957#
2958# Create var and the directories needed in var
2959#
2960sub setup_vardir() {
2961  mtr_report("Creating var directory '$opt_vardir'...");
2962
2963  if ( $opt_vardir eq $default_vardir )
2964  {
2965    #
2966    # Running with "var" in mysql-test dir
2967    #
2968    if ( -l $opt_vardir )
2969    {
2970      #  it's a symlink
2971
2972      # Make sure the directory where it points exist
2973      mtr_error("The destination for symlink $opt_vardir does not exist")
2974	if ! -d readlink($opt_vardir);
2975    }
2976    elsif ( $opt_mem )
2977    {
2978      # Runinng with "var" as a link to some "memory" location, normally tmpfs
2979      mtr_verbose("Creating $opt_mem");
2980      mkpath($opt_mem);
2981
2982      mtr_report(" - symlinking 'var' to '$opt_mem'");
2983      symlink($opt_mem, $opt_vardir);
2984    }
2985  }
2986
2987  if ( ! -d $opt_vardir )
2988  {
2989    mtr_verbose("Creating $opt_vardir");
2990    mkpath($opt_vardir);
2991  }
2992
2993  # Ensure a proper error message if vardir couldn't be created
2994  unless ( -d $opt_vardir and -w $opt_vardir )
2995  {
2996    mtr_error("Writable 'var' directory is needed, use the " .
2997	      "'--vardir=<path>' option");
2998  }
2999
3000  mkpath("$opt_vardir/log");
3001  mkpath("$opt_vardir/run");
3002
3003  # Create var/tmp and tmp - they might be different
3004  mkpath("$opt_vardir/tmp");
3005  mkpath($opt_tmpdir) if ($opt_tmpdir ne "$opt_vardir/tmp");
3006
3007  # On some operating systems, there is a limit to the length of a
3008  # UNIX domain socket's path far below PATH_MAX.
3009  # Don't allow that to happen
3010  if (check_socket_path_length("$opt_tmpdir/testsocket.sock")){
3011    mtr_error("Socket path '$opt_tmpdir' too long, it would be ",
3012	      "truncated and thus not possible to use for connection to ",
3013	      "MySQL Server. Set a shorter with --tmpdir=<path> option");
3014  }
3015
3016  # copy all files from std_data into var/std_data
3017  # and make them world readable
3018  copytree("$glob_mysql_test_dir/std_data", "$opt_vardir/std_data", "0022");
3019
3020  # Remove old log files
3021  foreach my $name (glob("r/*.progress r/*.log r/*.warnings"))
3022  {
3023    unlink($name);
3024  }
3025}
3026
3027
3028#
3029# Check if running as root
3030# i.e a file can be read regardless what mode we set it to
3031#
3032sub  check_running_as_root () {
3033  my $test_file= "$opt_vardir/test_running_as_root.txt";
3034  mtr_tofile($test_file, "MySQL");
3035  chmod(oct("0000"), $test_file);
3036
3037  my $result="";
3038  if (open(FILE,"<",$test_file))
3039  {
3040    $result= join('', <FILE>);
3041    close FILE;
3042  }
3043
3044  # Some filesystems( for example CIFS) allows reading a file
3045  # although mode was set to 0000, but in that case a stat on
3046  # the file will not return 0000
3047  my $file_mode= (stat($test_file))[2] & 07777;
3048
3049  mtr_verbose("result: $result, file_mode: $file_mode");
3050  if ($result eq "MySQL" && $file_mode == 0)
3051  {
3052    mtr_warning("running this script as _root_ will cause some " .
3053                "tests to be skipped");
3054    $ENV{'MYSQL_TEST_ROOT'}= "YES";
3055  }
3056
3057  chmod(oct("0755"), $test_file);
3058  unlink($test_file);
3059}
3060
3061
3062sub check_ssl_support ($) {
3063  my $mysqld_variables= shift;
3064
3065  if ($opt_skip_ssl)
3066  {
3067    mtr_report(" - skipping SSL");
3068    $opt_ssl_supported= 0;
3069    $opt_ssl= 0;
3070    return;
3071  }
3072
3073  if ( ! $mysqld_variables->{'ssl'} )
3074  {
3075    if ( $opt_ssl)
3076    {
3077      mtr_error("Couldn't find support for SSL");
3078      return;
3079    }
3080    mtr_report(" - skipping SSL, mysqld not compiled with SSL");
3081    $opt_ssl_supported= 0;
3082    $opt_ssl= 0;
3083    return;
3084  }
3085  mtr_report(" - SSL connections supported");
3086  $opt_ssl_supported= 1;
3087}
3088
3089
3090sub check_debug_support ($) {
3091  my $mysqld_variables= shift;
3092
3093  if ( ! $mysqld_variables->{'debug'} )
3094  {
3095    #mtr_report(" - binaries are not debug compiled");
3096    $debug_compiled_binaries= 0;
3097
3098    if ( $opt_debug )
3099    {
3100      mtr_error("Can't use --debug, binary does not support it");
3101    }
3102    if ( $opt_debug_server )
3103    {
3104      mtr_warning("Ignoring --debug-server, binary does not support it");
3105    }
3106    return;
3107  }
3108  mtr_report(" - binaries are debug compiled");
3109  $debug_compiled_binaries= 1;
3110}
3111
3112
3113#
3114# Helper function to handle configuration-based subdirectories which Visual
3115# Studio uses for storing binaries.  If opt_vs_config is set, this returns
3116# a path based on that setting; if not, it returns paths for the default
3117# /release/ and /debug/ subdirectories.
3118#
3119# $exe can be undefined, if the directory itself will be used
3120#
3121sub vs_config_dirs ($$) {
3122  my ($path_part, $exe) = @_;
3123
3124  $exe = "" if not defined $exe;
3125  if ($opt_vs_config)
3126  {
3127    return ("$bindir/$path_part/$opt_vs_config/$exe");
3128  }
3129
3130  return ("$bindir/$path_part/Release/$exe",
3131          "$bindir/$path_part/RelWithDebinfo/$exe",
3132          "$bindir/$path_part/Debug/$exe",
3133          "$bindir/$path_part/$exe");
3134}
3135
3136
3137sub check_ndbcluster_support ($) {
3138  my $mysqld_variables= shift;
3139
3140  my $ndbcluster_supported = 0;
3141  if ($mysqld_variables{'ndb-connectstring'})
3142  {
3143    $ndbcluster_supported = 1;
3144  }
3145
3146  if ($opt_skip_ndbcluster && $opt_include_ndbcluster)
3147  {
3148    # User is ambivalent. Theoretically the arg which was
3149    # given last on command line should win, but that order is
3150    # unknown at this time.
3151    mtr_error("Ambigous command, both --include-ndbcluster " .
3152	      " and --skip-ndbcluster was specified");
3153  }
3154
3155  # Check if this is MySQL Cluster, ie. mysql version string ends
3156  # with -ndb-Y.Y.Y[-status]
3157  if ( defined $mysql_version_extra &&
3158       $mysql_version_extra =~ /-ndb-([0-9]*)\.([0-9]*)\.([0-9]*)/ )
3159  {
3160    # MySQL Cluster tree
3161    mtr_report(" - MySQL Cluster detected");
3162
3163    if ($opt_skip_ndbcluster)
3164    {
3165      mtr_report(" - skipping ndbcluster(--skip-ndbcluster)");
3166      return;
3167    }
3168
3169    if (!$ndbcluster_supported)
3170    {
3171      # MySQL Cluster tree, but mysqld was not compiled with
3172      # ndbcluster -> fail unless --skip-ndbcluster was used
3173      mtr_error("This is MySQL Cluster but mysqld does not " .
3174		"support ndbcluster. Use --skip-ndbcluster to " .
3175		"force mtr to run without it.");
3176    }
3177
3178    # mysqld was compiled with ndbcluster -> auto enable
3179  }
3180  else
3181  {
3182    # Not a MySQL Cluster tree
3183    if (!$ndbcluster_supported)
3184    {
3185      if ($opt_include_ndbcluster)
3186      {
3187	mtr_error("Could not detect ndbcluster support ".
3188		  "requested with --include-ndbcluster");
3189      }
3190
3191      # Silently skip, mysqld was compiled without ndbcluster
3192      # which is the default case
3193      return;
3194    }
3195
3196    if ($opt_skip_ndbcluster)
3197    {
3198      # Compiled with ndbcluster but ndbcluster skipped
3199      mtr_report(" - skipping ndbcluster(--skip-ndbcluster)");
3200      return;
3201    }
3202
3203
3204    # Not a MySQL Cluster tree, enable ndbcluster
3205    # if --include-ndbcluster was used
3206    if ($opt_include_ndbcluster)
3207    {
3208      # enable ndbcluster
3209    }
3210    else
3211    {
3212      mtr_report(" - skipping ndbcluster(disabled by default)");
3213      return;
3214    }
3215  }
3216
3217  mtr_report(" - enabling ndbcluster");
3218  $ndbcluster_enabled= 1;
3219  # Add MySQL Cluster test suites
3220  $DEFAULT_SUITES.=",ndb,ndb_binlog,rpl_ndb,ndb_rpl,ndb_memcache";
3221  return;
3222}
3223
3224
3225sub ndbcluster_wait_started($$){
3226  my $cluster= shift;
3227  my $ndb_waiter_extra_opt= shift;
3228  my $path_waitlog= join('/', $opt_vardir, $cluster->name(), "ndb_waiter.log");
3229
3230  my $args;
3231  mtr_init_args(\$args);
3232  mtr_add_arg($args, "--defaults-file=%s", $path_config_file);
3233  mtr_add_arg($args, "--defaults-group-suffix=%s", $cluster->suffix());
3234  mtr_add_arg($args, "--timeout=%d", $opt_start_timeout);
3235
3236  if ($ndb_waiter_extra_opt)
3237  {
3238    mtr_add_arg($args, "$ndb_waiter_extra_opt");
3239  }
3240
3241  # Start the ndb_waiter which will connect to the ndb_mgmd
3242  # and poll it for state of the ndbd's, will return when
3243  # all nodes in the cluster is started
3244
3245  my $res= My::SafeProcess->run
3246    (
3247     name          => "ndb_waiter ".$cluster->name(),
3248     path          => $exe_ndb_waiter,
3249     args          => \$args,
3250     output        => $path_waitlog,
3251     error         => $path_waitlog,
3252     append        => 1,
3253    );
3254
3255  # Check that ndb_mgmd(s) are still alive
3256  foreach my $ndb_mgmd ( in_cluster($cluster, ndb_mgmds()) )
3257  {
3258    my $proc= $ndb_mgmd->{proc};
3259    if ( ! $proc->wait_one(0) )
3260    {
3261      mtr_warning("$proc died");
3262      return 2;
3263    }
3264  }
3265
3266  # Check that all started ndbd(s) are still alive
3267  foreach my $ndbd ( in_cluster($cluster, ndbds()) )
3268  {
3269    my $proc= $ndbd->{proc};
3270    next unless defined $proc;
3271    if ( ! $proc->wait_one(0) )
3272    {
3273      mtr_warning("$proc died");
3274      return 3;
3275    }
3276  }
3277
3278  if ($res)
3279  {
3280    mtr_verbose("ndbcluster_wait_started failed");
3281    return 1;
3282  }
3283  return 0;
3284}
3285
3286
3287sub ndbcluster_dump($) {
3288  my ($cluster)= @_;
3289
3290  print "\n== Dumping cluster log files\n\n";
3291
3292  # ndb_mgmd(s)
3293  foreach my $ndb_mgmd ( in_cluster($cluster, ndb_mgmds()) )
3294  {
3295    my $datadir = $ndb_mgmd->value('DataDir');
3296
3297    # Should find ndb_<nodeid>_cluster.log and ndb_mgmd.log
3298    foreach my $file ( glob("$datadir/ndb*.log") )
3299    {
3300      print "$file:\n";
3301      mtr_printfile("$file");
3302      print "\n";
3303    }
3304  }
3305
3306  # ndb(s)
3307  foreach my $ndbd ( in_cluster($cluster, ndbds()) )
3308  {
3309    my $datadir = $ndbd->value('DataDir');
3310
3311    # Should find ndbd.log
3312    foreach my $file ( glob("$datadir/ndbd.log") )
3313    {
3314      print "$file:\n";
3315      mtr_printfile("$file");
3316      print "\n";
3317    }
3318  }
3319}
3320
3321
3322sub ndb_mgmd_wait_started($) {
3323  my ($cluster)= @_;
3324
3325  my $retries= 100;
3326  while ($retries)
3327  {
3328    my $result= ndbcluster_wait_started($cluster, "--no-contact");
3329    if ($result == 0)
3330    {
3331      # ndb_mgmd is started
3332      mtr_verbose("ndb_mgmd is started");
3333      return 0;
3334    }
3335    elsif ($result > 1)
3336    {
3337      mtr_warning("Cluster process failed while waiting for start");
3338      return $result;
3339    }
3340
3341    mtr_milli_sleep(100);
3342    $retries--;
3343  }
3344
3345  return 1;
3346}
3347
3348sub ndb_mgmd_stop{
3349  my $ndb_mgmd= shift or die "usage: ndb_mgmd_stop(<ndb_mgmd>)";
3350
3351  my $host=$ndb_mgmd->value('HostName');
3352  my $port=$ndb_mgmd->value('PortNumber');
3353  mtr_verbose("Stopping cluster '$host:$port'");
3354
3355  my $args;
3356  mtr_init_args(\$args);
3357  mtr_add_arg($args, "--ndb-connectstring=%s:%s", $host,$port);
3358  mtr_add_arg($args, "-e");
3359  mtr_add_arg($args, "shutdown");
3360
3361  My::SafeProcess->run
3362    (
3363     name          => "ndb_mgm shutdown $host:$port",
3364     path          => $exe_ndb_mgm,
3365     args          => \$args,
3366     output         => "/dev/null",
3367    );
3368}
3369
3370sub ndb_mgmd_start ($$) {
3371  my ($cluster, $ndb_mgmd)= @_;
3372
3373  mtr_verbose("ndb_mgmd_start");
3374
3375  my $dir= $ndb_mgmd->value("DataDir");
3376  mkpath($dir) unless -d $dir;
3377
3378  my $args;
3379  mtr_init_args(\$args);
3380  mtr_add_arg($args, "--defaults-file=%s", $path_config_file);
3381  mtr_add_arg($args, "--defaults-group-suffix=%s", $cluster->suffix());
3382  mtr_add_arg($args, "--mycnf");
3383  mtr_add_arg($args, "--nodaemon");
3384  mtr_add_arg($args, "--configdir=%s", "$dir");
3385
3386  my $path_ndb_mgmd_log= "$dir/ndb_mgmd.log";
3387
3388  $ndb_mgmd->{'proc'}= My::SafeProcess->new
3389    (
3390     name          => $ndb_mgmd->after('cluster_config.'),
3391     path          => $exe_ndb_mgmd,
3392     args          => \$args,
3393     output        => $path_ndb_mgmd_log,
3394     error         => $path_ndb_mgmd_log,
3395     append        => 1,
3396     verbose       => $opt_verbose,
3397     shutdown      => sub { ndb_mgmd_stop($ndb_mgmd) },
3398    );
3399  mtr_verbose("Started $ndb_mgmd->{proc}");
3400
3401  # FIXME Should not be needed
3402  # Unfortunately the cluster nodes will fail to start
3403  # if ndb_mgmd has not started properly
3404  if (ndb_mgmd_wait_started($cluster))
3405  {
3406    mtr_warning("Failed to wait for start of ndb_mgmd");
3407    return 1;
3408  }
3409
3410  return 0;
3411}
3412
3413sub ndbd_stop {
3414  # Intentionally left empty, ndbd nodes will be shutdown
3415  # by sending "shutdown" to ndb_mgmd
3416}
3417
3418my $exe_ndbmtd_counter= 0;
3419
3420sub ndbd_start {
3421  my ($cluster, $ndbd)= @_;
3422
3423  mtr_verbose("ndbd_start");
3424
3425  my $dir= $ndbd->value("DataDir");
3426  mkpath($dir) unless -d $dir;
3427
3428  my $args;
3429  mtr_init_args(\$args);
3430  mtr_add_arg($args, "--defaults-file=%s", $path_config_file);
3431  mtr_add_arg($args, "--defaults-group-suffix=%s", $cluster->suffix());
3432  mtr_add_arg($args, "--nodaemon");
3433
3434# > 5.0 { 'character-sets-dir' => \&fix_charset_dir },
3435
3436  my $exe= $exe_ndbd;
3437  if ($exe_ndbmtd)
3438  { if ($ENV{MTR_NDBMTD})
3439    {
3440      # ndbmtd forced by env var MTR_NDBMTD
3441      $exe= $exe_ndbmtd;
3442    }
3443    if (($exe_ndbmtd_counter++ % 2) == 0)
3444    {
3445      # Use ndbmtd every other time
3446      $exe= $exe_ndbmtd;
3447    }
3448  }
3449
3450  my $path_ndbd_log= "$dir/ndbd.log";
3451  my $proc= My::SafeProcess->new
3452    (
3453     name          => $ndbd->after('cluster_config.'),
3454     path          => $exe,
3455     args          => \$args,
3456     output        => $path_ndbd_log,
3457     error         => $path_ndbd_log,
3458     append        => 1,
3459     verbose       => $opt_verbose,
3460     shutdown      => sub { ndbd_stop($ndbd) },
3461    );
3462  mtr_verbose("Started $proc");
3463
3464  $ndbd->{proc}= $proc;
3465
3466  return;
3467}
3468
3469
3470sub memcached_start {
3471  my ($cluster, $memcached) = @_;
3472
3473  my $name = $memcached->name();
3474  mtr_verbose("memcached_start '$name'");
3475
3476  my $found_perl_source = my_find_file($basedir,
3477     ["storage/ndb/memcache",        # source
3478      "mysql-test/lib",              # install
3479      "share/mysql-test/lib"],       # install
3480      "memcached_path.pl", NOT_REQUIRED);
3481
3482  mtr_verbose("Found memcache script: '$found_perl_source'");
3483  $found_perl_source ne "" or return;
3484
3485  my $found_so = my_find_file($bindir,
3486    ["storage/ndb/memcache",        # source or build
3487     "lib", "lib64"],               # install
3488    "ndb_engine.so");
3489  mtr_verbose("Found memcache plugin: '$found_so'");
3490
3491  require "$found_perl_source";
3492  if(! memcached_is_available())
3493  {
3494    mtr_error("Memcached not available.");
3495  }
3496  my $exe = "";
3497  if(memcached_is_bundled())
3498  {
3499    $exe = my_find_bin($bindir,
3500    ["libexec", "sbin", "bin", "storage/ndb/memcache/extra/memcached"],
3501    "memcached", NOT_REQUIRED);
3502  }
3503  else
3504  {
3505    $exe = get_memcached_exe_path();
3506  }
3507  $exe ne "" or mtr_error("Failed to find memcached.");
3508
3509  my $args;
3510  mtr_init_args(\$args);
3511  # TCP port number to listen on
3512  mtr_add_arg($args, "-p %d", $memcached->value('port'));
3513  # Max simultaneous connections
3514  mtr_add_arg($args, "-c %d", $memcached->value('max_connections'));
3515  # Load engine as storage engine, ie. /path/ndb_engine.so
3516  mtr_add_arg($args, "-E");
3517  mtr_add_arg($args, $found_so);
3518  # Config options for loaded storage engine
3519  {
3520    my @opts;
3521    push(@opts, "connectstring=" . $memcached->value('ndb_connectstring'));
3522    push(@opts, $memcached->if_exist("options"));
3523    mtr_add_arg($args, "-e");
3524    mtr_add_arg($args, join(";", @opts));
3525  }
3526
3527  if($opt_gdb)
3528  {
3529    gdb_arguments(\$args, \$exe, "memcached");
3530  }
3531
3532  my $proc = My::SafeProcess->new
3533  ( name     =>  $name,
3534    path     =>  $exe,
3535    args     => \$args,
3536    output   =>  "$opt_vardir/log/$name.out",
3537    error    =>  "$opt_vardir/log/$name.out",
3538    append   =>  1,
3539    verbose  => $opt_verbose,
3540  );
3541  mtr_verbose("Started $proc");
3542
3543  $memcached->{proc} = $proc;
3544
3545  return;
3546}
3547
3548
3549sub memcached_load_metadata($) {
3550  my $cluster= shift;
3551
3552  foreach my $mysqld (mysqlds())
3553  {
3554    if(-d $mysqld->value('datadir') . "/" . "ndbmemcache")
3555    {
3556      mtr_verbose("skipping memcache metadata (already stored)");
3557      return;
3558    }
3559  }
3560
3561  my $sql_script= my_find_file($bindir,
3562                              ["share/mysql/memcache-api", # RPM install
3563                               "share/memcache-api",       # Other installs
3564                               "scripts"                   # Build tree
3565                              ],
3566                              "ndb_memcache_metadata.sql", NOT_REQUIRED);
3567  mtr_verbose("memcached_load_metadata: '$sql_script'");
3568  if (-f $sql_script )
3569  {
3570    my $args;
3571    mtr_init_args(\$args);
3572    mtr_add_arg($args, "--defaults-file=%s", $path_config_file);
3573    mtr_add_arg($args, "--defaults-group-suffix=%s", $cluster->suffix());
3574    mtr_add_arg($args, "--connect-timeout=20");
3575    if ( My::SafeProcess->run(
3576           name   => "ndbmemcache config loader",
3577           path   => $exe_mysql,
3578           args   => \$args,
3579           input  => $sql_script,
3580           output => "$opt_vardir/log/memcache_config.log",
3581           error  => "$opt_vardir/log/memcache_config.log"
3582       ) != 0)
3583    {
3584      mtr_error("Could not load ndb_memcache_metadata.sql file");
3585    }
3586  }
3587}
3588
3589
3590sub ndbcluster_start ($) {
3591  my $cluster= shift;
3592
3593  mtr_verbose("ndbcluster_start '".$cluster->name()."'");
3594
3595  foreach my $ndb_mgmd ( in_cluster($cluster, ndb_mgmds()) )
3596  {
3597    next if started($ndb_mgmd);
3598    ndb_mgmd_start($cluster, $ndb_mgmd);
3599  }
3600
3601  foreach my $ndbd ( in_cluster($cluster, ndbds()) )
3602  {
3603    next if started($ndbd);
3604    ndbd_start($cluster, $ndbd);
3605  }
3606
3607  return 0;
3608}
3609
3610
3611sub create_config_file_for_extern {
3612  my %opts=
3613    (
3614     socket     => '/tmp/mysqld.sock',
3615     port       => 3306,
3616     user       => $opt_user,
3617     password   => '',
3618     @_
3619    );
3620
3621  mtr_report("Creating my.cnf file for extern server...");
3622  my $F= IO::File->new($path_config_file, "w")
3623    or mtr_error("Can't write to $path_config_file: $!");
3624
3625  print $F "[client]\n";
3626  while (my ($option, $value)= each( %opts )) {
3627    print $F "$option= $value\n";
3628    mtr_report(" $option= $value");
3629  }
3630
3631  print $F <<EOF
3632
3633# binlog reads from [client] and [mysqlbinlog]
3634[mysqlbinlog]
3635character-sets-dir= $path_charsetsdir
3636local-load= $opt_tmpdir
3637
3638EOF
3639;
3640
3641  $F= undef; # Close file
3642}
3643
3644
3645#
3646# Kill processes left from previous runs, normally
3647# there should be none so make sure to warn
3648# if there is one
3649#
3650sub kill_leftovers ($) {
3651  my $rundir= shift;
3652  return unless ( -d $rundir );
3653
3654  mtr_report("Checking leftover processes...");
3655
3656  # Scan the "run" directory for process id's to kill
3657  opendir(RUNDIR, $rundir)
3658    or mtr_error("kill_leftovers, can't open dir \"$rundir\": $!");
3659  while ( my $elem= readdir(RUNDIR) )
3660  {
3661    # Only read pid from files that end with .pid
3662    if ( $elem =~ /.*[.]pid$/ )
3663    {
3664      my $pidfile= "$rundir/$elem";
3665      next unless -f $pidfile;
3666      my $pid= mtr_fromfile($pidfile);
3667      unlink($pidfile);
3668      unless ($pid=~ /^(\d+)/){
3669	# The pid was not a valid number
3670	mtr_warning("Got invalid pid '$pid' from '$elem'");
3671	next;
3672      }
3673      mtr_report(" - found old pid $pid in '$elem', killing it...");
3674
3675      my $ret= kill("KILL", $pid);
3676      if ($ret == 0) {
3677	mtr_report("   process did not exist!");
3678	next;
3679      }
3680
3681      my $check_counter= 100;
3682      while ($ret > 0 and $check_counter--) {
3683	mtr_milli_sleep(100);
3684	$ret= kill(0, $pid);
3685      }
3686      mtr_report($check_counter ? "   ok!" : "   failed!");
3687    }
3688    else
3689    {
3690      mtr_warning("Found non pid file '$elem' in '$rundir'")
3691	if -f "$rundir/$elem";
3692    }
3693  }
3694  closedir(RUNDIR);
3695}
3696
3697#
3698# Check that all the ports that are going to
3699# be used are free
3700#
3701sub check_ports_free ($)
3702{
3703  my $bthread= shift;
3704  my $portbase = $bthread * 10 + 10000;
3705  for ($portbase..$portbase+9){
3706    if (mtr_ping_port($_)){
3707      mtr_report(" - 'localhost:$_' was not free");
3708      return 0; # One port was not free
3709    }
3710  }
3711
3712  return 1; # All ports free
3713}
3714
3715
3716sub initialize_servers {
3717
3718  if ( using_extern() )
3719  {
3720    # Running against an already started server, if the specified
3721    # vardir does not already exist it should be created
3722    if ( ! -d $opt_vardir )
3723    {
3724      setup_vardir();
3725    }
3726    else
3727    {
3728      mtr_verbose("No need to create '$opt_vardir' it already exists");
3729    }
3730  }
3731  else
3732  {
3733    # Kill leftovers from previous run
3734    # using any pidfiles found in var/run
3735    kill_leftovers("$opt_vardir/run");
3736
3737    if ( ! $opt_start_dirty )
3738    {
3739      remove_stale_vardir();
3740      setup_vardir();
3741
3742      mysql_install_db(default_mysqld(), "$opt_vardir/install.db");
3743    }
3744  }
3745}
3746
3747
3748#
3749# Remove all newline characters expect after semicolon
3750#
3751sub sql_to_bootstrap {
3752  my ($sql) = @_;
3753  my @lines= split(/\n/, $sql);
3754  my $result= "\n";
3755  my $delimiter= ';';
3756
3757  foreach my $line (@lines) {
3758
3759    # Change current delimiter if line starts with "delimiter"
3760    if ( $line =~ /^delimiter (.*)/ ) {
3761      my $new= $1;
3762      # Remove old delimiter from end of new
3763      $new=~ s/\Q$delimiter\E$//;
3764      $delimiter = $new;
3765      mtr_debug("changed delimiter to $delimiter");
3766      # No need to add the delimiter to result
3767      next;
3768    }
3769
3770    # Add newline if line ends with $delimiter
3771    # and convert the current delimiter to semicolon
3772    if ( $line =~ /\Q$delimiter\E$/ ){
3773      $line =~ s/\Q$delimiter\E$/;/;
3774      $result.= "$line\n";
3775      mtr_debug("Added default delimiter");
3776      next;
3777    }
3778
3779    # Remove comments starting with --
3780    if ( $line =~ /^\s*--/ ) {
3781      mtr_debug("Discarded $line");
3782      next;
3783    }
3784
3785    # Replace @HOSTNAME with localhost
3786    $line=~ s/\'\@HOSTNAME\@\'/localhost/;
3787
3788    # Default, just add the line without newline
3789    # but with a space as separator
3790    $result.= "$line ";
3791
3792  }
3793  return $result;
3794}
3795
3796
3797sub default_mysqld {
3798  # Generate new config file from template
3799  my $config= My::ConfigFactory->new_config
3800    ( {
3801       basedir         => $basedir,
3802       testdir         => $glob_mysql_test_dir,
3803       template_path   => "include/default_my.cnf",
3804       vardir          => $opt_vardir,
3805       tmpdir          => $opt_tmpdir,
3806       baseport        => 0,
3807       user            => $opt_user,
3808       password        => '',
3809      }
3810    );
3811
3812  my $mysqld= $config->group('mysqld.1')
3813    or mtr_error("Couldn't find mysqld.1 in default config");
3814  return $mysqld;
3815}
3816
3817
3818sub mysql_install_db {
3819  my ($mysqld, $datadir)= @_;
3820
3821  my $install_datadir= $datadir || $mysqld->value('datadir');
3822  my $install_basedir= $mysqld->value('basedir');
3823  my $install_lang= $mysqld->value('lc-messages-dir');
3824  my $install_chsdir= $mysqld->value('character-sets-dir');
3825
3826  mtr_report("Installing system database...");
3827
3828  my $args;
3829  mtr_init_args(\$args);
3830  mtr_add_arg($args, "--no-defaults");
3831  mtr_add_arg($args, "--bootstrap");
3832  mtr_add_arg($args, "--basedir=%s", $install_basedir);
3833  mtr_add_arg($args, "--datadir=%s", $install_datadir);
3834  mtr_add_arg($args, "--loose-skip-falcon");
3835  mtr_add_arg($args, "--loose-skip-ndbcluster");
3836  mtr_add_arg($args, "--tmpdir=%s", "$opt_vardir/tmp/");
3837  mtr_add_arg($args, "--secure-file-priv=%s", "$opt_vardir");
3838  mtr_add_arg($args, "--innodb-log-file-size=5M");
3839  mtr_add_arg($args, "--core-file");
3840  # over writing innodb_autoextend_increment to 8 for reducing the ibdata1 file size
3841  mtr_add_arg($args, "--innodb_autoextend_increment=8");
3842
3843  if ( $opt_debug )
3844  {
3845    mtr_add_arg($args, "--debug=$debug_d:t:i:A,%s/log/bootstrap.trace",
3846		$path_vardir_trace);
3847  }
3848
3849  mtr_add_arg($args, "--lc-messages-dir=%s", $install_lang);
3850  mtr_add_arg($args, "--character-sets-dir=%s", $install_chsdir);
3851
3852  # InnoDB arguments that affect file location and sizes may
3853  # need to be given to the bootstrap process as well as the
3854  # server process.
3855  foreach my $extra_opt ( @opt_extra_mysqld_opt ) {
3856    (my $temp_extra_opt=$extra_opt) =~ s/_/-/g;
3857    if ($temp_extra_opt =~ /--innodb-page-size/ ||
3858        $temp_extra_opt =~ /--innodb-log-file-size/) {
3859      mtr_add_arg($args, $extra_opt);
3860    }
3861  }
3862
3863  # If DISABLE_GRANT_OPTIONS is defined when the server is compiled (e.g.,
3864  # configure --disable-grant-options), mysqld will not recognize the
3865  # --bootstrap or --skip-grant-tables options.  The user can set
3866  # MYSQLD_BOOTSTRAP to the full path to a mysqld which does accept
3867  # --bootstrap, to accommodate this.
3868  my $exe_mysqld_bootstrap =
3869    $ENV{'MYSQLD_BOOTSTRAP'} || find_mysqld($install_basedir);
3870
3871  # ----------------------------------------------------------------------
3872  # export MYSQLD_BOOTSTRAP_CMD variable containing <path>/mysqld <args>
3873  # ----------------------------------------------------------------------
3874  $ENV{'MYSQLD_BOOTSTRAP_CMD'}= "$exe_mysqld_bootstrap " . join(" ", @$args);
3875
3876
3877
3878  # ----------------------------------------------------------------------
3879  # Create the bootstrap.sql file
3880  # ----------------------------------------------------------------------
3881  my $bootstrap_sql_file= "$opt_vardir/tmp/bootstrap.sql";
3882
3883  if ($opt_boot_gdb) {
3884    gdb_arguments(\$args, \$exe_mysqld_bootstrap, $mysqld->name(),
3885		  $bootstrap_sql_file);
3886  }
3887  if ($opt_boot_dbx) {
3888    dbx_arguments(\$args, \$exe_mysqld_bootstrap, $mysqld->name(),
3889		  $bootstrap_sql_file);
3890  }
3891  if ($opt_boot_ddd) {
3892    ddd_arguments(\$args, \$exe_mysqld_bootstrap, $mysqld->name(),
3893		  $bootstrap_sql_file);
3894  }
3895
3896  my $path_sql= my_find_file($install_basedir,
3897			     ["mysql", "sql/share", "share/mysql",
3898			      "share", "scripts"],
3899			     "mysql_system_tables.sql",
3900			     NOT_REQUIRED);
3901
3902  if (-f $path_sql )
3903  {
3904    my $sql_dir= dirname($path_sql);
3905    # Use the mysql database for system tables
3906    mtr_tofile($bootstrap_sql_file, "use mysql;\n");
3907
3908    # Add the offical mysql system tables
3909    # for a production system
3910    mtr_appendfile_to_file("$sql_dir/mysql_system_tables.sql",
3911			   $bootstrap_sql_file);
3912
3913    # Add the mysql system tables initial data
3914    # for a production system
3915    mtr_appendfile_to_file("$sql_dir/mysql_system_tables_data.sql",
3916			   $bootstrap_sql_file);
3917
3918    # Add test data for timezone - this is just a subset, on a real
3919    # system these tables will be populated either by mysql_tzinfo_to_sql
3920    # or by downloading the timezone table package from our website
3921    mtr_appendfile_to_file("$sql_dir/mysql_test_data_timezone.sql",
3922			   $bootstrap_sql_file);
3923
3924    # Fill help tables, just an empty file when running from bk repo
3925    # but will be replaced by a real fill_help_tables.sql when
3926    # building the source dist
3927    mtr_appendfile_to_file("$sql_dir/fill_help_tables.sql",
3928			   $bootstrap_sql_file);
3929
3930  }
3931  else
3932  {
3933    # Install db from init_db.sql that exist in early 5.1 and 5.0
3934    # versions of MySQL
3935    my $init_file= "$install_basedir/mysql-test/lib/init_db.sql";
3936    mtr_report(" - from '$init_file'");
3937    my $text= mtr_grab_file($init_file) or
3938      mtr_error("Can't open '$init_file': $!");
3939
3940    mtr_tofile($bootstrap_sql_file,
3941	       sql_to_bootstrap($text));
3942  }
3943
3944  # Remove anonymous users
3945  mtr_tofile($bootstrap_sql_file,
3946	     "DELETE FROM mysql.user where user= '';\n");
3947
3948  # Create mtr database
3949  mtr_tofile($bootstrap_sql_file,
3950	     "CREATE DATABASE mtr;\n");
3951
3952  # Add help tables and data for warning detection and supression
3953  mtr_tofile($bootstrap_sql_file,
3954             sql_to_bootstrap(mtr_grab_file("include/mtr_warnings.sql")));
3955
3956  # Add procedures for checking server is restored after testcase
3957  mtr_tofile($bootstrap_sql_file,
3958             sql_to_bootstrap(mtr_grab_file("include/mtr_check.sql")));
3959
3960  # Log bootstrap command
3961  my $path_bootstrap_log= "$opt_vardir/log/bootstrap.log";
3962  mtr_tofile($path_bootstrap_log,
3963	     "$exe_mysqld_bootstrap " . join(" ", @$args) . "\n");
3964
3965  # Create directories mysql and test
3966  mkpath("$install_datadir/mysql");
3967  mkpath("$install_datadir/test");
3968
3969  if ( My::SafeProcess->run
3970       (
3971	name          => "bootstrap",
3972	path          => $exe_mysqld_bootstrap,
3973	args          => \$args,
3974	input         => $bootstrap_sql_file,
3975	output        => $path_bootstrap_log,
3976	error         => $path_bootstrap_log,
3977	append        => 1,
3978	verbose       => $opt_verbose,
3979       ) != 0)
3980  {
3981    mtr_error("Error executing mysqld --bootstrap\n" .
3982              "Could not install system database from $bootstrap_sql_file\n" .
3983	      "see $path_bootstrap_log for errors");
3984  }
3985}
3986
3987
3988sub run_testcase_check_skip_test($)
3989{
3990  my ($tinfo)= @_;
3991
3992  # ----------------------------------------------------------------------
3993  # If marked to skip, just print out and return.
3994  # Note that a test case not marked as 'skip' can still be
3995  # skipped later, because of the test case itself in cooperation
3996  # with the mysqltest program tells us so.
3997  # ----------------------------------------------------------------------
3998
3999  if ( $tinfo->{'skip'} )
4000  {
4001    mtr_report_test_skipped($tinfo) unless $start_only;
4002    return 1;
4003  }
4004
4005  return 0;
4006}
4007
4008
4009sub run_query {
4010  my ($tinfo, $mysqld, $query)= @_;
4011
4012  my $args;
4013  mtr_init_args(\$args);
4014  mtr_add_arg($args, "--defaults-file=%s", $path_config_file);
4015  mtr_add_arg($args, "--defaults-group-suffix=%s", $mysqld->after('mysqld'));
4016
4017  mtr_add_arg($args, "-e %s", $query);
4018
4019  my $res= My::SafeProcess->run
4020    (
4021     name          => "run_query -> ".$mysqld->name(),
4022     path          => $exe_mysql,
4023     args          => \$args,
4024     output        => '/dev/null',
4025     error         => '/dev/null'
4026    );
4027
4028  return $res
4029}
4030
4031
4032sub do_before_run_mysqltest($)
4033{
4034  my $tinfo= shift;
4035
4036  $ENV{'MYSQL_CURRENT_TEST_DIR'} = dirname($tinfo->{'path'});
4037  # Remove old files produced by mysqltest
4038  my $base_file= mtr_match_extension($tinfo->{result_file},
4039				     "result"); # Trim extension
4040  if (defined $base_file ){
4041    unlink("$base_file.reject");
4042    unlink("$base_file.progress");
4043    unlink("$base_file.log");
4044    unlink("$base_file.warnings");
4045  }
4046
4047  if ( $mysql_version_id < 50000 ) {
4048    # Set environment variable NDB_STATUS_OK to 1
4049    # if script decided to run mysqltest cluster _is_ installed ok
4050    $ENV{'NDB_STATUS_OK'} = "1";
4051  } elsif ( $mysql_version_id < 50100 ) {
4052    # Set environment variable NDB_STATUS_OK to YES
4053    # if script decided to run mysqltest cluster _is_ installed ok
4054    $ENV{'NDB_STATUS_OK'} = "YES";
4055  }
4056}
4057
4058
4059#
4060# Check all server for sideffects
4061#
4062# RETURN VALUE
4063#  0 ok
4064#  1 Check failed
4065#  >1 Fatal errro
4066
4067sub check_testcase($$)
4068{
4069  my ($tinfo, $mode)= @_;
4070  my $tname= $tinfo->{name};
4071
4072  # Start the mysqltest processes in parallel to save time
4073  # also makes it possible to wait for any process to exit during the check
4074  my %started;
4075  foreach my $mysqld ( mysqlds() )
4076  {
4077    # Skip if server has been restarted with additional options
4078    if ( defined $mysqld->{'proc'} && ! exists $mysqld->{'restart_opts'} )
4079    {
4080      my $proc= start_check_testcase($tinfo, $mode, $mysqld);
4081      $started{$proc->pid()}= $proc;
4082    }
4083  }
4084
4085  # Return immediately if no check proceess was started
4086  return 0 unless ( keys %started );
4087
4088  my $timeout= start_timer(check_timeout($tinfo));
4089
4090  while (1){
4091    my $result;
4092    my $proc= My::SafeProcess->wait_any_timeout($timeout);
4093    mtr_report("Got $proc");
4094
4095    if ( delete $started{$proc->pid()} ) {
4096
4097      my $err_file= $proc->user_data();
4098      my $base_file= mtr_match_extension($err_file, "err"); # Trim extension
4099
4100      # One check testcase process returned
4101      my $res= $proc->exit_status();
4102
4103      if ( $res == 0){
4104	# Check completed without problem
4105
4106	# Remove the .err file the check generated
4107	unlink($err_file);
4108
4109	# Remove the .result file the check generated
4110	if ( $mode eq 'after' ){
4111	  unlink("$base_file.result");
4112	}
4113
4114	if ( keys(%started) == 0){
4115	  # All checks completed
4116	  mark_time_used('check');
4117	  return 0;
4118	}
4119	# Wait for next process to exit
4120	next;
4121      }
4122      else
4123      {
4124	if ( $mode eq "after" and $res == 1 )
4125	{
4126	  # Test failed, grab the report mysqltest has created
4127	  my $report= mtr_grab_file($err_file);
4128	  $tinfo->{check}.=
4129	    "\nMTR's internal check of the test case '$tname' failed.
4130This means that the test case does not preserve the state that existed
4131before the test case was executed.  Most likely the test case did not
4132do a proper clean-up. It could also be caused by the previous test run
4133by this thread, if the server wasn't restarted.
4134This is the diff of the states of the servers before and after the
4135test case was executed:\n";
4136	  $tinfo->{check}.= $report;
4137
4138	  # Check failed, mark the test case with that info
4139	  $tinfo->{'check_testcase_failed'}= 1;
4140	  $result= 1;
4141	}
4142	elsif ( $res )
4143	{
4144	  my $report= mtr_grab_file($err_file);
4145	  $tinfo->{comment}.=
4146	    "Could not execute 'check-testcase' $mode ".
4147	      "testcase '$tname' (res: $res):\n";
4148	  $tinfo->{comment}.= $report;
4149
4150	  $result= 2;
4151	}
4152
4153	# Remove the .result file the check generated
4154	unlink("$base_file.result");
4155
4156      }
4157    }
4158    elsif ( $proc->{timeout} ) {
4159      $tinfo->{comment}.= "Timeout for 'check-testcase' expired after "
4160	.check_timeout($tinfo)." seconds";
4161      $result= 4;
4162    }
4163    else {
4164      # Unknown process returned, most likley a crash, abort everything
4165      $tinfo->{comment}=
4166	"The server $proc crashed while running ".
4167	"'check testcase $mode test'".
4168	get_log_from_proc($proc, $tinfo->{name});
4169      $result= 3;
4170    }
4171
4172    # Kill any check processes still running
4173    map($_->kill(), values(%started));
4174
4175    mtr_warning("Check-testcase failed, this could also be caused by the" .
4176		" previous test run by this worker thread")
4177      if $result > 1 && $mode eq "before";
4178    mark_time_used('check');
4179
4180    return $result;
4181  }
4182
4183  mtr_error("INTERNAL_ERROR: check_testcase");
4184}
4185
4186
4187# Start run mysqltest on one server
4188#
4189# RETURN VALUE
4190#  0 OK
4191#  1 Check failed
4192#
4193sub start_run_one ($$) {
4194  my ($mysqld, $run)= @_;
4195
4196  my $name= "$run-".$mysqld->name();
4197
4198  my $args;
4199  mtr_init_args(\$args);
4200
4201  mtr_add_arg($args, "--defaults-file=%s", $path_config_file);
4202  mtr_add_arg($args, "--defaults-group-suffix=%s", $mysqld->after('mysqld'));
4203
4204  mtr_add_arg($args, "--silent");
4205  mtr_add_arg($args, "--test-file=%s", "include/$run.test");
4206
4207  my $errfile= "$opt_vardir/tmp/$name.err";
4208  my $proc= My::SafeProcess->new
4209    (
4210     name          => $name,
4211     path          => $exe_mysqltest,
4212     error         => $errfile,
4213     output        => $errfile,
4214     args          => \$args,
4215     user_data     => $errfile,
4216     verbose       => $opt_verbose,
4217    );
4218  mtr_verbose("Started $proc");
4219  return $proc;
4220}
4221
4222
4223#
4224# Run script on all servers, collect results
4225#
4226# RETURN VALUE
4227#  0 ok
4228#  1 Failure
4229
4230sub run_on_all($$)
4231{
4232  my ($tinfo, $run)= @_;
4233
4234  # Start the mysqltest processes in parallel to save time
4235  # also makes it possible to wait for any process to exit during the check
4236  # and to have a timeout process
4237  my %started;
4238  foreach my $mysqld ( mysqlds() )
4239  {
4240    if ( defined $mysqld->{'proc'} )
4241    {
4242      my $proc= start_run_one($mysqld, $run);
4243      $started{$proc->pid()}= $proc;
4244    }
4245  }
4246
4247  # Return immediately if no check proceess was started
4248  return 0 unless ( keys %started );
4249
4250  my $timeout= start_timer(check_timeout($tinfo));
4251
4252  while (1){
4253    my $result;
4254    my $proc= My::SafeProcess->wait_any_timeout($timeout);
4255    mtr_report("Got $proc");
4256
4257    if ( delete $started{$proc->pid()} ) {
4258
4259      # One mysqltest process returned
4260      my $err_file= $proc->user_data();
4261      my $res= $proc->exit_status();
4262
4263      # Append the report from .err file
4264      $tinfo->{comment}.= " == $err_file ==\n";
4265      $tinfo->{comment}.= mtr_grab_file($err_file);
4266      $tinfo->{comment}.= "\n";
4267
4268      # Remove the .err file
4269      unlink($err_file);
4270
4271      if ( keys(%started) == 0){
4272	# All completed
4273	return 0;
4274      }
4275
4276      # Wait for next process to exit
4277      next;
4278    }
4279    elsif ($proc->{timeout}) {
4280      $tinfo->{comment}.= "Timeout for '$run' expired after "
4281	.check_timeout($tinfo)." seconds";
4282    }
4283    else {
4284      # Unknown process returned, most likley a crash, abort everything
4285      $tinfo->{comment}.=
4286	"The server $proc crashed while running '$run'".
4287	get_log_from_proc($proc, $tinfo->{name});
4288    }
4289
4290    # Kill any check processes still running
4291    map($_->kill(), values(%started));
4292
4293    return 1;
4294  }
4295  mtr_error("INTERNAL_ERROR: run_on_all");
4296}
4297
4298
4299sub mark_log {
4300  my ($log, $tinfo)= @_;
4301  my $log_msg= "CURRENT_TEST: $tinfo->{name}\n";
4302  mtr_tofile($log, $log_msg);
4303}
4304
4305
4306sub find_testcase_skipped_reason($)
4307{
4308  my ($tinfo)= @_;
4309
4310  # Set default message
4311  $tinfo->{'comment'}= "Detected by testcase(no log file)";
4312
4313  # Open the test log file
4314  my $F= IO::File->new($path_current_testlog)
4315    or return;
4316  my $reason;
4317
4318  while ( my $line= <$F> )
4319  {
4320    # Look for "reason: <reason for skipping test>"
4321    if ( $line =~ /reason: (.*)/ )
4322    {
4323      $reason= $1;
4324    }
4325  }
4326
4327  if ( ! $reason )
4328  {
4329    mtr_warning("Could not find reason for skipping test in $path_current_testlog");
4330    $reason= "Detected by testcase(reason unknown) ";
4331  }
4332  $tinfo->{'comment'}= $reason;
4333}
4334
4335
4336sub find_analyze_request
4337{
4338  # Open the test log file
4339  my $F= IO::File->new($path_current_testlog)
4340    or return;
4341  my $analyze;
4342
4343  while ( my $line= <$F> )
4344  {
4345    # Look for "reason: <reason for skipping test>"
4346    if ( $line =~ /analyze: (.*)/ )
4347    {
4348      $analyze= $1;
4349    }
4350  }
4351
4352  return $analyze;
4353}
4354
4355
4356# The test can leave a file in var/tmp/ to signal
4357# that all servers should be restarted
4358sub restart_forced_by_test($)
4359{
4360  my $file = shift;
4361  my $restart = 0;
4362  foreach my $mysqld ( mysqlds() )
4363  {
4364    my $datadir = $mysqld->value('datadir');
4365    my $force_restart_file = "$datadir/mtr/$file";
4366    if ( -f $force_restart_file )
4367    {
4368      mtr_verbose("Restart of servers forced by test");
4369      $restart = 1;
4370      last;
4371    }
4372  }
4373  return $restart;
4374}
4375
4376
4377# Return timezone value of tinfo or default value
4378sub timezone {
4379  my ($tinfo)= @_;
4380  return $tinfo->{timezone} || "GMT-3";
4381}
4382
4383
4384# Storage for changed environment variables
4385my %old_env;
4386
4387sub resfile_report_test ($) {
4388  my $tinfo=  shift;
4389
4390  resfile_new_test();
4391
4392  resfile_test_info("name", $tinfo->{name});
4393  resfile_test_info("variation", $tinfo->{combination})
4394    if $tinfo->{combination};
4395  resfile_test_info("start_time", isotime time);
4396}
4397
4398sub error_logs_to_comment {
4399  my $tinfo= shift;
4400  foreach my $mysqld (mysqlds())
4401  {
4402    $tinfo->{comment}.= "\nServer " . $mysqld->{proc} . " log: ".
4403      get_log_from_proc($mysqld->{proc}, $tinfo->{name});
4404  }
4405}
4406
4407#
4408# Run a single test case
4409#
4410# RETURN VALUE
4411#  0 OK
4412#  > 0 failure
4413#
4414
4415sub run_testcase ($) {
4416  my $tinfo=  shift;
4417
4418  my $print_freq=20;
4419
4420  mtr_verbose("Running test:", $tinfo->{name});
4421  resfile_report_test($tinfo) if $opt_resfile;
4422
4423  # Allow only alpanumerics pluss _ - + . in combination names,
4424  # or anything beginning with -- (the latter comes from --combination)
4425  my $combination= $tinfo->{combination};
4426  if ($combination && $combination !~ /^\w[-\w\.\+]+$/
4427                   && $combination !~ /^--/)
4428  {
4429    mtr_error("Combination '$combination' contains illegal characters");
4430  }
4431  # -------------------------------------------------------
4432  # Init variables that can change between each test case
4433  # -------------------------------------------------------
4434  my $timezone= timezone($tinfo);
4435  $ENV{'TZ'}= $timezone;
4436  mtr_verbose("Setting timezone: $timezone");
4437
4438  if ( ! using_extern() )
4439  {
4440    my @restart= servers_need_restart($tinfo);
4441    if ( @restart != 0) {
4442      stop_servers($tinfo, @restart );
4443    }
4444
4445    if ( started(all_servers()) == 0 )
4446    {
4447
4448      # Remove old datadirs
4449      clean_datadir() unless $opt_start_dirty;
4450
4451      # Restore old ENV
4452      while (my ($option, $value)= each( %old_env )) {
4453	if (defined $value){
4454	  mtr_verbose("Restoring $option to $value");
4455	  $ENV{$option}= $value;
4456
4457	} else {
4458	  mtr_verbose("Removing $option");
4459	  delete($ENV{$option});
4460	}
4461      }
4462      %old_env= ();
4463
4464      mtr_verbose("Generating my.cnf from '$tinfo->{template_path}'");
4465
4466      # Generate new config file from template
4467      $config= My::ConfigFactory->new_config
4468	( {
4469	   basedir         => $basedir,
4470	   testdir         => $glob_mysql_test_dir,
4471	   template_path   => $tinfo->{template_path},
4472	   extra_template_path => $tinfo->{extra_template_path},
4473	   vardir          => $opt_vardir,
4474	   tmpdir          => $opt_tmpdir,
4475	   baseport        => $baseport,
4476	   #hosts          => [ 'host1', 'host2' ],
4477	   user            => $opt_user,
4478	   password        => '',
4479	   ssl             => $opt_ssl_supported,
4480	   embedded        => $opt_embedded_server,
4481	  }
4482	);
4483
4484      # Write the new my.cnf
4485      $config->save($path_config_file);
4486
4487      # Remember current config so a restart can occur when a test need
4488      # to use a different one
4489      $current_config_name= $tinfo->{template_path};
4490
4491      #
4492      # Set variables in the ENV section
4493      #
4494      foreach my $option ($config->options_in_group("ENV"))
4495      {
4496	# Save old value to restore it before next time
4497	$old_env{$option->name()}= $ENV{$option->name()};
4498
4499	mtr_verbose($option->name(), "=",$option->value());
4500	$ENV{$option->name()}= $option->value();
4501      }
4502    }
4503
4504    # Write start of testcase to log
4505    mark_log($path_current_testlog, $tinfo);
4506
4507    if (start_servers($tinfo))
4508    {
4509      report_failure_and_restart($tinfo);
4510      return 1;
4511    }
4512  }
4513  mark_time_used('restart');
4514
4515  # --------------------------------------------------------------------
4516  # If --start or --start-dirty given, stop here to let user manually
4517  # run tests
4518  # If --wait-all is also given, do the same, but don't die if one
4519  # server exits
4520  # ----------------------------------------------------------------------
4521
4522  if ( $start_only )
4523  {
4524    mtr_print("\nStarted", started(all_servers()));
4525    mtr_print("Using config for test", $tinfo->{name});
4526    mtr_print("Port and socket path for server(s):");
4527    foreach my $mysqld ( mysqlds() )
4528    {
4529      mtr_print ($mysqld->name() . "  " . $mysqld->value('port') .
4530	      "  " . $mysqld->value('socket'));
4531    }
4532    if ( $opt_start_exit )
4533    {
4534      mtr_print("Server(s) started, not waiting for them to finish");
4535      if (IS_WINDOWS)
4536      {
4537	POSIX::_exit(0);	# exit hangs here in ActiveState Perl
4538      }
4539      else
4540      {
4541	exit(0);
4542      }
4543    }
4544    mtr_print("Waiting for server(s) to exit...");
4545    if ( $opt_wait_all ) {
4546      My::SafeProcess->wait_all();
4547      mtr_print( "All servers exited" );
4548      exit(1);
4549    }
4550    else {
4551      my $proc= My::SafeProcess->wait_any();
4552      if ( grep($proc eq $_, started(all_servers())) )
4553      {
4554        mtr_print("Server $proc died");
4555        exit(1);
4556      }
4557      mtr_print("Unknown process $proc died");
4558      exit(1);
4559    }
4560  }
4561
4562  my $test_timeout= start_timer(testcase_timeout($tinfo));
4563
4564  do_before_run_mysqltest($tinfo);
4565
4566  mark_time_used('admin');
4567
4568  if ( $opt_check_testcases and check_testcase($tinfo, "before") ){
4569    # Failed to record state of server or server crashed
4570    report_failure_and_restart($tinfo);
4571
4572    return 1;
4573  }
4574
4575  my $test= start_mysqltest($tinfo);
4576  # Set only when we have to keep waiting after expectedly died server
4577  my $keep_waiting_proc = 0;
4578  my $print_timeout= start_timer($print_freq * 60);
4579
4580  while (1)
4581  {
4582    my $proc;
4583    if ($keep_waiting_proc)
4584    {
4585      # Any other process exited?
4586      $proc = My::SafeProcess->check_any();
4587      if ($proc)
4588      {
4589	mtr_verbose ("Found exited process $proc");
4590      }
4591      else
4592      {
4593	$proc = $keep_waiting_proc;
4594	# Also check if timer has expired, if so cancel waiting
4595	if ( has_expired($test_timeout) )
4596	{
4597	  $keep_waiting_proc = 0;
4598	}
4599      }
4600    }
4601    if (! $keep_waiting_proc)
4602    {
4603      if($test_timeout > $print_timeout)
4604      {
4605         $proc= My::SafeProcess->wait_any_timeout($print_timeout);
4606         if ( $proc->{timeout} )
4607         {
4608            #print out that the test is still on
4609            mtr_print("Test still running: $tinfo->{name}");
4610            #reset the timer
4611            $print_timeout= start_timer($print_freq * 60);
4612            next;
4613         }
4614      }
4615      else
4616      {
4617         $proc= My::SafeProcess->wait_any_timeout($test_timeout);
4618      }
4619    }
4620
4621    # Will be restored if we need to keep waiting
4622    $keep_waiting_proc = 0;
4623
4624    unless ( defined $proc )
4625    {
4626      mtr_error("wait_any failed");
4627    }
4628    mtr_verbose("Got $proc");
4629
4630    mark_time_used('test');
4631    # ----------------------------------------------------
4632    # Was it the test program that exited
4633    # ----------------------------------------------------
4634    if ($proc eq $test)
4635    {
4636      my $res= $test->exit_status();
4637
4638      if ($res == 0 and $opt_warnings and check_warnings($tinfo) )
4639      {
4640	# Test case suceeded, but it has produced unexpected
4641	# warnings, continue in $res == 1
4642	$res= 1;
4643	resfile_output($tinfo->{'warnings'}) if $opt_resfile;
4644      }
4645
4646      if ( $res == 0 )
4647      {
4648	my $check_res;
4649	if ( restart_forced_by_test('force_restart') )
4650	{
4651	  stop_all_servers($opt_shutdown_timeout);
4652	}
4653	elsif ( $opt_check_testcases and
4654	     $check_res= check_testcase($tinfo, "after"))
4655	{
4656	  if ($check_res == 1) {
4657	    # Test case had sideeffects, not fatal error, just continue
4658	    stop_all_servers($opt_shutdown_timeout);
4659	    mtr_report("Resuming tests...\n");
4660	    resfile_output($tinfo->{'check'}) if $opt_resfile;
4661	  }
4662	  else {
4663	    # Test case check failed fatally, probably a server crashed
4664	    report_failure_and_restart($tinfo);
4665	    return 1;
4666	  }
4667	}
4668	mtr_report_test_passed($tinfo);
4669      }
4670      elsif ( $res == 62 )
4671      {
4672	# Testcase itself tell us to skip this one
4673	$tinfo->{skip_reason} = MTR_SKIP_BY_TEST;
4674	# Try to get reason from test log file
4675	find_testcase_skipped_reason($tinfo);
4676	mtr_report_test_skipped($tinfo);
4677	# Restart if skipped due to missing perl, it may have had side effects
4678	if ( restart_forced_by_test('force_restart_if_skipped') ||
4679             $tinfo->{'comment'} =~ /^perl not found/ )
4680	{
4681	  stop_all_servers($opt_shutdown_timeout);
4682	}
4683      }
4684      elsif ( $res == 65 )
4685      {
4686	# Testprogram killed by signal
4687	$tinfo->{comment}=
4688	  "testprogram crashed(returned code $res)";
4689	report_failure_and_restart($tinfo);
4690      }
4691      elsif ( $res == 1 )
4692      {
4693	# Check if the test tool requests that
4694	# an analyze script should be run
4695	my $analyze= find_analyze_request();
4696	if ($analyze){
4697	  run_on_all($tinfo, "analyze-$analyze");
4698	}
4699
4700	# Wait a bit and see if a server died, if so report that instead
4701	mtr_milli_sleep(100);
4702	my $srvproc= My::SafeProcess::check_any();
4703	if ($srvproc && grep($srvproc eq $_, started(all_servers()))) {
4704	  $proc= $srvproc;
4705	  goto SRVDIED;
4706	}
4707
4708        error_logs_to_comment($tinfo);
4709
4710	# Test case failure reported by mysqltest
4711	report_failure_and_restart($tinfo);
4712      }
4713      else
4714      {
4715	# mysqltest failed, probably crashed
4716	$tinfo->{comment}=
4717	  "mysqltest failed with unexpected return code $res\n";
4718	report_failure_and_restart($tinfo);
4719      }
4720
4721      # Save info from this testcase run to mysqltest.log
4722      if( -f $path_current_testlog)
4723      {
4724	if ($opt_resfile && $res && $res != 62) {
4725	  resfile_output_file($path_current_testlog);
4726	}
4727	mtr_appendfile_to_file($path_current_testlog, $path_testlog);
4728	unlink($path_current_testlog);
4729      }
4730
4731      return ($res == 62) ? 0 : $res;
4732
4733    }
4734
4735    # ----------------------------------------------------
4736    # Check if it was an expected crash
4737    # ----------------------------------------------------
4738    my $check_crash = check_expected_crash_and_restart($proc);
4739    if ($check_crash)
4740    {
4741      # Keep waiting if it returned 2, if 1 don't wait or stop waiting.
4742      $keep_waiting_proc = 0 if $check_crash == 1;
4743      $keep_waiting_proc = $proc if $check_crash == 2;
4744      next;
4745    }
4746
4747  SRVDIED:
4748    # ----------------------------------------------------
4749    # Stop the test case timer
4750    # ----------------------------------------------------
4751    $test_timeout= 0;
4752
4753    # ----------------------------------------------------
4754    # Check if it was a server that died
4755    # ----------------------------------------------------
4756    if ( grep($proc eq $_, started(all_servers())) )
4757    {
4758      # Server failed, probably crashed
4759      $tinfo->{comment}=
4760	"Server $proc failed during test run" .
4761	get_log_from_proc($proc, $tinfo->{name});
4762
4763      # ----------------------------------------------------
4764      # It's not mysqltest that has exited, kill it
4765      # ----------------------------------------------------
4766      $test->kill();
4767
4768      report_failure_and_restart($tinfo);
4769      return 1;
4770    }
4771
4772    # Try to dump core for mysqltest and all servers
4773    foreach my $proc ($test, started(all_servers()))
4774    {
4775      mtr_print("Trying to dump core for $proc");
4776      if ($proc->dump_core())
4777      {
4778	$proc->wait_one(20);
4779      }
4780    }
4781
4782    # ----------------------------------------------------
4783    # It's not mysqltest that has exited, kill it
4784    # ----------------------------------------------------
4785    $test->kill();
4786
4787    # ----------------------------------------------------
4788    # Check if testcase timer expired
4789    # ----------------------------------------------------
4790    if ( $proc->{timeout} )
4791    {
4792      my $log_file_name= $opt_vardir."/log/".$tinfo->{shortname}.".log";
4793      $tinfo->{comment}=
4794        "Test case timeout after ".testcase_timeout($tinfo).
4795	  " seconds\n\n";
4796      # Add 20 last executed commands from test case log file
4797      if  (-e $log_file_name)
4798      {
4799        $tinfo->{comment}.=
4800	   "== $log_file_name == \n".
4801	     mtr_lastlinesfromfile($log_file_name, 500)."\n";
4802      }
4803      error_logs_to_comment($tinfo);
4804      $tinfo->{'timeout'}= testcase_timeout($tinfo); # Mark as timeout
4805      run_on_all($tinfo, 'analyze-timeout');
4806
4807      report_failure_and_restart($tinfo);
4808      return 1;
4809    }
4810
4811    mtr_error("Unhandled process $proc exited");
4812  }
4813  mtr_error("Should never come here");
4814}
4815
4816
4817# Extract server log from after the last occurrence of named test
4818# Return as an array of lines
4819#
4820
4821sub extract_server_log ($$) {
4822  my ($error_log, $tname) = @_;
4823
4824  # Open the servers .err log file and read all lines
4825  # belonging to current tets into @lines
4826  my $Ferr = IO::File->new($error_log)
4827    or mtr_error("Could not open file '$error_log' for reading: $!");
4828
4829  my @lines;
4830  my $found_test= 0;		# Set once we've found the log of this test
4831  while ( my $line = <$Ferr> )
4832  {
4833    if ($found_test)
4834    {
4835      # If test wasn't last after all, discard what we found, test again.
4836      if ( $line =~ /^CURRENT_TEST:/)
4837      {
4838	@lines= ();
4839	$found_test= $line =~ /^CURRENT_TEST: $tname$/;
4840      }
4841      else
4842      {
4843	push(@lines, $line);
4844	if (scalar(@lines) > 1000000) {
4845	  $Ferr = undef;
4846	  mtr_warning("Too much log from test, bailing out from extracting");
4847	  return ();
4848	}
4849      }
4850    }
4851    else
4852    {
4853      # Search for beginning of test, until found
4854      $found_test= 1 if ($line =~ /^CURRENT_TEST: $tname$/);
4855    }
4856  }
4857  $Ferr = undef; # Close error log file
4858
4859  return @lines;
4860}
4861
4862# Get log from server identified from its $proc object, from named test
4863# Return as a single string
4864#
4865
4866sub get_log_from_proc ($$) {
4867  my ($proc, $name)= @_;
4868  my $srv_log= "";
4869
4870  foreach my $mysqld (mysqlds()) {
4871    if ($mysqld->{proc} eq $proc) {
4872      my @srv_lines= extract_server_log($mysqld->value('#log-error'), $name);
4873      $srv_log= "\nServer log from this test:\n" .
4874	"----------SERVER LOG START-----------\n". join ("", @srv_lines) .
4875	"----------SERVER LOG END-------------\n";
4876      last;
4877    }
4878  }
4879  return $srv_log;
4880}
4881
4882# Perform a rough examination of the servers
4883# error log and write all lines that look
4884# suspicious into $error_log.warnings
4885#
4886sub extract_warning_lines ($$) {
4887  my ($error_log, $tname) = @_;
4888
4889  my @lines= extract_server_log($error_log, $tname);
4890
4891# Write all suspicious lines to $error_log.warnings file
4892  my $warning_log = "$error_log.warnings";
4893  my $Fwarn = IO::File->new($warning_log, "w")
4894    or die("Could not open file '$warning_log' for writing: $!");
4895  print $Fwarn "Suspicious lines from $error_log\n";
4896
4897  my @patterns =
4898    (
4899     qr/^Warning:|mysqld: Warning|\[Warning\]/,
4900     qr/^Error:|\[ERROR\]/,
4901     qr/^==\d+==\s+\S/, # valgrind errors
4902     qr/InnoDB: Warning|InnoDB: Error/,
4903     qr/^safe_mutex:|allocated at line/,
4904     qr/missing DBUG_RETURN/,
4905     qr/Attempting backtrace/,
4906     qr/Assertion .* failed/,
4907    );
4908  my $skip_valgrind= 0;
4909
4910  my $last_pat= "";
4911  my $num_rep= 0;
4912
4913  foreach my $line ( @lines )
4914  {
4915    if ($opt_valgrind_mysqld) {
4916      # Skip valgrind summary from tests where server has been restarted
4917      # Should this contain memory leaks, the final report will find it
4918      # Use a generic pattern for summaries
4919      $skip_valgrind= 1 if $line =~ /^==\d+== [A-Z ]+ SUMMARY:/;
4920      $skip_valgrind= 0 unless $line =~ /^==\d+==/;
4921      next if $skip_valgrind;
4922    }
4923    foreach my $pat ( @patterns )
4924    {
4925      if ( $line =~ /$pat/ )
4926      {
4927	# Remove initial timestamp and look for consecutive identical lines
4928	my $line_pat= $line;
4929	$line_pat =~ s/^[0-9:\-\+\.TZ ]*//;
4930	if ($line_pat eq $last_pat) {
4931	  $num_rep++;
4932	} else {
4933	  # Previous line had been repeated, report that first
4934	  if ($num_rep) {
4935	    print $Fwarn ".... repeated $num_rep times: $last_pat";
4936	    $num_rep= 0;
4937	  }
4938	  $last_pat= $line_pat;
4939	  print $Fwarn $line;
4940	}
4941	last;
4942      }
4943    }
4944  }
4945  # Catch the case of last warning being repeated
4946  if ($num_rep) {
4947    print $Fwarn ".... repeated $num_rep times: $last_pat";
4948  }
4949
4950  $Fwarn = undef; # Close file
4951
4952}
4953
4954
4955# Run include/check-warnings.test
4956#
4957# RETURN VALUE
4958#  0 OK
4959#  1 Check failed
4960#
4961sub start_check_warnings ($$) {
4962  my $tinfo=    shift;
4963  my $mysqld=   shift;
4964
4965  my $name= "warnings-".$mysqld->name();
4966
4967  my $log_error= $mysqld->value('#log-error');
4968  # To be communicated to the test
4969  $ENV{MTR_LOG_ERROR}= $log_error;
4970  extract_warning_lines($log_error, $tinfo->{name});
4971
4972  my $args;
4973  mtr_init_args(\$args);
4974
4975  mtr_add_arg($args, "--defaults-file=%s", $path_config_file);
4976  mtr_add_arg($args, "--defaults-group-suffix=%s", $mysqld->after('mysqld'));
4977  mtr_add_arg($args, "--test-file=%s", "include/check-warnings.test");
4978
4979  if ( $opt_embedded_server )
4980  {
4981
4982    # Get the args needed for the embedded server
4983    # and append them to args prefixed
4984    # with --sever-arg=
4985
4986    my $mysqld=  $config->group('embedded')
4987      or mtr_error("Could not get [embedded] section");
4988
4989    my $mysqld_args;
4990    mtr_init_args(\$mysqld_args);
4991    my $extra_opts= get_extra_opts($mysqld, $tinfo);
4992    mysqld_arguments($mysqld_args, $mysqld, $extra_opts);
4993    mtr_add_arg($args, "--server-arg=%s", $_) for @$mysqld_args;
4994  }
4995
4996  my $errfile= "$opt_vardir/tmp/$name.err";
4997  my $proc= My::SafeProcess->new
4998    (
4999     name          => $name,
5000     path          => $exe_mysqltest,
5001     error         => $errfile,
5002     output        => $errfile,
5003     args          => \$args,
5004     user_data     => $errfile,
5005     verbose       => $opt_verbose,
5006    );
5007  mtr_verbose("Started $proc");
5008  return $proc;
5009}
5010
5011
5012#
5013# Loop through our list of processes and check the error log
5014# for unexepcted errors and warnings
5015#
5016sub check_warnings ($) {
5017  my ($tinfo)= @_;
5018  my $res= 0;
5019
5020  my $tname= $tinfo->{name};
5021
5022  # Clear previous warnings
5023  delete($tinfo->{warnings});
5024
5025  # Start the mysqltest processes in parallel to save time
5026  # also makes it possible to wait for any process to exit during the check
5027  my %started;
5028  foreach my $mysqld ( mysqlds() )
5029  {
5030    if ( defined $mysqld->{'proc'} )
5031    {
5032      my $proc= start_check_warnings($tinfo, $mysqld);
5033      $started{$proc->pid()}= $proc;
5034    }
5035  }
5036
5037  # Return immediately if no check proceess was started
5038  return 0 unless ( keys %started );
5039
5040  my $timeout= start_timer(check_timeout($tinfo));
5041
5042  while (1){
5043    my $result= 0;
5044    my $proc= My::SafeProcess->wait_any_timeout($timeout);
5045    mtr_report("Got $proc");
5046
5047    if ( delete $started{$proc->pid()} ) {
5048      # One check warning process returned
5049      my $res= $proc->exit_status();
5050      my $err_file= $proc->user_data();
5051
5052      if ( $res == 0 or $res == 62 ){
5053
5054	if ( $res == 0 ) {
5055	  # Check completed with problem
5056	  my $report= mtr_grab_file($err_file);
5057	  # In rare cases on Windows, exit code 62 is lost, so check output
5058	  if (IS_WINDOWS and
5059	      $report =~ /^The test .* is not supported by this installation/) {
5060	    # Extra sanity check
5061	    if ($report =~ /^reason: OK$/m) {
5062	      $res= 62;
5063	      mtr_print("Seems to have lost exit code 62, assume no warn\n");
5064	      goto LOST62;
5065	    }
5066	  }
5067	  # Log to var/log/warnings file
5068	  mtr_tofile("$opt_vardir/log/warnings",
5069		     $tname."\n".$report);
5070
5071	  $tinfo->{'warnings'}.= $report;
5072	  $result= 1;
5073	}
5074      LOST62:
5075	if ( $res == 62 ) {
5076	  # Test case was ok and called "skip"
5077	  # Remove the .err file the check generated
5078	  unlink($err_file);
5079	}
5080
5081	if ( keys(%started) == 0){
5082	  # All checks completed
5083	  mark_time_used('ch-warn');
5084	  return $result;
5085	}
5086	# Wait for next process to exit
5087	next if not $result;
5088      }
5089      else
5090      {
5091	my $report= mtr_grab_file($err_file);
5092	$tinfo->{comment}.=
5093	  "Could not execute 'check-warnings' for ".
5094	    "testcase '$tname' (res: $res):\n";
5095	$tinfo->{comment}.= $report;
5096
5097	$result= 2;
5098      }
5099    }
5100    elsif ( $proc->{timeout} ) {
5101      $tinfo->{comment}.= "Timeout for 'check warnings' expired after "
5102	.check_timeout($tinfo)." seconds";
5103      $result= 4;
5104    }
5105    else {
5106      # Unknown process returned, most likley a crash, abort everything
5107      $tinfo->{comment}=
5108	"The server $proc crashed while running 'check warnings'".
5109	get_log_from_proc($proc, $tinfo->{name});
5110      $result= 3;
5111    }
5112
5113    # Kill any check processes still running
5114    map($_->kill(), values(%started));
5115
5116    mark_time_used('ch-warn');
5117    return $result;
5118  }
5119
5120  mtr_error("INTERNAL_ERROR: check_warnings");
5121}
5122
5123
5124#
5125# Loop through our list of processes and look for and entry
5126# with the provided pid, if found check for the file indicating
5127# expected crash and restart it.
5128#
5129sub check_expected_crash_and_restart {
5130  my ($proc)= @_;
5131
5132  foreach my $mysqld ( mysqlds() )
5133  {
5134    next unless ( $mysqld->{proc} and $mysqld->{proc} eq $proc );
5135
5136    # Check if crash expected by looking at the .expect file
5137    # in var/tmp
5138    my $expect_file= "$opt_vardir/tmp/".$mysqld->name().".expect";
5139    if ( -f $expect_file )
5140    {
5141      mtr_verbose("Crash was expected, file '$expect_file' exists");
5142
5143      for (my $waits = 0;  $waits < 50;  mtr_milli_sleep(100), $waits++)
5144      {
5145	# Race condition seen on Windows: try again until file not empty
5146	next if -z $expect_file;
5147	# If last line in expect file starts with "wait"
5148	# sleep a little and try again, thus allowing the
5149	# test script to control when the server should start
5150	# up again. Keep trying for up to 5s at a time.
5151	my $last_line= mtr_lastlinesfromfile($expect_file, 1);
5152	if ($last_line =~ /^wait/ )
5153	{
5154	  mtr_verbose("Test says wait before restart") if $waits == 0;
5155	  next;
5156	}
5157
5158	# Ignore any partial or unknown command
5159	next unless $last_line =~ /^restart/;
5160	# If last line begins "restart:", the rest of the line is read as
5161        # extra command line options to add to the restarted mysqld.
5162        # Anything other than 'wait' or 'restart:' (with a colon) will
5163        # result in a restart with original mysqld options.
5164	if ($last_line =~ /restart:(.+)/) {
5165	  my @rest_opt= split(' ', $1);
5166	  $mysqld->{'restart_opts'}= \@rest_opt;
5167	} else {
5168	  delete $mysqld->{'restart_opts'};
5169	}
5170	unlink($expect_file);
5171
5172	# Start server with same settings as last time
5173	mysqld_start($mysqld, $mysqld->{'started_opts'});
5174
5175	return 1;
5176      }
5177      # Loop ran through: we should keep waiting after a re-check
5178      return 2;
5179    }
5180  }
5181
5182  # Not an expected crash
5183  return 0;
5184}
5185
5186
5187# Remove all files and subdirectories of a directory
5188sub clean_dir {
5189  my ($dir)= @_;
5190  mtr_verbose("clean_dir: $dir");
5191  finddepth(
5192	  { no_chdir => 1,
5193	    wanted => sub {
5194	      if (-d $_){
5195		# A dir
5196		if ($_ eq $dir){
5197		  # The dir to clean
5198		  return;
5199		} else {
5200		  mtr_verbose("rmdir: '$_'");
5201		  rmdir($_) or mtr_warning("rmdir($_) failed: $!");
5202		}
5203	      } else {
5204		# Hopefully a file
5205		mtr_verbose("unlink: '$_'");
5206		unlink($_) or mtr_warning("unlink($_) failed: $!");
5207	      }
5208	    }
5209	  },
5210	    $dir);
5211}
5212
5213
5214sub clean_datadir {
5215
5216  mtr_verbose("Cleaning datadirs...");
5217
5218  if (started(all_servers()) != 0){
5219    mtr_error("Trying to clean datadir before all servers stopped");
5220  }
5221
5222  foreach my $cluster ( clusters() )
5223  {
5224    my $cluster_dir= "$opt_vardir/".$cluster->{name};
5225    mtr_verbose(" - removing '$cluster_dir'");
5226    rmtree($cluster_dir);
5227
5228  }
5229
5230  foreach my $mysqld ( mysqlds() )
5231  {
5232    my $mysqld_dir= dirname($mysqld->value('datadir'));
5233    if (-d $mysqld_dir ) {
5234      mtr_verbose(" - removing '$mysqld_dir'");
5235      rmtree($mysqld_dir);
5236    }
5237  }
5238
5239  # Remove all files in tmp and var/tmp
5240  clean_dir("$opt_vardir/tmp");
5241  if ($opt_tmpdir ne "$opt_vardir/tmp"){
5242    clean_dir($opt_tmpdir);
5243  }
5244}
5245
5246
5247#
5248# Save datadir before it's removed
5249#
5250sub save_datadir_after_failure($$) {
5251  my ($dir, $savedir)= @_;
5252
5253  mtr_report(" - saving '$dir'");
5254  my $dir_name= basename($dir);
5255  rename("$dir", "$savedir/$dir_name");
5256}
5257
5258
5259sub remove_ndbfs_from_ndbd_datadir {
5260  my ($ndbd_datadir)= @_;
5261  # Remove the ndb_*_fs directory from ndbd.X/ dir
5262  foreach my $ndbfs_dir ( glob("$ndbd_datadir/ndb_*_fs") )
5263  {
5264    next unless -d $ndbfs_dir; # Skip if not a directory
5265    rmtree($ndbfs_dir);
5266  }
5267}
5268
5269
5270sub after_failure ($) {
5271  my ($tinfo)= @_;
5272
5273  mtr_report("Saving datadirs...");
5274
5275  my $save_dir= "$opt_vardir/log/";
5276  $save_dir.= $tinfo->{name};
5277  # Add combination name if any
5278  $save_dir.= "-$tinfo->{combination}"
5279    if defined $tinfo->{combination};
5280
5281  # Save savedir  path for server
5282  $tinfo->{savedir}= $save_dir;
5283
5284  mkpath($save_dir) if ! -d $save_dir;
5285
5286  # Save the used my.cnf file
5287  copy($path_config_file, $save_dir);
5288
5289  # Copy the tmp dir
5290  copytree("$opt_vardir/tmp/", "$save_dir/tmp/");
5291
5292  if ( clusters() ) {
5293    foreach my $cluster ( clusters() ) {
5294      my $cluster_dir= "$opt_vardir/".$cluster->{name};
5295
5296      # Remove the fileystem of each ndbd
5297      foreach my $ndbd ( in_cluster($cluster, ndbds()) )
5298      {
5299        my $ndbd_datadir= $ndbd->value("DataDir");
5300        remove_ndbfs_from_ndbd_datadir($ndbd_datadir);
5301      }
5302
5303      save_datadir_after_failure($cluster_dir, $save_dir);
5304    }
5305  }
5306  else {
5307    foreach my $mysqld ( mysqlds() ) {
5308      my $data_dir= $mysqld->value('datadir');
5309      save_datadir_after_failure(dirname($data_dir), $save_dir);
5310    }
5311  }
5312}
5313
5314
5315sub report_failure_and_restart ($) {
5316  my $tinfo= shift;
5317
5318  if ($opt_valgrind_mysqld && ($tinfo->{'warnings'} || $tinfo->{'timeout'})) {
5319    # In these cases we may want valgrind report from normal termination
5320    $tinfo->{'dont_kill_server'}= 1;
5321  }
5322
5323  # Shutdown properly if not to be killed (for valgrind)
5324  stop_all_servers($tinfo->{'dont_kill_server'} ? $opt_shutdown_timeout : 0);
5325
5326  $tinfo->{'result'}= 'MTR_RES_FAILED';
5327
5328  my $test_failures= $tinfo->{'failures'} || 0;
5329  $tinfo->{'failures'}=  $test_failures + 1;
5330
5331
5332  if ( $tinfo->{comment} )
5333  {
5334    # The test failure has been detected by mysql-test-run.pl
5335    # when starting the servers or due to other error, the reason for
5336    # failing the test is saved in "comment"
5337    ;
5338  }
5339
5340  if ( !defined $tinfo->{logfile} )
5341  {
5342    my $logfile= $path_current_testlog;
5343    if ( defined $logfile )
5344    {
5345      if ( -f $logfile )
5346      {
5347	# Test failure was detected by test tool and its report
5348	# about what failed has been saved to file. Save the report
5349	# in tinfo
5350	$tinfo->{logfile}= mtr_fromfile($logfile);
5351	# If no newlines in the test log:
5352	# (it will contain the CURRENT_TEST written by mtr, so is not empty)
5353	if ($tinfo->{logfile} !~ /\n/)
5354	{
5355	  # Show how far it got before suddenly failing
5356	  $tinfo->{comment}.= "mysqltest failed but provided no output\n";
5357	  my $log_file_name= $opt_vardir."/log/".$tinfo->{shortname}.".log";
5358	  if (-e $log_file_name) {
5359	    $tinfo->{comment}.=
5360	      "The result from queries just before the failure was:".
5361	      "\n< snip >\n".
5362	      mtr_lastlinesfromfile($log_file_name, 500)."\n";
5363	  }
5364	}
5365      }
5366      else
5367      {
5368	# The test tool report didn't exist, display an
5369	# error message
5370	$tinfo->{logfile}= "Could not open test tool report '$logfile'";
5371      }
5372    }
5373  }
5374
5375  after_failure($tinfo);
5376
5377  mtr_report_test($tinfo);
5378
5379}
5380
5381
5382sub run_sh_script {
5383  my ($script)= @_;
5384
5385  return 0 unless defined $script;
5386
5387  mtr_verbose("Running '$script'");
5388  my $ret= system("/bin/sh $script") >> 8;
5389  return $ret;
5390}
5391
5392
5393sub mysqld_stop {
5394  my $mysqld= shift or die "usage: mysqld_stop(<mysqld>)";
5395
5396  my $args;
5397  mtr_init_args(\$args);
5398
5399  mtr_add_arg($args, "--no-defaults");
5400  mtr_add_arg($args, "--character-sets-dir=%s", $mysqld->value('character-sets-dir'));
5401  mtr_add_arg($args, "--user=%s", $opt_user);
5402  mtr_add_arg($args, "--password=");
5403  mtr_add_arg($args, "--port=%d", $mysqld->value('port'));
5404  mtr_add_arg($args, "--host=%s", $mysqld->value('#host'));
5405  mtr_add_arg($args, "--connect_timeout=20");
5406  mtr_add_arg($args, "--protocol=tcp");
5407
5408  mtr_add_arg($args, "shutdown");
5409
5410  My::SafeProcess->run
5411    (
5412     name          => "mysqladmin shutdown ".$mysqld->name(),
5413     path          => $exe_mysqladmin,
5414     args          => \$args,
5415     error         => "/dev/null",
5416
5417    );
5418}
5419
5420
5421sub mysqld_arguments ($$$) {
5422  my $args=              shift;
5423  my $mysqld=            shift;
5424  my $extra_opts=        shift;
5425
5426  my @defaults = grep(/^--defaults-file=/, @$extra_opts);
5427  if (@defaults > 0) {
5428    mtr_add_arg($args, pop(@defaults))
5429  }
5430  else {
5431    mtr_add_arg($args, "--defaults-file=%s",  $path_config_file);
5432  }
5433
5434  # When mysqld is run by a root user(euid is 0), it will fail
5435  # to start unless we specify what user to run as, see BUG#30630
5436  my $euid= $>;
5437  if (!IS_WINDOWS and $euid == 0 and
5438      (grep(/^--user/, @$extra_opts)) == 0) {
5439    mtr_add_arg($args, "--user=root");
5440  }
5441
5442  if ( $opt_valgrind_mysqld )
5443  {
5444    if ( $mysql_version_id < 50100 )
5445    {
5446      mtr_add_arg($args, "--skip-bdb");
5447    }
5448  }
5449
5450  # On some old linux kernels, aio on tmpfs is not supported
5451  # Remove this if/when Bug #58421 fixes this in the server
5452  if ($^O eq "linux" && $opt_mem)
5453  {
5454    mtr_add_arg($args, "--loose-skip-innodb-use-native-aio");
5455  }
5456
5457  if ( $mysql_version_id >= 50106 && !$opt_user_args)
5458  {
5459    # Turn on logging to file
5460    mtr_add_arg($args, "--log-output=file");
5461  }
5462
5463  # Check if "extra_opt" contains skip-log-bin
5464  my $skip_binlog= grep(/^(--|--loose-)skip-log-bin/, @$extra_opts);
5465
5466  # Indicate to mysqld it will be debugged in debugger
5467  if ( $glob_debugger )
5468  {
5469    mtr_add_arg($args, "--gdb");
5470  }
5471
5472  # Enable the debug sync facility, set default wait timeout.
5473  # Facility stays disabled if timeout value is zero.
5474  mtr_add_arg($args, "--loose-debug-sync-timeout=%s",
5475              $opt_debug_sync_timeout) unless $opt_user_args;
5476
5477  # Options specified in .opt files should be added last so they can
5478  # override defaults above.
5479
5480  my $found_skip_core= 0;
5481  my $found_no_console= 0;
5482  my $found_log_error= 0;
5483
5484  # On windows, do not add console if log-error found in .cnf file
5485  open (CONFIG_FILE, " < $path_config_file") or
5486    die("Could not open output file $path_config_file");
5487
5488  while (<CONFIG_FILE>)
5489  {
5490    if (m/^log[-_]error/)
5491    {
5492      $found_log_error= 1;
5493    }
5494  }
5495  close (CONFIG_FILE);
5496
5497  foreach my $arg ( @$extra_opts )
5498  {
5499    # Skip --defaults-file option since it's handled above.
5500    next if $arg =~ /^--defaults-file/;
5501
5502    if ($arg =~ /^--log[-_]error/)
5503    {
5504      $found_log_error= 1;
5505    }
5506
5507    # Allow --skip-core-file to be set in <testname>-[master|slave].opt file
5508    if ($arg eq "--skip-core-file")
5509    {
5510      $found_skip_core= 1;
5511    }
5512    elsif ($arg eq "--no-console")
5513    {
5514        $found_no_console= 1;
5515    }
5516    elsif ($skip_binlog and mtr_match_prefix($arg, "--binlog-format"))
5517    {
5518      ; # Dont add --binlog-format when running without binlog
5519    }
5520    elsif ($arg eq "--loose-skip-log-bin" and
5521           $mysqld->option("log-slave-updates"))
5522    {
5523      ; # Dont add --skip-log-bin when mysqld have --log-slave-updates in config
5524    }
5525    elsif ($arg eq "")
5526    {
5527      # We can get an empty argument when  we set environment variables to ""
5528      # (e.g plugin not found). Just skip it.
5529    }
5530    else
5531    {
5532      mtr_add_arg($args, "%s", $arg);
5533    }
5534  }
5535  $opt_skip_core = $found_skip_core;
5536  if (IS_WINDOWS && !$found_no_console && !$found_log_error)
5537  {
5538    # Trick the server to send output to stderr, with --console
5539    mtr_add_arg($args, "--console");
5540  }
5541  if ( !$found_skip_core && !$opt_user_args )
5542  {
5543    mtr_add_arg($args, "%s", "--core-file");
5544  }
5545
5546  return $args;
5547}
5548
5549
5550
5551sub mysqld_start ($$) {
5552  my $mysqld=            shift;
5553  my $extra_opts=        shift;
5554
5555  mtr_verbose(My::Options::toStr("mysqld_start", @$extra_opts));
5556
5557  my $exe= find_mysqld($mysqld->value('basedir'));
5558  my $wait_for_pid_file= 1;
5559
5560  mtr_error("Internal error: mysqld should never be started for embedded")
5561    if $opt_embedded_server;
5562
5563  my $args;
5564  mtr_init_args(\$args);
5565# implementation for strace-server
5566  if ( $opt_strace_server )
5567  {
5568    strace_server_arguments($args, \$exe, $mysqld->name());
5569  }
5570
5571
5572  if ( $opt_valgrind_mysqld )
5573  {
5574    valgrind_arguments($args, \$exe, $mysqld->name());
5575  }
5576
5577  mtr_add_arg($args, "--defaults-group-suffix=%s", $mysqld->after('mysqld'));
5578
5579  # Add any additional options from an in-test restart
5580  my @all_opts= @$extra_opts;
5581  if (exists $mysqld->{'restart_opts'}) {
5582    push (@all_opts, @{$mysqld->{'restart_opts'}});
5583    mtr_verbose(My::Options::toStr("mysqld_start restart",
5584				   @{$mysqld->{'restart_opts'}}));
5585  }
5586  mysqld_arguments($args,$mysqld,\@all_opts);
5587
5588  if ( $opt_debug )
5589  {
5590    mtr_add_arg($args, "--debug=$debug_d:t:i:A,%s/log/%s.trace",
5591		$path_vardir_trace, $mysqld->name());
5592  }
5593
5594  if ( $opt_gdb || $opt_manual_gdb )
5595  {
5596    gdb_arguments(\$args, \$exe, $mysqld->name());
5597  }
5598  elsif ( $opt_lldb || $opt_manual_lldb )
5599  {
5600    lldb_arguments(\$args, \$exe, $mysqld->name());
5601  }
5602  elsif ( $opt_ddd || $opt_manual_ddd )
5603  {
5604    ddd_arguments(\$args, \$exe, $mysqld->name());
5605  }
5606  if ( $opt_dbx || $opt_manual_dbx ) {
5607    dbx_arguments(\$args, \$exe, $mysqld->name());
5608  }
5609  elsif ( $opt_debugger )
5610  {
5611    debugger_arguments(\$args, \$exe, $mysqld->name());
5612  }
5613  elsif ( $opt_manual_debug )
5614  {
5615     print "\nStart " .$mysqld->name()." in your debugger\n" .
5616           "dir: $glob_mysql_test_dir\n" .
5617           "exe: $exe\n" .
5618	   "args:  " . join(" ", @$args)  . "\n\n" .
5619	   "Waiting ....\n";
5620
5621     # Indicate the exe should not be started
5622    $exe= undef;
5623  }
5624  else
5625  {
5626    # Default to not wait until pid file has been created
5627    $wait_for_pid_file= 0;
5628  }
5629
5630  # Remove the old pidfile if any
5631  unlink($mysqld->value('pid-file'));
5632
5633  my $output= $mysqld->value('#log-error');
5634
5635  # Remember this log file for valgrind/shutdown error report search
5636  $mysqld_logs{$output}= 1;
5637
5638  # Remember data dir for gmon.out files if using gprof
5639  $gprof_dirs{$mysqld->value('datadir')}= 1 if $opt_gprof;
5640
5641  if ( defined $exe )
5642  {
5643    $mysqld->{'proc'}= My::SafeProcess->new
5644      (
5645       name          => $mysqld->name(),
5646       path          => $exe,
5647       args          => \$args,
5648       output        => $output,
5649       error         => $output,
5650       append        => 1,
5651       verbose       => $opt_verbose,
5652       nocore        => $opt_skip_core,
5653       host          => undef,
5654       shutdown      => sub { mysqld_stop($mysqld) },
5655       envs          => \@opt_mysqld_envs,
5656      );
5657    mtr_verbose("Started $mysqld->{proc}");
5658  }
5659
5660  if ( $wait_for_pid_file &&
5661       !sleep_until_file_created($mysqld->value('pid-file'),
5662				 $opt_start_timeout,
5663				 $mysqld->{'proc'}))
5664  {
5665    my $mname= $mysqld->name();
5666    mtr_error("Failed to start mysqld $mname with command $exe");
5667  }
5668
5669  # Remember options used when starting
5670  $mysqld->{'started_opts'}= $extra_opts;
5671
5672  return;
5673}
5674
5675sub shutdown_processes {
5676  my ($timeout, @servers)= @_;
5677  my $append_exit_reports= 0;
5678  my %status = My::SafeProcess::shutdown($timeout, @servers);
5679
5680  if ($status{failed}) {
5681    $shutdown_report_text.= "mysqld abnormal exit\n";
5682  }
5683  if ($status{killed}) {
5684    $shutdown_report_text.=
5685      "mysqld was killed after it failed to properly shutdown\n";
5686  }
5687
5688  if ($status{failed} or $status{killed}) {
5689    $shutdown_report = 1;
5690    my $reports= shutdown_exit_reports();
5691    while (my ($log_file, $report) = each (%$reports)) {
5692      $shutdown_report_text.= $log_file . " after tests: @{$report->{after_tests}}:\n".
5693                              "----------SERVER LOG START-----------\n".
5694                              $report->{text}.
5695                              "----------SERVER LOG END-------------\n";
5696    }
5697  }
5698}
5699
5700sub stop_all_servers () {
5701  my $shutdown_timeout = $_[0] or 0;
5702
5703  mtr_verbose("Stopping all servers...");
5704
5705  # Kill all started servers
5706  shutdown_processes($shutdown_timeout,
5707                     started(all_servers()));
5708
5709  # Remove pidfiles
5710  foreach my $server ( all_servers() )
5711  {
5712    my $pid_file= $server->if_exist('pid-file');
5713    unlink($pid_file) if defined $pid_file;
5714  }
5715
5716  # Mark servers as stopped
5717  map($_->{proc} = undef, all_servers());
5718}
5719
5720
5721# Find out if server should be restarted for this test
5722sub server_need_restart {
5723  my ($tinfo, $server)= @_;
5724
5725  # Mark the tinfo so slaves will restart if server restarts
5726  # This assumes master will be considered first.
5727  my $is_master= $server->option("#!run-master-sh");
5728
5729  if ( using_extern() )
5730  {
5731    mtr_verbose_restart($server, "no restart for --extern server");
5732    return 0;
5733  }
5734
5735  if ( $tinfo->{'force_restart'} ) {
5736    mtr_verbose_restart($server, "forced in .opt file");
5737    $tinfo->{master_restart}= 1 if $is_master;
5738    return 1;
5739  }
5740
5741  if ( $opt_force_restart ) {
5742    mtr_verbose_restart($server, "forced restart turned on");
5743    $tinfo->{master_restart}= 1 if $is_master;
5744    return 1;
5745  }
5746
5747  if ( $tinfo->{template_path} ne $current_config_name)
5748  {
5749    mtr_verbose_restart($server, "using different config file");
5750    $tinfo->{master_restart}= 1 if $is_master;
5751    return 1;
5752  }
5753
5754  if ( $tinfo->{'master_sh'}  || $tinfo->{'slave_sh'} )
5755  {
5756    mtr_verbose_restart($server, "sh script to run");
5757    $tinfo->{master_restart}= 1 if $is_master;
5758    return 1;
5759  }
5760
5761  if ( ! started($server) )
5762  {
5763    mtr_verbose_restart($server, "not started");
5764    $tinfo->{master_restart}= 1 if $is_master;
5765    return 1;
5766  }
5767
5768  my $started_tinfo= $server->{'started_tinfo'};
5769  if ( defined $started_tinfo )
5770  {
5771
5772    # Check if timezone of  test that server was started
5773    # with differs from timezone of next test
5774    if ( timezone($started_tinfo) ne timezone($tinfo) )
5775    {
5776      mtr_verbose_restart($server, "different timezone");
5777      $tinfo->{master_restart}= 1 if $is_master;
5778      return 1;
5779    }
5780  }
5781
5782  my $is_mysqld= grep ($server eq $_, mysqlds());
5783  if ($is_mysqld)
5784  {
5785
5786    # Check that running process was started with same options
5787    # as the current test requires
5788    my $extra_opts= get_extra_opts($server, $tinfo);
5789    my $started_opts= $server->{'started_opts'};
5790
5791    # Also, always restart if server had been restarted with additional
5792    # options within test.
5793    if (!My::Options::same($started_opts, $extra_opts) ||
5794        exists $server->{'restart_opts'})
5795    {
5796      my $use_dynamic_option_switch= 0;
5797      if (!$use_dynamic_option_switch)
5798      {
5799	mtr_verbose_restart($server, "running with different options '" .
5800			    join(" ", @{$extra_opts}) . "' != '" .
5801			    join(" ", @{$started_opts}) . "'" );
5802	$tinfo->{master_restart}= 1 if $is_master;
5803	return 1;
5804      }
5805
5806      mtr_verbose(My::Options::toStr("started_opts", @$started_opts));
5807      mtr_verbose(My::Options::toStr("extra_opts", @$extra_opts));
5808
5809      # Get diff and check if dynamic switch is possible
5810      my @diff_opts= My::Options::diff($started_opts, $extra_opts);
5811      mtr_verbose(My::Options::toStr("diff_opts", @diff_opts));
5812
5813      my $query= My::Options::toSQL(@diff_opts);
5814      mtr_verbose("Attempting dynamic switch '$query'");
5815      if (run_query($tinfo, $server, $query)){
5816	mtr_verbose("Restart: running with different options '" .
5817		    join(" ", @{$extra_opts}) . "' != '" .
5818		    join(" ", @{$started_opts}) . "'" );
5819	$tinfo->{master_restart}= 1 if $is_master;
5820	return 1;
5821      }
5822
5823      # Remember the dynamically set options
5824      $server->{'started_opts'}= $extra_opts;
5825    }
5826  }
5827
5828  if ($server->option("#!use-slave-opt") && $tinfo->{master_restart}) {
5829    mtr_verbose_restart($server, "master will be restarted");
5830    return 1;
5831  }
5832
5833  # Default, no restart
5834  return 0;
5835}
5836
5837
5838sub servers_need_restart($) {
5839  my ($tinfo)= @_;
5840  return grep { server_need_restart($tinfo, $_); } all_servers();
5841}
5842
5843
5844
5845#
5846# Return list of specific servers
5847#  - there is no servers in an empty config
5848#
5849sub _like   { return $config ? $config->like($_[0]) : (); }
5850sub mysqlds { return _like('mysqld.'); }
5851sub ndbds   { return _like('cluster_config.ndbd.');}
5852sub ndb_mgmds { return _like('cluster_config.ndb_mgmd.'); }
5853sub clusters  { return _like('mysql_cluster.'); }
5854sub memcacheds { return _like('memcached.'); }
5855sub all_servers { return ( mysqlds(), ndb_mgmds(), ndbds(), memcacheds() ); }
5856
5857#
5858# Filter a list of servers and return only those that are part
5859# of the specified cluster
5860#
5861sub in_cluster {
5862  my ($cluster)= shift;
5863  # Return only processes for a specific cluster
5864  return grep { $_->suffix() eq $cluster->suffix() } @_;
5865}
5866
5867
5868
5869#
5870# Filter a list of servers and return the SafeProcess
5871# for only those that are started or stopped
5872#
5873sub started { return grep(defined $_, map($_->{proc}, @_));  }
5874sub stopped { return grep(!defined $_, map($_->{proc}, @_)); }
5875
5876
5877sub envsubst {
5878  my $string= shift;
5879# Check for the ? symbol in the var name and remove it.
5880  if ( $string =~ s/^\?// )
5881  {
5882    if ( ! defined $ENV{$string} )
5883    {
5884      return "";
5885    }
5886  }
5887  else
5888  {
5889    if ( ! defined $ENV{$string} )
5890    {
5891      mtr_error(".opt file references '$string' which is not set");
5892    }
5893  }
5894
5895  return $ENV{$string};
5896}
5897
5898
5899sub get_extra_opts {
5900  # No extra options if --user-args
5901  return \@opt_extra_mysqld_opt if $opt_user_args;
5902
5903  my ($mysqld, $tinfo)= @_;
5904
5905  my $opts=
5906    $mysqld->option("#!use-slave-opt") ?
5907      $tinfo->{slave_opt} : $tinfo->{master_opt};
5908
5909  # Expand environment variables
5910  foreach my $opt ( @$opts )
5911  {
5912    $opt =~ s/\$\{(\??\w+)\}/envsubst($1)/ge;
5913    $opt =~ s/\$(\??\w+)/envsubst($1)/ge;
5914  }
5915  return $opts;
5916}
5917
5918
5919sub stop_servers($$) {
5920  my ($tinfo, @servers)= @_;
5921
5922  # Remember if we restarted for this test case (count restarts)
5923  $tinfo->{'restarted'} = 1;
5924
5925  if ( join('|', @servers) eq join('|', all_servers()) )
5926  {
5927    # All servers are going down, use some kind of order to
5928    # avoid too many warnings in the log files
5929
5930    mtr_report("Restarting all servers");
5931
5932    # mysqld processes
5933    shutdown_processes($opt_shutdown_timeout,
5934                       started(mysqlds()));
5935
5936    # cluster processes
5937    shutdown_processes($opt_shutdown_timeout,
5938                       started(ndbds(), ndb_mgmds(), memcacheds()));
5939  }
5940  else
5941  {
5942    mtr_report("Restarting ", started(@servers));
5943
5944    # Stop only some servers
5945    shutdown_processes($opt_shutdown_timeout,
5946                       started(@servers));
5947  }
5948
5949  foreach my $server (@servers)
5950  {
5951    # Mark server as stopped
5952    $server->{proc}= undef;
5953
5954    # Forget history
5955    delete $server->{'started_tinfo'};
5956    delete $server->{'started_opts'};
5957    delete $server->{'started_cnf'};
5958  }
5959}
5960
5961
5962#
5963# start_servers
5964#
5965# Start servers not already started
5966#
5967# RETURN
5968#  0 OK
5969#  1 Start failed
5970#
5971sub start_servers($) {
5972  my ($tinfo)= @_;
5973
5974  # Make sure the safe_process also exits from now on
5975  # Could not be done before, as we don't want this for the bootstrap
5976  if ($opt_start_exit) {
5977    My::SafeProcess->start_exit();
5978  }
5979
5980  # Start clusters
5981  foreach my $cluster ( clusters() )
5982  {
5983    ndbcluster_start($cluster);
5984  }
5985
5986  # Start mysqlds
5987  foreach my $mysqld ( mysqlds() )
5988  {
5989    if ( $mysqld->{proc} )
5990    {
5991      # Already started
5992
5993      # Write start of testcase to log file
5994      mark_log($mysqld->value('#log-error'), $tinfo);
5995
5996      next;
5997    }
5998
5999    my $datadir= $mysqld->value('datadir');
6000    if ($opt_start_dirty)
6001    {
6002      # Don't delete anything if starting dirty
6003      ;
6004    }
6005    else
6006    {
6007
6008      my @options= ('log-bin', 'relay-log');
6009      foreach my $option_name ( @options )  {
6010	next unless $mysqld->option($option_name);
6011
6012	my $file_name= $mysqld->value($option_name);
6013	next unless
6014	  defined $file_name and
6015	    -e $file_name;
6016
6017	mtr_debug(" -removing '$file_name'");
6018	unlink($file_name) or die ("unable to remove file '$file_name'");
6019      }
6020
6021      if (-d $datadir ) {
6022	mtr_verbose(" - removing '$datadir'");
6023	rmtree($datadir);
6024      }
6025    }
6026
6027    my $mysqld_basedir= $mysqld->value('basedir');
6028    if ( $basedir eq $mysqld_basedir )
6029    {
6030      if (!$opt_start_dirty)	# If dirty, keep possibly grown system db
6031      {
6032        # Copy datadir from installed system db
6033        my $path= ($opt_parallel == 1) ? "$opt_vardir" : "$opt_vardir/..";
6034        my $install_db= "$path/install.db";
6035        copytree($install_db, $datadir) if -d $install_db;
6036        mtr_error("Failed to copy system db to '$datadir'")
6037          unless -d $datadir;
6038      }
6039    }
6040    else
6041    {
6042      mysql_install_db($mysqld); # For versional testing
6043
6044      mtr_error("Failed to install system db to '$datadir'")
6045	unless -d $datadir;
6046
6047    }
6048
6049    # Create the servers tmpdir
6050    my $tmpdir= $mysqld->value('tmpdir');
6051    mkpath($tmpdir) unless -d $tmpdir;
6052
6053    # Write start of testcase to log file
6054    mark_log($mysqld->value('#log-error'), $tinfo);
6055
6056    # Run <tname>-master.sh
6057    if ($mysqld->option('#!run-master-sh') and
6058       run_sh_script($tinfo->{master_sh}) )
6059    {
6060      $tinfo->{'comment'}= "Failed to execute '$tinfo->{master_sh}'";
6061      return 1;
6062    }
6063
6064    # Run <tname>-slave.sh
6065    if ($mysqld->option('#!run-slave-sh') and
6066	run_sh_script($tinfo->{slave_sh}))
6067    {
6068      $tinfo->{'comment'}= "Failed to execute '$tinfo->{slave_sh}'";
6069      return 1;
6070    }
6071
6072    if (!$opt_embedded_server)
6073    {
6074      my $extra_opts= get_extra_opts($mysqld, $tinfo);
6075      mysqld_start($mysqld,$extra_opts);
6076
6077      # Save this test case information, so next can examine it
6078      $mysqld->{'started_tinfo'}= $tinfo;
6079
6080      # Wait until server's uuid is generated. This avoids that master and
6081      # slave generate the same UUID sporadically.
6082      sleep_until_file_created("$datadir/auto.cnf", $opt_start_timeout,
6083                               $mysqld->{'proc'});
6084
6085    }
6086
6087  }
6088
6089  # Wait for clusters to start
6090  foreach my $cluster ( clusters() )
6091  {
6092    if (ndbcluster_wait_started($cluster, ""))
6093    {
6094      # failed to start
6095      $tinfo->{'comment'}= "Start of '".$cluster->name()."' cluster failed";
6096
6097      #
6098      # Dump cluster log files to log file to help analyze the
6099      # cause of the failed start
6100      #
6101      ndbcluster_dump($cluster);
6102
6103      return 1;
6104    }
6105  }
6106
6107  # Wait for mysqlds to start
6108  foreach my $mysqld ( mysqlds() )
6109  {
6110    next if !started($mysqld);
6111
6112    if (sleep_until_file_created($mysqld->value('pid-file'),
6113				 $opt_start_timeout,
6114				 $mysqld->{'proc'}) == 0) {
6115      $tinfo->{comment}=
6116	"Failed to start ".$mysqld->name();
6117
6118      my $logfile= $mysqld->value('#log-error');
6119      if ( defined $logfile and -f $logfile )
6120      {
6121        my @srv_lines= extract_server_log($logfile, $tinfo->{name});
6122	$tinfo->{logfile}= "Server log is:\n" . join ("", @srv_lines);
6123      }
6124      else
6125      {
6126	$tinfo->{logfile}= "Could not open server logfile: '$logfile'";
6127      }
6128      return 1;
6129    }
6130  }
6131
6132  # Start memcached(s) for each cluster
6133  foreach my $cluster ( clusters() )
6134  {
6135    next if !in_cluster($cluster, memcacheds());
6136
6137    # Load the memcache metadata into this cluster
6138    memcached_load_metadata($cluster);
6139
6140    # Start memcached(s)
6141    foreach my $memcached ( in_cluster($cluster, memcacheds()))
6142    {
6143      next if started($memcached);
6144      memcached_start($cluster, $memcached);
6145    }
6146  }
6147
6148  return 0;
6149}
6150
6151
6152#
6153# Run include/check-testcase.test
6154# Before a testcase, run in record mode and save result file to var/tmp
6155# After testcase, run and compare with the recorded file, they should be equal!
6156#
6157# RETURN VALUE
6158#  The newly started process
6159#
6160sub start_check_testcase ($$$) {
6161  my $tinfo=    shift;
6162  my $mode=     shift;
6163  my $mysqld=   shift;
6164
6165  my $name= "check-".$mysqld->name();
6166  # Replace dots in name with underscore to avoid that mysqltest
6167  # misinterpret's what the filename extension is :(
6168  $name=~ s/\./_/g;
6169
6170  my $args;
6171  mtr_init_args(\$args);
6172
6173  mtr_add_arg($args, "--defaults-file=%s", $path_config_file);
6174  mtr_add_arg($args, "--defaults-group-suffix=%s", $mysqld->after('mysqld'));
6175  mtr_add_arg($args, "--result-file=%s", "$opt_vardir/tmp/$name.result");
6176  mtr_add_arg($args, "--test-file=%s", "include/check-testcase.test");
6177  mtr_add_arg($args, "--verbose");
6178  mtr_add_arg($args, "--logdir=%s/tmp", $opt_vardir);
6179
6180  if ( $mode eq "before" )
6181  {
6182    mtr_add_arg($args, "--record");
6183  }
6184  my $errfile= "$opt_vardir/tmp/$name.err";
6185  my $proc= My::SafeProcess->new
6186    (
6187     name          => $name,
6188     path          => $exe_mysqltest,
6189     error         => $errfile,
6190     output        => $errfile,
6191     args          => \$args,
6192     user_data     => $errfile,
6193     verbose       => $opt_verbose,
6194    );
6195
6196  mtr_report("Started $proc");
6197  return $proc;
6198}
6199
6200
6201sub run_mysqltest ($) {
6202  my $proc= start_mysqltest(@_);
6203  $proc->wait();
6204}
6205
6206
6207sub start_mysqltest ($) {
6208  my ($tinfo)= @_;
6209  my $exe= $exe_mysqltest;
6210  my $args;
6211
6212  mark_time_used('admin');
6213
6214  mtr_init_args(\$args);
6215
6216  if ( $opt_strace_client )
6217  {
6218    $exe=  "strace";
6219    mtr_add_arg($args, "-o");
6220    mtr_add_arg($args, "%s/log/mysqltest.strace", $opt_vardir);
6221    mtr_add_arg($args, "-f");
6222    mtr_add_arg($args, "$exe_mysqltest");
6223  }
6224
6225  mtr_add_arg($args, "--defaults-file=%s", $path_config_file);
6226  mtr_add_arg($args, "--silent");
6227  mtr_add_arg($args, "--tmpdir=%s", $opt_tmpdir);
6228  mtr_add_arg($args, "--character-sets-dir=%s", $path_charsetsdir);
6229  mtr_add_arg($args, "--logdir=%s/log", $opt_vardir);
6230  if ($auth_plugin)
6231  {
6232    mtr_add_arg($args, "--plugin_dir=%s", dirname($auth_plugin));
6233  }
6234
6235  # Log line number and time  for each line in .test file
6236  mtr_add_arg($args, "--mark-progress")
6237    if $opt_mark_progress;
6238
6239  mtr_add_arg($args, "--database=test");
6240
6241  if ( $opt_ps_protocol )
6242  {
6243    mtr_add_arg($args, "--ps-protocol");
6244  }
6245
6246  if ( $opt_sp_protocol )
6247  {
6248    mtr_add_arg($args, "--sp-protocol");
6249  }
6250
6251  if ( $opt_explain_protocol )
6252  {
6253    mtr_add_arg($args, "--explain-protocol");
6254  }
6255
6256  if ( $opt_json_explain_protocol )
6257  {
6258    mtr_add_arg($args, "--json-explain-protocol");
6259  }
6260
6261  if ( $opt_view_protocol )
6262  {
6263    mtr_add_arg($args, "--view-protocol");
6264  }
6265
6266  if ( $opt_trace_protocol )
6267  {
6268    mtr_add_arg($args, "--opt-trace-protocol");
6269  }
6270
6271  if ( $opt_cursor_protocol )
6272  {
6273    mtr_add_arg($args, "--cursor-protocol");
6274  }
6275
6276
6277  mtr_add_arg($args, "--timer-file=%s/log/timer", $opt_vardir);
6278
6279  if ( $opt_compress )
6280  {
6281    mtr_add_arg($args, "--compress");
6282  }
6283
6284  if ( $opt_sleep )
6285  {
6286    mtr_add_arg($args, "--sleep=%d", $opt_sleep);
6287  }
6288
6289  if ( $opt_ssl )
6290  {
6291    # Turn on SSL for _all_ test cases if option --ssl was used
6292    mtr_add_arg($args, "--ssl");
6293  }
6294
6295  if ( $opt_max_connections ) {
6296    mtr_add_arg($args, "--max-connections=%d", $opt_max_connections);
6297  }
6298
6299  if ( $opt_embedded_server )
6300  {
6301
6302    # Get the args needed for the embedded server
6303    # and append them to args prefixed
6304    # with --sever-arg=
6305
6306    my $mysqld=  $config->group('embedded')
6307      or mtr_error("Could not get [embedded] section");
6308
6309    my $mysqld_args;
6310    mtr_init_args(\$mysqld_args);
6311    my $extra_opts= get_extra_opts($mysqld, $tinfo);
6312    mysqld_arguments($mysqld_args, $mysqld, $extra_opts);
6313    mtr_add_arg($args, "--server-arg=%s", $_) for @$mysqld_args;
6314  }
6315
6316  # ----------------------------------------------------------------------
6317  # export MYSQL_TEST variable containing <path>/mysqltest <args>
6318  # ----------------------------------------------------------------------
6319  $ENV{'MYSQL_TEST'}= mtr_args2str($exe_mysqltest, @$args);
6320
6321  # ----------------------------------------------------------------------
6322  # Add arguments that should not go into the MYSQL_TEST env var
6323  # ----------------------------------------------------------------------
6324  if ( $opt_valgrind_mysqltest )
6325  {
6326    # Prefix the Valgrind options to the argument list.
6327    # We do this here, since we do not want to Valgrind the nested invocations
6328    # of mysqltest; that would mess up the stderr output causing test failure.
6329    my @args_saved = @$args;
6330    mtr_init_args(\$args);
6331    valgrind_arguments($args, \$exe);
6332    mtr_add_arg($args, "%s", $_) for @args_saved;
6333  }
6334
6335  mtr_add_arg($args, "--test-file=%s", $tinfo->{'path'});
6336
6337  # Number of lines of resut to include in failure report
6338  mtr_add_arg($args, "--tail-lines=500");
6339
6340  if ( defined $tinfo->{'result_file'} ) {
6341    mtr_add_arg($args, "--result-file=%s", $tinfo->{'result_file'});
6342  }
6343
6344  client_debug_arg($args, "mysqltest");
6345
6346  if ( $opt_record )
6347  {
6348    mtr_add_arg($args, "--record");
6349
6350    # When recording to a non existing result file
6351    # the name of that file is in "record_file"
6352    if ( defined $tinfo->{'record_file'} ) {
6353      mtr_add_arg($args, "--result-file=%s", $tinfo->{record_file});
6354    }
6355  }
6356
6357  if ( $opt_client_gdb )
6358  {
6359    gdb_arguments(\$args, \$exe, "client");
6360  }
6361  elsif ( $opt_client_ddd )
6362  {
6363    ddd_arguments(\$args, \$exe, "client");
6364  }
6365  if ( $opt_client_dbx ) {
6366    dbx_arguments(\$args, \$exe, "client");
6367  }
6368  elsif ( $opt_client_debugger )
6369  {
6370    debugger_arguments(\$args, \$exe, "client");
6371  }
6372
6373  my $proc= My::SafeProcess->new
6374    (
6375     name          => "mysqltest",
6376     path          => $exe,
6377     args          => \$args,
6378     append        => 1,
6379     error         => $path_current_testlog,
6380     verbose       => $opt_verbose,
6381    );
6382  mtr_verbose("Started $proc");
6383  return $proc;
6384}
6385
6386sub create_debug_statement {
6387  my $run = shift;
6388  my $args= shift;
6389  my $input= shift;
6390  my @params_to_quote = ("--plugin_load=", "--plugin_load_add=");
6391
6392  # Put $args into a single string
6393  my $str= join(" ", @$$args);
6394  my $runline= $input ? "$run $str < $input" : "$run $str";
6395
6396  foreach my $param_to_quote (@params_to_quote) {
6397    # add quotes to escape ; in plugin_load option
6398    my $pos1 = index($runline, $param_to_quote);
6399    if ( $pos1 != -1 ) {
6400      my $pos2 = index($runline, " ",$pos1);
6401      substr($runline,$pos1+length($param_to_quote),0) = "\"";
6402      substr($runline,$pos2+1,0) = "\"";
6403    }
6404  }
6405
6406  return $runline;
6407}
6408
6409#
6410# Modify the exe and args so that program is run in gdb in xterm
6411#
6412sub gdb_arguments {
6413  my $args= shift;
6414  my $exe=  shift;
6415  my $type= shift;
6416  my $input= shift;
6417
6418  my $gdb_init_file= "$opt_vardir/tmp/gdbinit.$type";
6419
6420  # Remove the old gdbinit file
6421  unlink($gdb_init_file);
6422
6423  my $runline=create_debug_statement("run", $args,$input);
6424
6425  # write init file for mysqld or client
6426  mtr_tofile($gdb_init_file,
6427	     "break main\n" .
6428	     $runline);
6429
6430  if ( $opt_manual_gdb )
6431  {
6432     print "\nTo start gdb for $type, type in another window:\n";
6433     print "gdb -cd $glob_mysql_test_dir -x $gdb_init_file $$exe\n";
6434
6435     # Indicate the exe should not be started
6436     $$exe= undef;
6437     return;
6438  }
6439
6440  $$args= [];
6441
6442  my $term_exe;
6443  set_term_args($opt_mtr_term_args, $term_exe, $$args, $type);
6444
6445  if ( $exe_libtool )
6446  {
6447    mtr_add_arg($$args, $exe_libtool);
6448    mtr_add_arg($$args, "--mode=execute");
6449  }
6450
6451  mtr_add_arg($$args, "gdb");
6452  mtr_add_arg($$args, "-x");
6453  mtr_add_arg($$args, "$gdb_init_file");
6454  mtr_add_arg($$args, "$$exe");
6455
6456  $$exe= $term_exe;
6457}
6458
6459 #
6460# Modify the exe and args so that program is run in lldb
6461#
6462sub lldb_arguments {
6463  my $args= shift;
6464  my $exe= shift;
6465  my $type= shift;
6466  my $input= shift;
6467
6468  my $lldb_init_file= "$opt_vardir/tmp/lldbinit.$type";
6469  unlink($lldb_init_file);
6470
6471  my $lldb_start_file= "$opt_vardir/tmp/lldbstart.$type";
6472  unlink($lldb_start_file);
6473
6474  my $runline=create_debug_statement("process launch --", $args, $input);
6475
6476  # write init file for mysqld or client
6477  mtr_tofile($lldb_init_file,
6478	     "b main\n" .
6479	     $runline);
6480
6481  if ( $opt_manual_lldb )
6482  {
6483    print "\nTo start lldb for $type, type in another window:\n";
6484    print "cd $glob_mysql_test_dir && lldb -s $lldb_init_file $$exe\n";
6485
6486    # Indicate the exe should not be started
6487    $$exe= undef;
6488    return;
6489  }
6490
6491  $$args= [];
6492
6493  my $term_exe;
6494  set_term_args($opt_mtr_term_args, $term_exe, $$args, $type);
6495
6496  mtr_add_arg($$args, $opt_lldb_cmd);
6497  mtr_add_arg($$args, "-s");
6498  mtr_add_arg($$args, "$lldb_init_file");
6499  mtr_add_arg($$args, "$$exe");
6500
6501  $$exe= $term_exe;
6502}
6503
6504#
6505# Modify the exe and args so that program is run in ddd
6506#
6507sub ddd_arguments {
6508  my $args= shift;
6509  my $exe=  shift;
6510  my $type= shift;
6511  my $input= shift;
6512
6513  my $gdb_init_file= "$opt_vardir/tmp/gdbinit.$type";
6514
6515  # Remove the old gdbinit file
6516  unlink($gdb_init_file);
6517
6518  my $runline=create_debug_statement("run", $args,$input);
6519
6520  # write init file for mysqld or client
6521  mtr_tofile($gdb_init_file,
6522	     "file $$exe\n" .
6523	     "break main\n" .
6524	     $runline);
6525
6526  if ( $opt_manual_ddd )
6527  {
6528     print "\nTo start ddd for $type, type in another window:\n";
6529     print "ddd -cd $glob_mysql_test_dir -x $gdb_init_file $$exe\n";
6530
6531     # Indicate the exe should not be started
6532     $$exe= undef;
6533     return;
6534  }
6535
6536  my $save_exe= $$exe;
6537  $$args= [];
6538  if ( $exe_libtool )
6539  {
6540    $$exe= $exe_libtool;
6541    mtr_add_arg($$args, "--mode=execute");
6542    mtr_add_arg($$args, "ddd");
6543  }
6544  else
6545  {
6546    $$exe= "ddd";
6547  }
6548  mtr_add_arg($$args, "--command=$gdb_init_file");
6549  mtr_add_arg($$args, "$save_exe");
6550}
6551
6552
6553#
6554# Modify the exe and args so that program is run in dbx in xterm
6555#
6556sub dbx_arguments {
6557  my $args= shift;
6558  my $exe=  shift;
6559  my $type= shift;
6560  my $input= shift;
6561
6562  # Put $args into a single string
6563  my $str= join " ", @$$args;
6564  my $runline= $input ? "run $str < $input" : "run $str";
6565
6566  if ( $opt_manual_dbx ) {
6567    print "\nTo start dbx for $type, type in another window:\n";
6568    print "cd $glob_mysql_test_dir; dbx -c \"stop in main; " .
6569          "$runline\" $$exe\n";
6570
6571    # Indicate the exe should not be started
6572    $$exe= undef;
6573    return;
6574  }
6575
6576  $$args= [];
6577  mtr_add_arg($$args, "-title");
6578  mtr_add_arg($$args, "$type");
6579  mtr_add_arg($$args, "-e");
6580
6581  if ( $exe_libtool ) {
6582    mtr_add_arg($$args, $exe_libtool);
6583    mtr_add_arg($$args, "--mode=execute");
6584  }
6585
6586  mtr_add_arg($$args, "dbx");
6587  mtr_add_arg($$args, "-c");
6588  mtr_add_arg($$args, "stop in main; $runline");
6589  mtr_add_arg($$args, "$$exe");
6590
6591  $$exe= "xterm";
6592}
6593
6594
6595#
6596# Modify the exe and args so that program is run in the selected debugger
6597#
6598sub debugger_arguments {
6599  my $args= shift;
6600  my $exe=  shift;
6601  my $debugger= $opt_debugger || $opt_client_debugger;
6602
6603  if ( $debugger =~ /vcexpress|vc|devenv/ )
6604  {
6605    # vc[express] /debugexe exe arg1 .. argn
6606
6607    # Add name of the exe and /debugexe before args
6608    unshift(@$$args, "$$exe");
6609    unshift(@$$args, "/debugexe");
6610
6611    # Set exe to debuggername
6612    $$exe= $debugger;
6613
6614  }
6615  elsif ( $debugger =~ /windbg/ )
6616  {
6617    # windbg exe arg1 .. argn
6618
6619    # Add name of the exe before args
6620    unshift(@$$args, "$$exe");
6621
6622    # Set exe to debuggername
6623    $$exe= $debugger;
6624
6625  }
6626  else
6627  {
6628    mtr_error("Unknown argument \"$debugger\" passed to --debugger");
6629  }
6630}
6631
6632#
6633# Modify the exe and args so that program is run in strace
6634#
6635sub strace_server_arguments {
6636  my $args= shift;
6637  my $exe=  shift;
6638  my $type= shift;
6639
6640  mtr_add_arg($args, "-o");
6641  mtr_add_arg($args, "%s/log/%s.strace", $opt_vardir, $type);
6642  mtr_add_arg($args, "-f");
6643  mtr_add_arg($args, $$exe);
6644  $$exe= "strace";
6645}
6646
6647#
6648# Modify the exe and args so that program is run in valgrind
6649#
6650sub valgrind_arguments {
6651  my $args= shift;
6652  my $exe=  shift;
6653  my $report_prefix= shift;
6654
6655  if (my @tool_list= grep(/^--tool=(memcheck|callgrind|helgrind|massif)/, @valgrind_args))
6656  {
6657    # Get the value of the last specified --tool=<> argument to valgrind
6658    my ($tool_name)= $tool_list[-1] =~ /(memcheck|callgrind|helgrind|massif)$/;
6659    if ($tool_name=~ /memcheck/)
6660    {
6661      mtr_add_arg($args, "--leak-check=yes") ;
6662      # Support statically-linked malloc libraries and
6663      # dynamically-linked jemalloc
6664      mtr_add_arg($args, "--soname-synonyms=somalloc=NONE,somalloc=*jemalloc*");
6665    }
6666    else
6667    {
6668      $$exe=~ /.*[\/](.*)$/;
6669      my $report_prefix= defined $report_prefix ? $report_prefix : $1;
6670      mtr_add_arg($args, "--$tool_name-out-file=$opt_vardir/log/".
6671                         "$report_prefix"."_$tool_name.out.%%p");
6672    }
6673  }
6674
6675  # Add valgrind options, can be overriden by user
6676  mtr_add_arg($args, '%s', $_) for (@valgrind_args);
6677
6678  mtr_add_arg($args, $$exe);
6679
6680  $$exe= $opt_valgrind_path || "valgrind";
6681
6682  if ($exe_libtool)
6683  {
6684    # Add "libtool --mode-execute" before the test to execute
6685    # if running in valgrind(to avoid valgrinding bash)
6686    unshift(@$args, "--mode=execute", $$exe);
6687    $$exe= $exe_libtool;
6688  }
6689}
6690
6691#
6692# Search server logs for valgrind reports printed at mysqld termination
6693#
6694
6695sub valgrind_exit_reports() {
6696  my $aggregate= '';
6697
6698  foreach my $log_file (keys %mysqld_logs)
6699  {
6700    my @culprits= ();
6701    my $valgrind_rep= "";
6702    my $found_report= 0;
6703    my $err_in_report= 0;
6704    my $ignore_report= 0;
6705
6706    my $LOGF = IO::File->new($log_file)
6707      or mtr_error("Could not open file '$log_file' for reading: $!");
6708
6709    while ( my $line = <$LOGF> )
6710    {
6711      if ($line =~ /^CURRENT_TEST: (.+)$/)
6712      {
6713        my $testname= $1;
6714        # If we have a report, report it if needed and start new list of tests
6715        if ($found_report)
6716        {
6717          if ($err_in_report)
6718          {
6719            $aggregate.= "Valgrind report from $log_file after tests:\n";
6720            $aggregate.= "@culprits\n$valgrind_rep\n";
6721            $err_in_report= 0;
6722          }
6723          # Make ready to collect new report
6724          @culprits= ();
6725          $found_report= 0;
6726          $valgrind_rep= "";
6727        }
6728        push (@culprits, $testname);
6729        next;
6730      }
6731      # This line marks a report to be ignored
6732      $ignore_report=1 if $line =~ /VALGRIND_DO_QUICK_LEAK_CHECK/;
6733      # This line marks the start of a valgrind report
6734      $found_report= 1 if $line =~ /^==\d+== .* SUMMARY:/;
6735
6736      if ($ignore_report && $found_report) {
6737        $ignore_report= 0;
6738        $found_report= 0;
6739      }
6740
6741      if ($found_report) {
6742        $line=~ s/^==\d+== //;
6743        $valgrind_rep .= $line;
6744        $err_in_report= 1 if $line =~ /ERROR SUMMARY: [1-9]/;
6745        $err_in_report= 1 if $line =~ /definitely lost: [1-9]/;
6746        $err_in_report= 1 if $line =~ /possibly lost: [1-9]/;
6747        $err_in_report= 1 if $line =~ /still reachable: [1-9]/;
6748      }
6749
6750      $found_report= 1 if $line =~ / \[Note\] .*: Shutdown complete$/;
6751    }
6752
6753    $LOGF= undef;
6754
6755    if ($err_in_report) {
6756      $aggregate.= "Valgrind report from $log_file after tests:\n";
6757      $aggregate.= "@culprits\n$valgrind_rep\n";
6758    }
6759  }
6760
6761  return $aggregate;
6762}
6763
6764sub run_ctest() {
6765  my $olddir= getcwd();
6766  chdir ($bindir) or die ("Could not chdir to $bindir");
6767  my $tinfo;
6768  my $no_ctest= (IS_WINDOWS) ? 256 : -1;
6769  my $ctest_vs= "";
6770
6771  # Just ignore if not configured/built to run ctest
6772  if (! -f "CTestTestfile.cmake") {
6773    mtr_report("No unit tests found.");
6774    chdir($olddir);
6775    return;
6776  }
6777
6778  # Add vs-config option if needed
6779  $ctest_vs= "-C $opt_vs_config" if $opt_vs_config;
6780
6781  # Limit ctest execution time
6782  my $ctest_timeout= "--timeout @{[$opt_testcase_timeout * 60]}";
6783
6784  # Request Valgrind for unit tests if former was requested for other tests.
6785  my $ctest_memcheck= $opt_valgrind_mysqld ? ' -T memcheck' : '';
6786
6787  # Also silently ignore if we don't have ctest and didn't insist
6788  # Special override: also ignore in Pushbuild, some platforms may not have it
6789  # Now, run ctest and collect output
6790  $ENV{CTEST_OUTPUT_ON_FAILURE} = 1;
6791  my $ctest_out= `ctest $ctest_vs $ctest_timeout $ctest_memcheck 2>&1`;
6792  if ($? == $no_ctest && ($opt_ctest == -1 || defined $ENV{PB2WORKDIR})) {
6793    chdir($olddir);
6794    return;
6795  }
6796
6797  # Create minimalistic "test" for the reporting
6798  $tinfo = My::Test->new
6799    (
6800     name           => 'unit_tests',
6801    );
6802  # Set dummy worker id to align report with normal tests
6803  $tinfo->{worker} = 0 if $opt_parallel > 1;
6804
6805  my $ctfail= 0;		# Did ctest fail?
6806  if ($?) {
6807    $ctfail= 1;
6808    $tinfo->{result}= 'MTR_RES_FAILED';
6809    $tinfo->{comment}= "ctest failed with exit code $?, see result below";
6810    $ctest_out= "" unless $ctest_out;
6811  }
6812  my $ctfile= "$opt_vardir/ctest.log";
6813  my $ctres= 0;			# Did ctest produce report summary?
6814
6815  open (CTEST, " > $ctfile") or die ("Could not open output file $ctfile");
6816
6817  $ctest_report .= $ctest_out if $opt_ctest_report;
6818
6819  # Put ctest output in log file, while analyzing results
6820  for (split ('\n', $ctest_out)) {
6821    print CTEST "$_\n";
6822    if (/tests passed/) {
6823      $ctres= 1;
6824      $ctest_report .= "\nUnit tests: $_\n";
6825    }
6826    if ( /FAILED/ or /\(Failed\)/ ) {
6827      $ctfail= 1;
6828      $ctest_report .= "  $_\n";
6829    }
6830  }
6831  close CTEST;
6832
6833  # Set needed 'attributes' for test reporting
6834  $tinfo->{comment}.= "\nctest did not pruduce report summary" if ! $ctres;
6835  $tinfo->{result}= ($ctres && !$ctfail)
6836    ? 'MTR_RES_PASSED' : 'MTR_RES_FAILED';
6837  $ctest_report .= "Report from unit tests in $ctfile";
6838  $tinfo->{failures}= ($tinfo->{result} eq 'MTR_RES_FAILED');
6839
6840  $tinfo->{comment} .= "\n" . $ctest_out;
6841  mark_time_used('test');
6842  mtr_report_test($tinfo);
6843  chdir($olddir);
6844  mtr_report_test_subunit($tinfo);
6845  return $tinfo;
6846}
6847
6848#
6849# Usage
6850#
6851sub usage ($) {
6852  my ($message)= @_;
6853
6854  if ( $message )
6855  {
6856    print STDERR "$message\n";
6857  }
6858
6859  print <<HERE;
6860
6861$0 [ OPTIONS ] [ TESTCASE ]
6862
6863Options to control what engine/variation to run
6864
6865  embedded-server       Use the embedded server, i.e. no mysqld daemons
6866  ps-protocol           Use the binary protocol between client and server
6867  cursor-protocol       Use the cursor protocol between client and server
6868                        (implies --ps-protocol)
6869  view-protocol         Create a view to execute all non updating queries
6870  opt-trace-protocol    Print optimizer trace
6871  explain-protocol      Run 'EXPLAIN EXTENDED' on all SELECT, INSERT,
6872                        REPLACE, UPDATE and DELETE queries.
6873  json-explain-protocol Run 'EXPLAIN FORMAT=JSON' on all SELECT, INSERT,
6874                        REPLACE, UPDATE and DELETE queries.
6875  sp-protocol           Create a stored procedure to execute all queries
6876  compress              Use the compressed protocol between client and server
6877  ssl                   Use ssl protocol between client and server
6878  skip-ssl              Dont start server with support for ssl connections
6879  vs-config             Visual Studio configuration used to create executables
6880                        (default: MTR_VS_CONFIG environment variable)
6881
6882  defaults-file=<config template> Use fixed config template for all
6883                        tests
6884  defaults-extra-file=<config template> Extra config template to add to
6885                        all generated configs
6886  combination=<opt>     Use at least twice to run tests with specified
6887                        options to mysqld
6888  skip-combinations     Ignore combination file (or options)
6889
6890Options to control directories to use
6891  tmpdir=DIR            The directory where temporary files are stored
6892                        (default: ./var/tmp).
6893  vardir=DIR            The directory where files generated from the test run
6894                        is stored (default: ./var). Specifying a ramdisk or
6895                        tmpfs will speed up tests.
6896  mem                   Run testsuite in "memory" using tmpfs or ramdisk
6897                        Attempts to find a suitable location
6898                        using a builtin list of standard locations
6899                        for tmpfs (/dev/shm)
6900                        The option can also be set using environment
6901                        variable MTR_MEM=[DIR]
6902  clean-vardir          Clean vardir if tests were successful and if
6903                        running in "memory". Otherwise this option is ignored
6904  client-bindir=PATH    Path to the directory where client binaries are located
6905  client-libdir=PATH    Path to the directory where client libraries are located
6906
6907
6908Options to control what test suites or cases to run
6909
6910  force                 Continue to run the suite after failure
6911  with-ndbcluster-only  Run only tests that include "ndb" in the filename
6912  skip-ndb[cluster]     Skip all tests that need cluster. Default.
6913  include-ndb[cluster]  Enable all tests that need cluster
6914  do-test=PREFIX or REGEX
6915                        Run test cases which name are prefixed with PREFIX
6916                        or fulfills REGEX
6917  skip-test=PREFIX or REGEX
6918                        Skip test cases which name are prefixed with PREFIX
6919                        or fulfills REGEX
6920  start-from=PREFIX     Run test cases starting test prefixed with PREFIX where
6921                        prefix may be suite.testname or just testname
6922  suite[s]=NAME1,..,NAMEN
6923                        Collect tests in suites from the comma separated
6924                        list of suite names.
6925                        The default is: "$DEFAULT_SUITES"
6926  skip-rpl              Skip the replication test cases.
6927  big-test              Also run tests marked as "big"
6928  enable-disabled       Run also tests marked as disabled
6929  print-testcases       Don't run the tests but print details about all the
6930                        selected tests, in the order they would be run.
6931  skip-test-list=FILE   Skip the tests listed in FILE. Each line in the file
6932                        is an entry and should be formatted as:
6933                        <TESTNAME> : <COMMENT>
6934
6935Options that specify ports
6936
6937  mtr-port-base=#       Base for port numbers, ports from this number to
6938  port-base=#           number+9 are reserved. Should be divisible by 10;
6939                        if not it will be rounded down. May be set with
6940                        environment variable MTR_PORT_BASE. If this value is
6941                        set and is not "auto", it overrides build-thread.
6942  mtr-build-thread=#    Specify unique number to calculate port number(s) from.
6943  build-thread=#        Can be set in environment variable MTR_BUILD_THREAD.
6944                        Set  MTR_BUILD_THREAD="auto" to automatically aquire
6945                        a build thread id that is unique to current host
6946
6947Options for test case authoring
6948
6949  record TESTNAME       (Re)genereate the result file for TESTNAME
6950  check-testcases       Check testcases for sideeffects
6951  mark-progress         Log line number and elapsed time to <testname>.progress
6952
6953Options that pass on options (these may be repeated)
6954
6955  mysqld=ARGS           Specify additional arguments to "mysqld"
6956  mysqld-env=VAR=VAL    Specify additional environment settings for "mysqld"
6957
6958Options to run test on running server
6959
6960  extern option=value   Run only the tests against an already started server
6961                        the options to use for connection to the extern server
6962                        must be specified using name-value pair notation
6963                        For example:
6964                         ./$0 --extern socket=/tmp/mysqld.sock
6965
6966Options for debugging the product
6967
6968  boot-dbx              Start bootstrap server in dbx
6969  boot-ddd              Start bootstrap server in ddd
6970  boot-gdb              Start bootstrap server in gdb
6971  client-dbx            Start mysqltest client in dbx
6972  client-ddd            Start mysqltest client in ddd
6973  client-debugger=NAME  Start mysqltest in the selected debugger
6974  client-gdb            Start mysqltest client in gdb
6975  dbx                   Start the mysqld(s) in dbx
6976  ddd                   Start the mysqld(s) in ddd
6977  debug                 Dump trace output for all servers and client programs
6978  debug-common          Same as debug, but sets 'd' debug flags to
6979                        "query,info,error,enter,exit"; you need this if you
6980                        want both to see debug printouts and to use
6981                        DBUG_EXECUTE_IF.
6982  debug-server          Use debug version of server, but without turning on
6983                        tracing
6984  debugger=NAME         Start mysqld in the selected debugger
6985  gdb                   Start the mysqld(s) in gdb
6986  manual-debug          Let user manually start mysqld in debugger, before
6987                        running test(s)
6988  manual-gdb            Let user manually start mysqld in gdb, before running
6989                        test(s)
6990  manual-ddd            Let user manually start mysqld in ddd, before running
6991                        test(s)
6992  manual-dbx            Let user manually start mysqld in dbx, before running
6993                        test(s)
6994  lldb                  Start mysqld(s) in lldb
6995  manual-lldb           Let user manually start mysqld in lldb, before running
6996                        test(s)
6997  strace-client         Create strace output for mysqltest client,
6998  strace-server         Create strace output for mysqltest server,
6999  max-save-core         Limit the number of core files saved (to avoid filling
7000                        up disks for heavily crashing server). Defaults to
7001                        $opt_max_save_core, set to 0 for no limit. Set
7002                        it's default with MTR_MAX_SAVE_CORE
7003  max-save-datadir      Limit the number of datadir saved (to avoid filling
7004                        up disks for heavily crashing server). Defaults to
7005                        $opt_max_save_datadir, set to 0 for no limit. Set
7006                        it's default with MTR_MAX_SAVE_DATDIR
7007  max-test-fail         Limit the number of test failurs before aborting
7008                        the current test run. Defaults to
7009                        $opt_max_test_fail, set to 0 for no limit. Set
7010                        it's default with MTR_MAX_TEST_FAIL
7011
7012Environment variables controlling debugging parameters
7013
7014  MTR_TERM              Configures the terminal command to run the debugger.
7015                        Defaults to xterm, but most other visual terminals
7016                        can also be specified. Examples:
7017                        MTR_TERM="gnome-terminal --title %title% --wait -x"
7018                        MTR_TERM="urxwt -title %title% -e"
7019                        Note: older version of gnome-terminal did not support
7020                        --wait - those versions aren't compatible.
7021  MTR_LLDB              Configures the lldb executable when debugging with
7022                        lldb, the default is "lldb". This is useful for
7023                        using lldb on a non default path, or on distributions
7024                        with versioned lldb binaries. Example:
7025                        MTR_LLDB=lldb-8.0
7026
7027Options for valgrind
7028
7029  valgrind              Run the "mysqltest" and "mysqld" executables using
7030                        valgrind with default options
7031  valgrind-all          Synonym for --valgrind
7032  valgrind-mysqltest    Run the "mysqltest" and "mysql_client_test" executable
7033                        with valgrind
7034  valgrind-mysqld       Run the "mysqld" executable with valgrind
7035  valgrind-options=ARGS Deprecated, use --valgrind-option
7036  valgrind-option=ARGS  Option to give valgrind, replaces default option(s),
7037                        can be specified more then once
7038  valgrind-path=<EXE>   Path to the valgrind executable
7039  callgrind             Instruct valgrind to use callgrind
7040  helgrind              Instruct valgrind to use helgrind
7041
7042Misc options
7043  user=USER             User for connecting to mysqld(default: $opt_user)
7044  comment=STR           Write STR to the output
7045  timer                 Show test case execution time.
7046  verbose               More verbose output(use multiple times for even more)
7047  verbose-restart       Write when and why servers are restarted
7048  start                 Only initialize and start the servers, using the
7049                        startup settings for the first specified test case
7050                        Example:
7051                         $0 --start alias &
7052  start-and-exit        Same as --start, but mysql-test-run terminates and
7053                        leaves just the server running
7054  start-dirty           Only start the servers (without initialization) for
7055                        the first specified test case
7056  user-args             In combination with start* and no test name, drops
7057                        arguments to mysqld except those speficied with
7058                        --mysqld (if any)
7059  wait-all              If --start or --start-dirty option is used, wait for all
7060                        servers to exit before finishing the process
7061  fast                  Run as fast as possible, dont't wait for servers
7062                        to shutdown etc.
7063  force-restart         Always restart servers between tests
7064  parallel=N            Run tests in N parallel threads (default=1)
7065                        Use parallel=auto for auto-setting of N
7066  repeat=N              Run each test N number of times
7067  retry=N               Retry tests that fail N times, limit number of failures
7068                        to $opt_retry_failure
7069  retry-failure=N       Limit number of retries for a failed test
7070  reorder               Reorder tests to get fewer server restarts
7071  help                  Get this help text
7072
7073  testcase-timeout=MINUTES Max test case run time (default $opt_testcase_timeout)
7074  suite-timeout=MINUTES Max test suite run time (default $opt_suite_timeout)
7075  shutdown-timeout=SECONDS Max number of seconds to wait for server shutdown
7076                        before killing servers (default $opt_shutdown_timeout)
7077  warnings              Scan the log files for warnings. Use --nowarnings
7078                        to turn off.
7079
7080  sleep=SECONDS         Passed to mysqltest, will be used as fixed sleep time
7081  debug-sync-timeout=NUM Set default timeout for WAIT_FOR debug sync
7082                        actions. Disable facility with NUM=0.
7083  gcov                  Collect coverage information after the test.
7084                        The result is a gcov file per source and header file.
7085  gprof                 Collect profiling information using gprof.
7086  experimental=<file>   Refer to list of tests considered experimental;
7087                        failures will be marked exp-fail instead of fail.
7088  report-features       First run a "test" that reports mysql features
7089  timestamp             Print timestamp before each test report line
7090  timediff              With --timestamp, also print time passed since
7091                        *previous* test started
7092  max-connections=N     Max number of open connection to server in mysqltest
7093  default-myisam        Set default storage engine to MyISAM for non-innodb
7094                        tests. This is needed after switching default storage
7095                        engine to InnoDB.
7096  report-times          Report how much time has been spent on different
7097                        phases of test execution.
7098  nounit-tests          Do not run unit tests. Normally run if configured
7099                        and if not running named tests/suites
7100  unit-tests            Run unit tests even if they would otherwise not be run
7101  unit-tests-report     Include report of every test included in unit tests.
7102  stress=ARGS           Run stress test, providing options to
7103                        mysql-stress-test.pl. Options are separated by comma.
7104  junit-output=FILE     Output JUnit test summary XML to FILE.
7105  junit-package=NAME    Set the JUnit package name to NAME for this test run.
7106
7107Some options that control enabling a feature for normal test runs,
7108can be turned off by prepending 'no' to the option, e.g. --notimer.
7109This applies to reorder, timer, check-testcases and warnings.
7110
7111HERE
7112  exit(1);
7113
7114}
7115
7116sub list_options ($) {
7117  my $hash= shift;
7118
7119  for (keys %$hash) {
7120    s/([:=].*|[+!])$//;
7121    s/\|/\n--/g;
7122    print "--$_\n" unless /list-options/;
7123  }
7124
7125  exit(1);
7126}
7127
7128