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($$);
38
my ($from, $what)= @_;
39
if ( $from =~ /^[a-z0-9]$/ ) {
40
# Does not contain any regex, make the pattern match
44
# Check that pattern is a valid regex
45
eval { "" =~/$from/; 1 } or
46
mtr_error("Invalid regex '$from' passed to $what\nPerl says: $@");
51
sub collect_incomp_tests {
52
open (INCOMP, "lib/v1/incompatible.tests");
56
s/\s.*\n//; # Ignore anything from first white space
61
##############################################################################
63
# Collect information about test cases we are to run
65
##############################################################################
67
sub collect_test_cases ($) {
68
$do_test= init_pattern($::opt_do_test, "--do-test");
69
$skip_test= init_pattern($::opt_skip_test, "--skip-test");
71
collect_incomp_tests();
73
my $suites= shift; # Semicolon separated list of test suites
74
my $cases = []; # Array of hash
76
foreach my $suite (split(",", $suites))
78
push(@$cases, collect_one_suite($suite));
84
# Check that the tests specified was found
85
# in at least one suite
86
foreach my $test_name_spec ( @::opt_cases )
89
my ($sname, $tname, $extension)= split_testname($test_name_spec);
90
foreach my $test ( @$cases )
92
# test->{name} is always in suite.name format
93
if ( $test->{name} =~ /.*\.$tname/ )
100
mtr_error("Could not find $tname in any suite");
105
if ( $::opt_reorder )
107
# Reorder the test cases in an order that will make them faster to run
110
# Make a mapping of test name to a string that represents how that test
111
# should be sorted among the other tests. Put the most important criterion
112
# first, then a sub-criterion, then sub-sub-criterion, et c.
113
foreach my $tinfo (@$cases)
117
# Look for tests that muct be in run in a defined order
118
# that is defined by test having the same name except for
121
# Put variables into hash
122
my $test_name= $tinfo->{'name'};
123
my $depend_on_test_name;
124
if ( $test_name =~ /^([\D]+)([0-9]{1})$/ )
128
mtr_verbose("$test_name => $base_name idx=$idx");
132
$base_name= "$base_name$idx";
133
mtr_verbose("New basename $base_name");
136
foreach my $tinfo2 (@$cases)
138
if ( $tinfo2->{'name'} eq $base_name )
140
mtr_verbose("found dependent test $tinfo2->{'name'}");
141
$depend_on_test_name=$base_name;
146
if ( defined $depend_on_test_name )
148
mtr_verbose("Giving $test_name same critera as $depend_on_test_name");
149
$sort_criteria{$test_name} = $sort_criteria{$depend_on_test_name};
154
# Append the criteria for sorting, in order of importance.
156
push(@criteria, "ndb=" . ($tinfo->{'ndb_test'} ? "1" : "0"));
157
# Group test with equal options together.
158
# Ending with "~" makes empty sort later than filled
159
push(@criteria, join("!", sort @{$tinfo->{'master_opt'}}) . "~");
161
$sort_criteria{$test_name} = join(" ", @criteria);
166
$sort_criteria{$a->{'name'}} . $a->{'name'} cmp
167
$sort_criteria{$b->{'name'}} . $b->{'name'}; } @$cases;
169
if ( $::opt_script_debug )
171
# For debugging the sort-order
172
foreach my $tinfo (@$cases)
174
print("$sort_criteria{$tinfo->{'name'}} -> \t$tinfo->{'name'}\n");
183
# Valid extensions and their corresonding component id
184
my %exts = ( 'test' => 'mysqld',
189
# Returns (suitename, testname, extension)
193
# Get rid of directory part and split name on .'s
194
my @parts= split(/\./, basename($test_name));
197
# Only testname given, ex: alias
198
return (undef , $parts[0], undef);
199
} elsif (@parts == 2) {
200
# Either testname.test or suite.testname given
201
# Ex. main.alias or alias.test
203
if (defined $exts{$parts[1]})
205
return (undef , $parts[0], $parts[1]);
209
return ($parts[0], $parts[1], undef);
212
} elsif (@parts == 3) {
213
# Fully specified suitename.testname.test
215
return ( $parts[0], $parts[1], $parts[2]);
218
mtr_error("Illegal format of test name: $test_name");
222
sub collect_one_suite($)
224
my $suite= shift; # Test suite name
225
my @cases; # Array of hash
227
mtr_verbose("Collecting: $suite");
229
my $suitedir= "$::glob_mysql_test_dir"; # Default
230
if ( $suite ne "main" )
232
$suitedir= mtr_path_exists("$suitedir/suite/$suite",
234
mtr_verbose("suitedir: $suitedir");
237
my $testdir= "$suitedir/t";
238
my $resdir= "$suitedir/r";
240
# ----------------------------------------------------------------------
241
# Build a hash of disabled testcases for this suite
242
# ----------------------------------------------------------------------
244
if ( open(DISABLED, "$testdir/disabled.def" ) )
249
if ( /^\s*(\S+)\s*:\s*(.*?)\s*$/ )
257
# Read suite.opt file
258
my $suite_opt_file= "$testdir/suite.opt";
260
if ( -f $suite_opt_file )
262
$suite_opts= mtr_get_opts_from_file($suite_opt_file);
267
# Collect in specified order
268
foreach my $test_name_spec ( @::opt_cases )
270
my ($sname, $tname, $extension)= split_testname($test_name_spec);
272
# The test name parts have now been defined
273
#print " suite_name: $sname\n";
274
#print " tname: $tname\n";
275
#print " extension: $extension\n";
277
# Check cirrect suite if suitename is defined
278
next if (defined $sname and $suite ne $sname);
281
if ( defined $extension )
283
my $full_name= "$testdir/$tname.$extension";
284
# Extension was specified, check if the test exists
285
if ( ! -f $full_name)
287
# This is only an error if suite was specified, otherwise it
288
# could exist in another suite
289
mtr_error("Test '$full_name' was not found in suite '$sname'")
294
$component_id= $exts{$extension};
298
# No extension was specified
299
my ($ext, $component);
300
while (($ext, $component)= each %exts) {
301
my $full_name= "$testdir/$tname.$ext";
303
if ( ! -f $full_name ) {
306
$component_id= $component;
309
# Test not found here, could exist in other suite
310
next unless $component_id;
313
collect_one_test_case($testdir,$resdir,$suite,$tname,
314
"$tname.$extension",\@cases,\%disabled,
315
$component_id,$suite_opts);
320
opendir(TESTDIR, $testdir) or mtr_error("Can't open dir \"$testdir\": $!");
322
foreach my $elem ( sort readdir(TESTDIR) )
324
my $component_id= undef;
327
if ($tname= mtr_match_extension($elem, 'test'))
329
$component_id = 'mysqld';
331
elsif ($tname= mtr_match_extension($elem, 'imtest'))
333
$component_id = 'im';
340
# Skip tests that does not match the --do-test= filter
341
next if ($do_test and not $tname =~ /$do_test/o);
343
collect_one_test_case($testdir,$resdir,$suite,$tname,
344
$elem,\@cases,\%disabled,$component_id,
351
# Return empty list if no testcases found
352
return if (@cases == 0);
354
# ----------------------------------------------------------------------
355
# Read combinations for this suite and build testcases x combinations
356
# if any combinations exists
357
# ----------------------------------------------------------------------
358
if ( ! $::opt_skip_combination )
361
my $combination_file= "$suitedir/combinations";
362
#print "combination_file: $combination_file\n";
363
if (@::opt_combinations)
365
# take the combination from command-line
366
mtr_verbose("Take the combination from command line");
367
foreach my $combination (@::opt_combinations) {
369
$comb->{name}= $combination;
370
push(@{$comb->{comb_opt}}, $combination);
371
push(@combinations, $comb);
374
elsif (-f $combination_file )
376
# Read combinations file in my.cnf format
377
mtr_verbose("Read combinations file");
378
my $config= My::Config->new($combination_file);
380
foreach my $group ($config->groups()) {
382
$comb->{name}= $group->name();
383
foreach my $option ( $group->options() ) {
384
push(@{$comb->{comb_opt}}, "--".$option->name()."=".$option->value());
386
push(@combinations, $comb);
392
print " - adding combinations\n";
393
#print_testcases(@cases);
396
foreach my $comb (@combinations)
398
foreach my $test (@cases)
400
#print $test->{name}, " ", $comb, "\n";
403
while (my ($key, $value) = each(%$test)) {
404
if (ref $value eq "ARRAY") {
405
push(@{$new_test->{$key}}, @$value);
407
$new_test->{$key}= $value;
411
# Append the combination options to master_opt and slave_opt
412
push(@{$new_test->{master_opt}}, @{$comb->{comb_opt}});
413
push(@{$new_test->{slave_opt}}, @{$comb->{comb_opt}});
415
# Add combination name shrt name
416
$new_test->{combination}= $comb->{name};
418
# Add the new test to new test cases list
419
push(@new_cases, $new_test);
422
#print_testcases(@new_cases);
424
#print_testcases(@cases);
428
optimize_cases(\@cases);
429
#print_testcases(@cases);
436
# Loop through all test cases
437
# - optimize which test to run by skipping unnecessary ones
438
# - update settings if necessary
443
foreach my $tinfo ( @$cases )
445
# Skip processing if already marked as skipped
446
next if $tinfo->{skip};
448
# =======================================================
449
# If a special binlog format was selected with
450
# --mysqld=--binlog-format=x, skip all test that does not
452
# =======================================================
453
#print "used_binlog_format: $::used_binlog_format\n";
454
if (defined $::used_binlog_format )
456
# =======================================================
457
# Fixed --binlog-format=x specified on command line
458
# =======================================================
459
if ( defined $tinfo->{'binlog_formats'} )
461
#print "binlog_formats: ". join(", ", @{$tinfo->{binlog_formats}})."\n";
463
# The test supports different binlog formats
464
# check if the selected one is ok
466
grep { $_ eq $::used_binlog_format } @{$tinfo->{'binlog_formats'}};
471
"Doesn't support --binlog-format='$::used_binlog_format'";
477
# =======================================================
478
# Use dynamic switching of binlog format
479
# =======================================================
481
# Get binlog-format used by this test from master_opt
482
my $test_binlog_format;
483
foreach my $opt ( @{$tinfo->{master_opt}} ) {
485
mtr_match_prefix($opt, "--binlog-format=") || $test_binlog_format;
488
if (defined $test_binlog_format and
489
defined $tinfo->{binlog_formats} )
492
grep { $_ eq $test_binlog_format } @{$tinfo->{'binlog_formats'}};
497
"Doesn't support --binlog-format='$test_binlog_format'";
507
##############################################################################
509
# Collect information about a single test case
511
##############################################################################
514
sub collect_one_test_case($$$$$$$$$) {
522
my $component_id= shift;
523
my $suite_opts= shift;
525
my $path= "$testdir/$elem";
527
# ----------------------------------------------------------------------
528
# Skip some tests silently
529
# ----------------------------------------------------------------------
531
if ( $::opt_start_from and $tname lt $::opt_start_from )
538
$tinfo->{'name'}= basename($suite) . ".$tname";
539
$tinfo->{'result_file'}= "$resdir/$tname.result";
540
$tinfo->{'component_id'} = $component_id;
541
push(@$cases, $tinfo);
543
# Remove "combinations" part of test name
544
my $test_base_name= $tinfo->{'name'};
545
$test_base_name=~ s/\s.*\n//;
547
if (exists ($incompatible{$test_base_name}))
550
$tinfo->{'comment'}= "Test cannot run in mtr v1";
554
# ----------------------------------------------------------------------
555
# Skip some tests but include in list, just mark them to skip
556
# ----------------------------------------------------------------------
558
if ( $skip_test and $tname =~ /$skip_test/o )
564
# ----------------------------------------------------------------------
565
# Collect information about test case
566
# ----------------------------------------------------------------------
568
$tinfo->{'path'}= $path;
569
$tinfo->{'timezone'}= "GMT-3"; # for UNIX_TIMESTAMP tests to work
571
$tinfo->{'slave_num'}= 0; # Default, no slave
572
$tinfo->{'master_num'}= 1; # Default, 1 master
573
if ( defined mtr_match_prefix($tname,"rpl") )
575
if ( $::opt_skip_rpl )
578
$tinfo->{'comment'}= "No replication tests(--skip-rpl)";
582
$tinfo->{'slave_num'}= 1; # Default for rpl* tests, use one slave
586
if ( defined mtr_match_prefix($tname,"federated") )
588
# Default, federated uses the first slave as it's federated database
589
$tinfo->{'slave_num'}= 1;
592
my $master_opt_file= "$testdir/$tname-master.opt";
593
my $slave_opt_file= "$testdir/$tname-slave.opt";
594
my $slave_mi_file= "$testdir/$tname.slave-mi";
595
my $master_sh= "$testdir/$tname-master.sh";
596
my $slave_sh= "$testdir/$tname-slave.sh";
597
my $disabled_file= "$testdir/$tname.disabled";
598
my $im_opt_file= "$testdir/$tname-im.opt";
600
$tinfo->{'master_opt'}= [];
601
$tinfo->{'slave_opt'}= [];
602
$tinfo->{'slave_mi'}= [];
606
foreach my $opt ( @$suite_opts )
609
push(@{$tinfo->{'master_opt'}}, $opt);
610
push(@{$tinfo->{'slave_opt'}}, $opt);
614
if ( -f $master_opt_file )
617
my $master_opt= mtr_get_opts_from_file($master_opt_file);
619
foreach my $opt ( @$master_opt )
623
# The opt file is used both to send special options to the mysqld
624
# as well as pass special test case specific options to this
627
$value= mtr_match_prefix($opt, "--timezone=");
628
if ( defined $value )
630
$tinfo->{'timezone'}= $value;
634
$value= mtr_match_prefix($opt, "--slave-num=");
635
if ( defined $value )
637
$tinfo->{'slave_num'}= $value;
641
$value= mtr_match_prefix($opt, "--result-file=");
642
if ( defined $value )
644
# Specifies the file mysqltest should compare
646
$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);
675
if ( -f $slave_opt_file )
677
my $slave_opt= mtr_get_opts_from_file($slave_opt_file);
679
foreach my $opt ( @$slave_opt )
681
# If we set default time zone, remove the one we have
682
my $value= mtr_match_prefix($opt, "--default-time-zone=");
683
$tinfo->{'slave_opt'}= [] if defined $value;
685
push(@{$tinfo->{'slave_opt'}}, @$slave_opt);
688
if ( -f $slave_mi_file )
690
$tinfo->{'slave_mi'}= mtr_get_opts_from_file($slave_mi_file);
695
if ( $::glob_win32_perl )
698
$tinfo->{'comment'}= "No tests with sh scripts on Windows";
703
$tinfo->{'master_sh'}= $master_sh;
709
if ( $::glob_win32_perl )
712
$tinfo->{'comment'}= "No tests with sh scripts on Windows";
717
$tinfo->{'slave_sh'}= $slave_sh;
721
if ( -f $im_opt_file )
723
$tinfo->{'im_opts'} = mtr_get_opts_from_file($im_opt_file);
727
$tinfo->{'im_opts'} = [];
730
# FIXME why this late?
731
my $marked_as_disabled= 0;
732
if ( $disabled->{$tname} )
734
$marked_as_disabled= 1;
735
$tinfo->{'comment'}= $disabled->{$tname};
738
if ( -f $disabled_file )
740
$marked_as_disabled= 1;
741
$tinfo->{'comment'}= mtr_fromfile($disabled_file);
744
# If test was marked as disabled, either opt_enable_disabled is off and then
745
# we skip this test, or it is on and then we run this test but warn
747
if ( $marked_as_disabled )
749
if ( $::opt_enable_disabled )
751
$tinfo->{'dont_skip_though_disabled'}= 1;
756
$tinfo->{'disable'}= 1; # Sub type of 'skip'
761
if ( $component_id eq 'im' )
763
if ( $::glob_use_embedded_server )
766
$tinfo->{'comment'}= "No IM with embedded server";
769
elsif ( $::opt_ps_protocol )
772
$tinfo->{'comment'}= "No IM with --ps-protocol";
775
elsif ( $::opt_skip_im )
778
$tinfo->{'comment'}= "No IM tests(--skip-im)";
784
mtr_options_from_test_file($tinfo,"$testdir/${tname}.test");
786
if ( defined $::used_default_engine )
788
# Different default engine is used
789
# tag test to require that engine
790
$tinfo->{'ndb_test'}= 1
791
if ( $::used_default_engine =~ /^ndb/i );
793
$tinfo->{'innodb_test'}= 1
794
if ( $::used_default_engine =~ /^innodb/i );
797
#enable federated for this test
798
if ($tinfo->{'federated_test'})
800
push(@{$tinfo->{'master_opt'}}, "--loose-federated");
801
push(@{$tinfo->{'slave_opt'}}, "--loose-federated");
804
if ( $tinfo->{'big_test'} and ! $::opt_big_test )
807
$tinfo->{'comment'}= "Test need 'big-test' option";
811
if ( $tinfo->{'ndb_extra'} and ! $::opt_ndb_extra_test )
814
$tinfo->{'comment'}= "Test need 'ndb_extra' option";
818
if ( $tinfo->{'require_manager'} )
821
$tinfo->{'comment'}= "Test need the _old_ manager(to be removed)";
825
if ( $tinfo->{'need_debug'} && ! $::debug_compiled_binaries )
828
$tinfo->{'comment'}= "Test need debug binaries";
832
if ( $tinfo->{'ndb_test'} )
835
if ( ! $::glob_ndbcluster_supported )
837
# Ndb is not supported, skip it
839
$tinfo->{'comment'}= "No ndbcluster support";
842
elsif ( $::opt_skip_ndbcluster )
844
# All ndb test's should be skipped
846
$tinfo->{'comment'}= "No ndbcluster tests(--skip-ndbcluster)";
849
# Ndb tests run with two mysqld masters
850
$tinfo->{'master_num'}= 2;
854
# This is not a ndb test
855
if ( $::opt_with_ndbcluster_only )
857
# Only the ndb test should be run, all other should be skipped
859
$tinfo->{'comment'}= "Only ndbcluster tests(--with-ndbcluster-only)";
864
if ( $tinfo->{'innodb_test'} )
866
# This is a test that need innodb
867
if ( $::mysqld_variables{'innodb'} eq "OFF" )
869
# innodb is not supported, skip it
871
$tinfo->{'comment'}= "No innodb support";
876
if ( $tinfo->{'need_binlog'} )
878
if (grep(/^--skip-log-bin/, @::opt_extra_mysqld_opt) )
881
$tinfo->{'comment'}= "Test need binlog";
887
if ( $::mysql_version_id >= 50100 )
889
# Test does not need binlog, add --skip-binlog to
890
# the options used when starting it
891
push(@{$tinfo->{'master_opt'}}, "--skip-log-bin");
899
# List of tags in the .test files that if found should set
900
# the specified value in "tinfo"
904
["include/have_binlog_format_row.inc", "binlog_formats", ["row"]],
905
["include/have_binlog_format_statement.inc", "binlog_formats", ["statement"]],
906
["include/have_binlog_format_mixed.inc", "binlog_formats", ["mixed"]],
907
["include/have_binlog_format_mixed_or_row.inc",
908
"binlog_formats", ["mixed", "row"]],
909
["include/have_binlog_format_mixed_or_statement.inc",
910
"binlog_formats", ["mixed", "statement"]],
911
["include/have_binlog_format_row_or_statement.inc",
912
"binlog_formats", ["row", "statement"]],
914
["include/have_innodb.inc", "innodb_test", 1],
915
["include/have_log_bin.inc", "need_binlog", 1],
916
["include/big_test.inc", "big_test", 1],
917
["include/have_debug.inc", "need_debug", 1],
918
["include/have_ndb.inc", "ndb_test", 1],
919
["include/have_multi_ndb.inc", "ndb_test", 1],
920
["include/have_ndb_extra.inc", "ndb_extra", 1],
921
["include/ndb_master-slave.inc", "ndb_test", 1],
922
["require_manager", "require_manager", 1],
923
["include/federated.inc", "federated_test", 1],
924
["include/have_federated_db.inc", "federated_test", 1],
927
sub mtr_options_from_test_file($$) {
930
#mtr_verbose("$file");
931
my $F= IO::File->new($file) or mtr_error("can't open file \"$file\": $!");
933
while ( my $line= <$F> )
936
# Skip line if it start's with #
937
next if ( $line =~ /^#/ );
939
# Match this line against tag in "tags" array
940
foreach my $tag (@tags)
942
if ( index($line, $tag->[0]) >= 0 )
944
# Tag matched, assign value to "tinfo"
945
$tinfo->{"$tag->[1]"}= $tag->[2];
949
# If test sources another file, open it as well
950
if ( $line =~ /^\-\-([[:space:]]*)source(.*)$/ or
951
$line =~ /^([[:space:]]*)source(.*);$/ )
954
$value =~ s/^\s+//; # Remove leading space
955
$value =~ s/[[:space:]]+$//; # Remove ending space
957
my $sourced_file= "$::glob_mysql_test_dir/$value";
958
if ( -f $sourced_file )
960
# Only source the file if it exists, we may get
961
# false positives in the regexes above if someone
962
# writes "source nnnn;" in a test case(such as mysqltest.test)
963
mtr_options_from_test_file($tinfo, $sourced_file);
970
sub print_testcases {
973
print "=" x 60, "\n";
974
foreach my $test (@cases){
975
print "[", $test->{name}, "]", "\n";
976
while ((my ($key, $value)) = each(%$test)) {
977
print " ", $key, "=";
978
if (ref $value eq "ARRAY") {
979
print join(", ", @$value);
987
print "=" x 60, "\n";