2
# Copyright (C) 2005-2006 MySQL AB
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; version 2 of the License.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
# This is a library file used by the Perl version of mysql-test-run,
18
# and is part of the translation of the Bourne shell script with the
27
sub collect_test_cases ($);
28
sub collect_one_suite ($);
29
sub collect_one_test_case ($$$$$$$$$);
31
sub mtr_options_from_test_file($$);
37
my ($from, $what)= @_;
38
if ( $from =~ /^[a-z0-9]$/ ) {
39
# Does not contain any regex, make the pattern match
43
# Check that pattern is a valid regex
44
eval { "" =~/$from/; 1 } or
45
mtr_error("Invalid regex '$from' passed to $what\nPerl says: $@");
51
##############################################################################
53
# Collect information about test cases we are to run
55
##############################################################################
57
sub collect_test_cases ($) {
58
$do_test= init_pattern($::opt_do_test, "--do-test");
59
$skip_test= init_pattern($::opt_skip_test, "--skip-test");
61
my $suites= shift; # Semicolon separated list of test suites
62
my $cases = []; # Array of hash
64
foreach my $suite (split(",", $suites))
66
push(@$cases, collect_one_suite($suite));
72
# Check that the tests specified was found
73
# in at least one suite
74
foreach my $test_name_spec ( @::opt_cases )
77
my ($sname, $tname, $extension)= split_testname($test_name_spec);
78
foreach my $test ( @$cases )
80
# test->{name} is always in suite.name format
81
if ( $test->{name} =~ /.*\.$tname/ )
88
mtr_error("Could not find $tname in any suite");
95
# Reorder the test cases in an order that will make them faster to run
98
# Make a mapping of test name to a string that represents how that test
99
# should be sorted among the other tests. Put the most important criterion
100
# first, then a sub-criterion, then sub-sub-criterion, et c.
101
foreach my $tinfo (@$cases)
105
# Look for tests that muct be in run in a defined order
106
# that is defined by test having the same name except for
109
# Put variables into hash
110
my $test_name= $tinfo->{'name'};
111
my $depend_on_test_name;
112
if ( $test_name =~ /^([\D]+)([0-9]{1})$/ )
116
mtr_verbose("$test_name => $base_name idx=$idx");
120
$base_name= "$base_name$idx";
121
mtr_verbose("New basename $base_name");
124
foreach my $tinfo2 (@$cases)
126
if ( $tinfo2->{'name'} eq $base_name )
128
mtr_verbose("found dependent test $tinfo2->{'name'}");
129
$depend_on_test_name=$base_name;
134
if ( defined $depend_on_test_name )
136
mtr_verbose("Giving $test_name same critera as $depend_on_test_name");
137
$sort_criteria{$test_name} = $sort_criteria{$depend_on_test_name};
142
# Append the criteria for sorting, in order of importance.
144
# Group test with equal options together.
145
# Ending with "~" makes empty sort later than filled
146
push(@criteria, join("!", sort @{$tinfo->{'master_opt'}}) . "~");
148
$sort_criteria{$test_name} = join(" ", @criteria);
153
$sort_criteria{$a->{'name'}} . $a->{'name'} cmp
154
$sort_criteria{$b->{'name'}} . $b->{'name'}; } @$cases;
156
if ( $::opt_script_debug )
158
# For debugging the sort-order
159
foreach my $tinfo (@$cases)
161
print("$sort_criteria{$tinfo->{'name'}} -> \t$tinfo->{'name'}\n");
170
# Valid extensions and their corresonding component id
171
my %exts = ( 'test' => 'mysqld',
176
# Returns (suitename, testname, extension)
180
# Get rid of directory part and split name on .'s
181
my @parts= split(/\./, basename($test_name));
184
# Only testname given, ex: alias
185
return (undef , $parts[0], undef);
186
} elsif (@parts == 2) {
187
# Either testname.test or suite.testname given
188
# Ex. main.alias or alias.test
190
if (defined $exts{$parts[1]})
192
return (undef , $parts[0], $parts[1]);
196
return ($parts[0], $parts[1], undef);
199
} elsif (@parts == 3) {
200
# Fully specified suitename.testname.test
202
return ( $parts[0], $parts[1], $parts[2]);
205
mtr_error("Illegal format of test name: $test_name");
209
sub collect_one_suite($)
211
my $suite= shift; # Test suite name
212
my @cases; # Array of hash
214
mtr_verbose("Collecting: $suite");
216
my $suitepath= "$::glob_suite_path";
217
my $suitedir= "$::glob_mysql_test_dir"; # Default
218
if ( $suite ne "main" )
220
$suitedir= mtr_path_exists(
221
"$suitepath/$suite/drizzle-tests",
222
"$suitepath/$suite/tests",
223
"$suitedir/suite/$suite",
225
mtr_verbose("suitedir: $suitedir");
228
my $testdir= "$suitedir/t";
229
my $resdir= "$suitedir/r";
231
# ----------------------------------------------------------------------
232
# Build a hash of disabled testcases for this suite
233
# ----------------------------------------------------------------------
235
if ( open(DISABLED, "$testdir/disabled.def" ) )
240
if ( /^\s*(\S+)\s*:\s*(.*?)\s*$/ )
248
# Read suite.opt file
249
my $suite_opt_file= "$testdir/suite.opt";
251
if ( -f $suite_opt_file )
253
$suite_opts= mtr_get_opts_from_file($suite_opt_file);
258
# Collect in specified order
259
foreach my $test_name_spec ( @::opt_cases )
261
my ($sname, $tname, $extension)= split_testname($test_name_spec);
263
# The test name parts have now been defined
264
#print " suite_name: $sname\n";
265
#print " tname: $tname\n";
266
#print " extension: $extension\n";
268
# Check cirrect suite if suitename is defined
269
next if (defined $sname and $suite ne $sname);
272
if ( defined $extension )
274
my $full_name= "$testdir/$tname.$extension";
275
# Extension was specified, check if the test exists
276
if ( ! -f $full_name)
278
# This is only an error if suite was specified, otherwise it
279
# could exist in another suite
280
mtr_error("Test '$full_name' was not found in suite '$sname'")
285
$component_id= $exts{$extension};
289
# No extension was specified
290
my ($ext, $component);
291
while (($ext, $component)= each %exts) {
292
my $full_name= "$testdir/$tname.$ext";
294
if ( ! -f $full_name ) {
297
$component_id= $component;
300
# Test not found here, could exist in other suite
301
next unless $component_id;
304
collect_one_test_case($testdir,$resdir,$suite,$tname,
305
"$tname.$extension",\@cases,\%disabled,
306
$component_id,$suite_opts);
311
opendir(TESTDIR, $testdir) or mtr_error("Can't open dir \"$testdir\": $!");
313
foreach my $elem ( sort readdir(TESTDIR) )
315
my $component_id= undef;
318
if ($tname= mtr_match_extension($elem, 'test'))
320
$component_id = 'mysqld';
322
elsif ($tname= mtr_match_extension($elem, 'imtest'))
324
$component_id = 'im';
331
# Skip tests that does not match the --do-test= filter
332
next if ($do_test and not $tname =~ /$do_test/o);
334
collect_one_test_case($testdir,$resdir,$suite,$tname,
335
$elem,\@cases,\%disabled,$component_id,
342
# Return empty list if no testcases found
343
return if (@cases == 0);
345
# ----------------------------------------------------------------------
346
# Read combinations for this suite and build testcases x combinations
347
# if any combinations exists
348
# ----------------------------------------------------------------------
349
if ( ! $::opt_skip_combination )
352
my $combination_file= "$suitedir/combinations";
353
#print "combination_file: $combination_file\n";
354
if (@::opt_combinations)
356
# take the combination from command-line
357
mtr_verbose("Take the combination from command line");
358
foreach my $combination (@::opt_combinations) {
360
$comb->{name}= $combination;
361
push(@{$comb->{comb_opt}}, $combination);
362
push(@combinations, $comb);
365
elsif (-f $combination_file )
367
# Read combinations file in my.cnf format
368
mtr_verbose("Read combinations file");
369
my $config= My::Config->new($combination_file);
371
foreach my $group ($config->groups()) {
373
$comb->{name}= $group->name();
374
foreach my $option ( $group->options() ) {
375
push(@{$comb->{comb_opt}}, $option->name()."=".$option->value());
377
push(@combinations, $comb);
383
print " - adding combinations\n";
384
#print_testcases(@cases);
387
foreach my $comb (@combinations)
389
foreach my $test (@cases)
391
#print $test->{name}, " ", $comb, "\n";
394
while (my ($key, $value) = each(%$test)) {
395
if (ref $value eq "ARRAY") {
396
push(@{$new_test->{$key}}, @$value);
398
$new_test->{$key}= $value;
402
# Append the combination options to master_opt and slave_opt
403
push(@{$new_test->{master_opt}}, @{$comb->{comb_opt}});
404
push(@{$new_test->{slave_opt}}, @{$comb->{comb_opt}});
406
# Add combination name shrt name
407
$new_test->{combination}= $comb->{name};
409
# Add the new test to new test cases list
410
push(@new_cases, $new_test);
413
#print_testcases(@new_cases);
415
#print_testcases(@cases);
419
optimize_cases(\@cases);
420
#print_testcases(@cases);
427
# Loop through all test cases
428
# - optimize which test to run by skipping unnecessary ones
429
# - update settings if necessary
434
foreach my $tinfo ( @$cases )
436
# Skip processing if already marked as skipped
437
next if $tinfo->{skip};
439
# Replication test needs an adjustment of binlog format
440
if (mtr_match_prefix($tinfo->{'name'}, "rpl"))
443
# =======================================================
444
# Get binlog-format used by this test from master_opt
445
# =======================================================
446
my $test_binlog_format;
447
foreach my $opt ( @{$tinfo->{master_opt}} ) {
448
$test_binlog_format= $test_binlog_format ||
449
mtr_match_prefix($opt, "--binlog-format=");
451
# print $tinfo->{name}." uses ".$test_binlog_format."\n";
453
# =======================================================
454
# If a special binlog format was selected with
455
# --mysqld=--binlog-format=x, skip all test with different
457
# =======================================================
458
if (defined $::used_binlog_format and
459
$test_binlog_format and
460
$::used_binlog_format ne $test_binlog_format)
463
$tinfo->{'comment'}= "Requires --binlog-format='$test_binlog_format'";
467
# =======================================================
468
# Check that testcase supports the designated binlog-format
469
# =======================================================
470
if ($test_binlog_format and defined $tinfo->{'sup_binlog_formats'} )
473
grep { $_ eq $test_binlog_format } @{$tinfo->{'sup_binlog_formats'}};
478
"Doesn't support --binlog-format='$test_binlog_format'";
483
# =======================================================
484
# Use dynamic switching of binlog-format if mtr started
485
# w/o --mysqld=--binlog-format=xxx and combinations.
486
# =======================================================
487
if (!defined $tinfo->{'combination'} and
488
!defined $::used_binlog_format)
490
$test_binlog_format= $tinfo->{'sup_binlog_formats'}->[0];
493
# Save binlog format for dynamic switching
494
$tinfo->{binlog_format}= $test_binlog_format;
500
##############################################################################
502
# Collect information about a single test case
504
##############################################################################
507
sub collect_one_test_case($$$$$$$$$) {
515
my $component_id= shift;
516
my $suite_opts= shift;
518
my $path= "$testdir/$elem";
520
# ----------------------------------------------------------------------
521
# Skip some tests silently
522
# ----------------------------------------------------------------------
524
if ( $::opt_start_from and $tname lt $::opt_start_from )
531
$tinfo->{'name'}= basename($suite) . ".$tname";
532
if ( -f "$resdir/$::opt_engine/$tname.result")
534
$tinfo->{'result_file'}= "$resdir/$::opt_engine/$tname.result";
538
$tinfo->{'result_file'}= "$resdir/$tname.result";
540
$tinfo->{'component_id'} = $component_id;
541
push(@$cases, $tinfo);
543
# ----------------------------------------------------------------------
544
# Skip some tests but include in list, just mark them to skip
545
# ----------------------------------------------------------------------
547
if ( $skip_test and $tname =~ /$skip_test/o )
553
# ----------------------------------------------------------------------
554
# Collect information about test case
555
# ----------------------------------------------------------------------
557
$tinfo->{'path'}= $path;
558
$tinfo->{'timezone'}= "GMT-3"; # for UNIX_TIMESTAMP tests to work
560
$tinfo->{'slave_num'}= 0; # Default, no slave
561
$tinfo->{'master_num'}= 1; # Default, 1 master
562
if ( defined mtr_match_prefix($tname,"rpl") )
564
if ( $::opt_skip_rpl )
567
$tinfo->{'comment'}= "No replication tests(--skip-rpl)";
571
$tinfo->{'slave_num'}= 1; # Default for rpl* tests, use one slave
575
if ( defined mtr_match_prefix($tname,"federated") )
577
# Default, federated uses the first slave as it's federated database
578
$tinfo->{'slave_num'}= 1;
581
my $global_master_opt_file= "$testdir/master.opt";
582
my $test_master_opt_file= "$testdir/$tname-master.opt";
583
my $slave_opt_file= "$testdir/$tname-slave.opt";
584
my $slave_mi_file= "$testdir/$tname.slave-mi";
585
my $master_sh= "$testdir/$tname-master.sh";
586
my $slave_sh= "$testdir/$tname-slave.sh";
587
my $disabled_file= "$testdir/$tname.disabled";
588
my $im_opt_file= "$testdir/$tname-im.opt";
590
$tinfo->{'master_opt'}= [];
591
$tinfo->{'slave_opt'}= [];
592
$tinfo->{'slave_mi'}= [];
596
foreach my $opt ( @$suite_opts )
599
push(@{$tinfo->{'master_opt'}}, $opt);
600
push(@{$tinfo->{'slave_opt'}}, $opt);
603
foreach my $master_opt_file ($global_master_opt_file, $test_master_opt_file)
606
if ( -f $master_opt_file )
609
my $master_opt= mtr_get_opts_from_file($master_opt_file);
611
foreach my $opt ( @$master_opt )
615
# The opt file is used both to send special options to the mysqld
616
# as well as pass special test case specific options to this
619
$value= mtr_match_prefix($opt, "--timezone=");
620
if ( defined $value )
622
$tinfo->{'timezone'}= $value;
626
$value= mtr_match_prefix($opt, "--slave-num=");
627
if ( defined $value )
629
$tinfo->{'slave_num'}= $value;
633
$value= mtr_match_prefix($opt, "--result-file=");
634
if ( defined $value )
636
# Specifies the file mysqltest should compare
638
if ( -f "r/$::opt_engine/$value.result")
640
$tinfo->{'result_file'}= "r/$::opt_engine/$value.result";
644
$tinfo->{'result_file'}= "r/$value.result";
650
# If we set default time zone, remove the one we have
651
$value= mtr_match_prefix($opt, "--default-time-zone=");
652
if ( defined $value )
654
# Set timezone for this test case to something different
655
$tinfo->{'timezone'}= "GMT-8";
656
# Fallthrough, add the --default-time-zone option
659
# The --restart option forces a restart even if no special
660
# option is set. If the options are the same as next testcase
661
# there is no need to restart after the testcase
663
if ( $opt eq "--force-restart" )
665
$tinfo->{'force_restart'}= 1;
669
# Ok, this was a real option, add it
670
push(@{$tinfo->{'master_opt'}}, $opt);
676
if ( -f $slave_opt_file )
678
my $slave_opt= mtr_get_opts_from_file($slave_opt_file);
680
foreach my $opt ( @$slave_opt )
682
# If we set default time zone, remove the one we have
683
my $value= mtr_match_prefix($opt, "--default-time-zone=");
684
$tinfo->{'slave_opt'}= [] if defined $value;
686
push(@{$tinfo->{'slave_opt'}}, @$slave_opt);
689
if ( -f $slave_mi_file )
691
$tinfo->{'slave_mi'}= mtr_get_opts_from_file($slave_mi_file);
696
if ( $::glob_win32_perl )
699
$tinfo->{'comment'}= "No tests with sh scripts on Windows";
704
$tinfo->{'master_sh'}= $master_sh;
710
if ( $::glob_win32_perl )
713
$tinfo->{'comment'}= "No tests with sh scripts on Windows";
718
$tinfo->{'slave_sh'}= $slave_sh;
722
if ( -f $im_opt_file )
724
$tinfo->{'im_opts'} = mtr_get_opts_from_file($im_opt_file);
728
$tinfo->{'im_opts'} = [];
731
# FIXME why this late?
732
my $marked_as_disabled= 0;
733
if ( $disabled->{$tname} )
735
$marked_as_disabled= 1;
736
$tinfo->{'comment'}= $disabled->{$tname};
739
if ( -f $disabled_file )
741
$marked_as_disabled= 1;
742
$tinfo->{'comment'}= mtr_fromfile($disabled_file);
745
# If test was marked as disabled, either opt_enable_disabled is off and then
746
# we skip this test, or it is on and then we run this test but warn
748
if ( $marked_as_disabled )
750
if ( $::opt_enable_disabled )
752
$tinfo->{'dont_skip_though_disabled'}= 1;
757
$tinfo->{'disable'}= 1; # Sub type of 'skip'
762
if ( $component_id eq 'im' )
764
if ( $::glob_use_embedded_server )
767
$tinfo->{'comment'}= "No IM with embedded server";
770
elsif ( $::opt_ps_protocol )
773
$tinfo->{'comment'}= "No IM with --ps-protocol";
776
elsif ( $::opt_skip_im )
779
$tinfo->{'comment'}= "No IM tests(--skip-im)";
785
mtr_options_from_test_file($tinfo,"$testdir/${tname}.test");
787
if ( defined $::used_default_engine )
789
# Different default engine is used
790
# tag test to require that engine
791
$tinfo->{'ndb_test'}= 1
792
if ( $::used_default_engine =~ /^ndb/i );
794
$tinfo->{'innodb_test'}= 1
795
if ( $::used_default_engine =~ /^innodb/i );
798
if ( $tinfo->{'ndb_extra'} and ! $::opt_ndb_extra_test )
801
$tinfo->{'comment'}= "Test need 'ndb_extra' option";
805
if ( $tinfo->{'require_manager'} )
808
$tinfo->{'comment'}= "Test need the _old_ manager(to be removed)";
812
if ( $tinfo->{'need_debug'} && ! $::debug_compiled_binaries )
815
$tinfo->{'comment'}= "Test need debug binaries";
822
# List of tags in the .test files that if found should set
823
# the specified value in "tinfo"
826
["include/have_innodb.inc", "innodb_test", 1],
827
["include/have_binlog_format_row.inc", "sup_binlog_formats", ["row"]],
828
["include/have_log_bin.inc", "need_binlog", 1],
829
["include/have_binlog_format_statement.inc",
830
"sup_binlog_formats", ["statement"]],
831
["include/have_binlog_format_mixed.inc", "sup_binlog_formats", ["mixed"]],
832
["include/have_binlog_format_mixed_or_row.inc",
833
"sup_binlog_formats", ["mixed","row"]],
834
["include/have_binlog_format_mixed_or_statement.inc",
835
"sup_binlog_formats", ["mixed","statement"]],
836
["include/have_binlog_format_row_or_statement.inc",
837
"sup_binlog_formats", ["row","statement"]],
838
["include/have_debug.inc", "need_debug", 1],
839
["require_manager", "require_manager", 1],
842
sub mtr_options_from_test_file($$) {
845
#mtr_verbose("$file");
846
my $F= IO::File->new($file) or mtr_error("can't open file \"$file\": $!");
848
while ( my $line= <$F> )
851
# Skip line if it start's with #
852
next if ( $line =~ /^#/ );
854
# Match this line against tag in "tags" array
855
foreach my $tag (@tags)
857
if ( index($line, $tag->[0]) >= 0 )
859
# Tag matched, assign value to "tinfo"
860
$tinfo->{"$tag->[1]"}= $tag->[2];
864
# If test sources another file, open it as well
865
if ( $line =~ /^\-\-([[:space:]]*)source(.*)$/ or
866
$line =~ /^([[:space:]]*)source(.*);$/ )
869
$value =~ s/^\s+//; # Remove leading space
870
$value =~ s/[[:space:]]+$//; # Remove ending space
872
my $sourced_file= "$::glob_mysql_test_dir/$value";
873
if ( -f $sourced_file )
875
# Only source the file if it exists, we may get
876
# false positives in the regexes above if someone
877
# writes "source nnnn;" in a test case(such as mysqltest.test)
878
mtr_options_from_test_file($tinfo, $sourced_file);
885
sub print_testcases {
888
print "=" x 60, "\n";
889
foreach my $test (@cases){
890
print "[", $test->{name}, "]", "\n";
891
while ((my ($key, $value)) = each(%$test)) {
892
print " ", $key, "=";
893
if (ref $value eq "ARRAY") {
894
print join(", ", @$value);
902
print "=" x 60, "\n";