Commit 9c8c572f authored by Sergei Golubchik's avatar Sergei Golubchik

per-file combinations

parent e06c1c70
...@@ -165,6 +165,8 @@ sub value { ...@@ -165,6 +165,8 @@ sub value {
} }
sub auto { 0 };
# #
# Return value for an option if it exist # Return value for an option if it exist
# #
...@@ -189,6 +191,8 @@ sub new { ...@@ -189,6 +191,8 @@ sub new {
bless My::Config::Group->new($group_name), $class; bless My::Config::Group->new($group_name), $class;
} }
sub auto { 1 };
# #
# Return value for an option in the group, fail if it does not exist # Return value for an option in the group, fail if it does not exist
# #
...@@ -214,6 +218,8 @@ use strict; ...@@ -214,6 +218,8 @@ use strict;
use warnings; use warnings;
use Carp; use Carp;
sub auto { 1 };
sub new { sub new {
my ($class, $group_name)= @_; my ($class, $group_name)= @_;
bless My::Config::Group->new($group_name), $class; bless My::Config::Group->new($group_name), $class;
......
...@@ -37,8 +37,8 @@ sub new { ...@@ -37,8 +37,8 @@ sub new {
sub fullname { sub fullname {
my ($self)= @_; my ($self)= @_;
$self->{name} . (defined $self->{combination} $self->{name} . (defined $self->{combinations}
? " '$self->{combination}'" ? " '" . join(',', sort @{$self->{combinations}}) . "'"
: "") : "")
} }
......
...@@ -213,6 +213,28 @@ sub split_testname { ...@@ -213,6 +213,28 @@ sub split_testname {
mtr_error("Illegal format of test name: $test_name"); mtr_error("Illegal format of test name: $test_name");
} }
sub combinations_from_file($)
{
my ($filename) = @_;
return () if @::opt_combinations or not -f $filename;
# Read combinations file in my.cnf format
mtr_verbose("Read combinations file");
my $config= My::Config->new($filename);
my @combs;
foreach my $group ($config->groups()) {
next if $group->auto();
my $comb= { name => $group->name() };
foreach my $option ( $group->options() ) {
push(@{$comb->{comb_opt}}, $option->option());
}
push @combs, $comb;
}
@combs;
}
my $suite_combinations = { };
my $file_combinations = { };
sub collect_one_suite sub collect_one_suite
{ {
...@@ -336,6 +358,30 @@ sub collect_one_suite ...@@ -336,6 +358,30 @@ sub collect_one_suite
} }
} }
# ----------------------------------------------------------------------
# Read combinations for this suite
# ----------------------------------------------------------------------
{
if (@::opt_combinations)
{
# take the combination from command-line
mtr_verbose("Take the combination from command line");
foreach my $combination (@::opt_combinations) {
my $comb= {};
$comb->{name}= $combination;
push(@{$comb->{comb_opt}}, $combination);
push @{$suite_combinations->{$suite}}, $comb;
}
}
else
{
my @combs = combinations_from_file("$suitedir/combinations");
my %env_filter = map { $_ => 1 } split /:/, $ENV{"\U${suite}_COMBINATIONS"};
@combs = grep $env_filter{$_->{name}}, @combs if %env_filter;
$suite_combinations->{$suite} = [ @combs ];
}
}
# Read suite.opt file # Read suite.opt file
my $suite_opts= [ opts_from_file("$testdir/suite.opt") ]; my $suite_opts= [ opts_from_file("$testdir/suite.opt") ];
$suite_opts = [ opts_from_file("$suitedir/suite.opt") ] unless @$suite_opts; $suite_opts = [ opts_from_file("$suitedir/suite.opt") ] unless @$suite_opts;
...@@ -387,99 +433,6 @@ sub collect_one_suite ...@@ -387,99 +433,6 @@ sub collect_one_suite
# Return empty list if no testcases found # Return empty list if no testcases found
return if (@cases == 0); return if (@cases == 0);
# ----------------------------------------------------------------------
# Read combinations for this suite and build testcases x combinations
# if any combinations exists
# ----------------------------------------------------------------------
{
my @combinations;
my $combination_file= "$suitedir/combinations";
#print "combination_file: $combination_file\n";
if (@::opt_combinations)
{
# take the combination from command-line
mtr_verbose("Take the combination from command line");
foreach my $combination (@::opt_combinations) {
my $comb= {};
$comb->{name}= $combination;
push(@{$comb->{comb_opt}}, $combination);
push(@combinations, $comb);
}
}
elsif (-f $combination_file )
{
# Read combinations file in my.cnf format
mtr_verbose("Read combinations file");
my %env_filter = map { $_ => 1 } split /:/, $ENV{"\U${suite}_COMBINATIONS"};
my $config= My::Config->new($combination_file);
foreach my $group ($config->groups()) {
my $comb= {};
$comb->{name}= $group->name();
next if %env_filter and not $env_filter{$comb->{name}};
foreach my $option ( $group->options() ) {
push(@{$comb->{comb_opt}}, $option->option());
}
push(@combinations, $comb) if $comb->{comb_opt};
}
}
if (@combinations)
{
print " - adding combinations for $suite\n";
my @new_cases;
TEST: foreach my $test (@cases)
{
if ( $test->{'skip'} )
{
push(@new_cases, $test);
next;
}
foreach my $comb (@combinations)
{
# Skip all other combinations if the values they change
# are already fixed in master_opt or slave_opt
if (My::Options::is_set($test->{master_opt}, $comb->{comb_opt}) &&
My::Options::is_set($test->{slave_opt}, $comb->{comb_opt}) ){
# Add combination name short name
$test->{combination}= $comb->{name};
# Add the test to new test cases list
push(@new_cases, $test);
next TEST;
}
}
foreach my $comb (@combinations)
{
# Copy test options
my $new_test= My::Test->new();
while (my ($key, $value) = each(%$test)) {
if (ref $value eq "ARRAY") {
push(@{$new_test->{$key}}, @$value);
} else {
$new_test->{$key}= $value;
}
}
# Append the combination options to master_opt and slave_opt
push(@{$new_test->{master_opt}}, @{$comb->{comb_opt}});
push(@{$new_test->{slave_opt}}, @{$comb->{comb_opt}});
# Add combination name short name
$new_test->{combination}= $comb->{name};
# Add the new test to new test cases list
push(@new_cases, $new_test);
}
}
@cases= @new_cases;
}
}
optimize_cases(\@cases); optimize_cases(\@cases);
return @cases; return @cases;
...@@ -504,52 +457,17 @@ sub optimize_cases { ...@@ -504,52 +457,17 @@ sub optimize_cases {
# Skip processing if already marked as skipped # Skip processing if already marked as skipped
next if $tinfo->{skip}; next if $tinfo->{skip};
# =======================================================
# If a special binlog format was selected with
# --mysqld=--binlog-format=x, skip all test that does not
# support it
# =======================================================
#print "binlog_format: $binlog_format\n";
if (not defined $binlog_format )
{
# =======================================================
# Use dynamic switching of binlog format
# =======================================================
# Get binlog-format used by this test from master_opt
my $test_binlog_format;
foreach my $opt ( @{$tinfo->{master_opt}} ) {
$test_binlog_format=
mtr_match_prefix($opt, "--binlog-format=") || $test_binlog_format;
}
if (defined $test_binlog_format and
defined $tinfo->{binlog_formats} )
{
my $supported=
grep { $_ eq $test_binlog_format } @{$tinfo->{'binlog_formats'}};
if ( !$supported )
{
$tinfo->{'skip'}= 1;
$tinfo->{'comment'}=
"Doesn't support --binlog-format='$test_binlog_format'";
# This test was added as a replication combination, but it is not
# actually ever possible to run it, as it is not made for this
# combination.
# So delete it from the list, rather than confuse the user with a
# message that this test is skipped (it is not really, just run
# with other combinations).
pop(@new_cases);
next;
}
}
}
# ======================================================= # =======================================================
# Check that engine selected by # Check that engine selected by
# --default-storage-engine=<engine> is supported # --default-storage-engine=<engine> is supported
# ======================================================= # =======================================================
my %builtin_engines = ('myisam' => 1, 'memory' => 1, 'csv' => 1);
#
# mandatory engines cannot be disabled with --skip-FOO.
# That is, --FOO switch does not exist, and mtr cannot detect
# if the engine is available.
#
my %mandatory_engines = ('myisam' => 1, 'memory' => 1, 'csv' => 1);
foreach my $opt ( @{$tinfo->{master_opt}} ) { foreach my $opt ( @{$tinfo->{master_opt}} ) {
my $default_engine= my $default_engine=
...@@ -567,7 +485,7 @@ sub optimize_cases { ...@@ -567,7 +485,7 @@ sub optimize_cases {
#print " - The mysqld_variables says '$engine_value'\n"; #print " - The mysqld_variables says '$engine_value'\n";
if ( ! exists $::mysqld_variables{$default_engine} and if ( ! exists $::mysqld_variables{$default_engine} and
! exists $builtin_engines{$default_engine} ) ! exists $mandatory_engines{$default_engine} )
{ {
$tinfo->{'skip'}= 1; $tinfo->{'skip'}= 1;
$tinfo->{'comment'}= $tinfo->{'comment'}=
...@@ -622,6 +540,52 @@ sub process_opts { ...@@ -622,6 +540,52 @@ sub process_opts {
} }
} }
sub make_combinations($@)
{
my ($test, @combinations) = @_;
return ($test) if $test->{'skip'} or not @combinations;
foreach my $comb (@combinations)
{
# Skip all other combinations if the values they change
# are already fixed in master_opt or slave_opt
if (My::Options::is_set($test->{master_opt}, $comb->{comb_opt}) &&
My::Options::is_set($test->{slave_opt}, $comb->{comb_opt}) ){
# Add combination name short name
push @{$test->{combinations}}, $comb->{name};
return ($test);
}
}
my @cases;
foreach my $comb (@combinations)
{
# Copy test options
my $new_test= My::Test->new();
while (my ($key, $value) = each(%$test)) {
if (ref $value eq "ARRAY") {
push(@{$new_test->{$key}}, @$value);
} else {
$new_test->{$key}= $value;
}
}
# Append the combination options to master_opt and slave_opt
push(@{$new_test->{master_opt}}, @{$comb->{comb_opt}});
push(@{$new_test->{slave_opt}}, @{$comb->{comb_opt}});
# Add combination name short name
push @{$new_test->{combinations}}, $comb->{name};
# Add the new test to new test cases list
push(@cases, $new_test);
}
return @cases;
}
############################################################################## ##############################################################################
# #
...@@ -764,8 +728,9 @@ sub collect_one_test_case { ...@@ -764,8 +728,9 @@ sub collect_one_test_case {
} }
} }
my $filename = "$testdir/${tname}.test";
my ($master_opts, $slave_opts)= my ($master_opts, $slave_opts)=
tags_from_test_file($tinfo, "$testdir/${tname}.test", $suitedir); tags_from_test_file($tinfo, $filename, $suitedir);
# Get default storage engine from suite.opt file # Get default storage engine from suite.opt file
...@@ -900,7 +865,13 @@ sub collect_one_test_case { ...@@ -900,7 +865,13 @@ sub collect_one_test_case {
process_opts($tinfo, 'master_opt'); process_opts($tinfo, 'master_opt');
process_opts($tinfo, 'slave_opt'); process_opts($tinfo, 'slave_opt');
return $tinfo; my @cases = ($tinfo);
for my $comb ($suite_combinations->{$suitename},
@{$file_combinations->{$filename}})
{
@cases = map make_combinations($_, @{$comb}), @cases;
}
return @cases;
} }
...@@ -927,14 +898,10 @@ my $file_to_slave_opts= { }; ...@@ -927,14 +898,10 @@ my $file_to_slave_opts= { };
# cached result. # cached result.
# We need to be a bit careful about speed here; previous version of this code # We need to be a bit careful about speed here; previous version of this code
# took forever to scan the full test suite. # took forever to scan the full test suite.
sub get_tags_from_file { sub get_tags_from_file($$) {
my ($file, $suitedir)= @_; my ($file, $suitedir)= @_;
return ([], [], []) unless -f $file; return @{$file_to_tags->{$file}} if exists $file_to_tags->{$file};
return ($file_to_tags->{$file}, $file_to_master_opts->{$file},
$file_to_slave_opts->{$file})
if exists($file_to_tags->{$file});
my $F= IO::File->new($file) my $F= IO::File->new($file)
or mtr_error("can't open file \"$file\": $!"); or mtr_error("can't open file \"$file\": $!");
...@@ -942,6 +909,7 @@ sub get_tags_from_file { ...@@ -942,6 +909,7 @@ sub get_tags_from_file {
my $tags= []; my $tags= [];
my $master_opts= []; my $master_opts= [];
my $slave_opts= []; my $slave_opts= [];
my @combinations;
while (my $line= <$F>) while (my $line= <$F>)
{ {
...@@ -972,11 +940,10 @@ sub get_tags_from_file { ...@@ -972,11 +940,10 @@ sub get_tags_from_file {
{ {
if (-e $sourced_file) if (-e $sourced_file)
{ {
my ($sub_tags, $sub_master_opts, $sub_slave_opts)= push @$tags, get_tags_from_file($sourced_file, $suitedir);
get_tags_from_file($sourced_file, $suitedir); push @$master_opts, @{$file_to_master_opts->{$sourced_file}};
push @$tags, @$sub_tags; push @$slave_opts, @{$file_to_slave_opts->{$sourced_file}};
push @$master_opts, @$sub_master_opts; push @combinations, @{$file_combinations->{$sourced_file}};
push @$slave_opts, @$sub_slave_opts;
last; last;
} }
} }
...@@ -992,22 +959,28 @@ sub get_tags_from_file { ...@@ -992,22 +959,28 @@ sub get_tags_from_file {
push @$master_opts, @common_opts, opts_from_file("$file_no_ext-master.opt"); push @$master_opts, @common_opts, opts_from_file("$file_no_ext-master.opt");
push @$slave_opts, @common_opts, opts_from_file("$file_no_ext-slave.opt"); push @$slave_opts, @common_opts, opts_from_file("$file_no_ext-slave.opt");
push @combinations, [ combinations_from_file("$file_no_ext.combinations") ];
# Save results so we can reuse without parsing if seen again. # Save results so we can reuse without parsing if seen again.
$file_to_tags->{$file}= $tags; $file_to_tags->{$file}= $tags;
$file_to_master_opts->{$file}= $master_opts; $file_to_master_opts->{$file}= $master_opts;
$file_to_slave_opts->{$file}= $slave_opts; $file_to_slave_opts->{$file}= $slave_opts;
return ($tags, $master_opts, $slave_opts); $file_combinations->{$file}= [ uniq(@combinations) ];
return @{$tags};
} }
sub tags_from_test_file { sub tags_from_test_file {
my ($tinfo, $file, $suitedir)= @_; my ($tinfo, $file, $suitedir)= @_;
my ($tags, $master_opts, $slave_opts)= get_tags_from_file($file, $suitedir); # a suite may generate tests that don't map to real *.test files
for (@$tags) # see unit suite for an example.
return ([], []) unless -f $file;
for (get_tags_from_file($file, $suitedir))
{ {
$tinfo->{$_->[0]}= $_->[1]; $tinfo->{$_->[0]}= $_->[1];
} }
return ($master_opts, $slave_opts); return ($file_to_master_opts->{$file}, $file_to_slave_opts->{$file});
} }
sub unspace { sub unspace {
......
...@@ -263,6 +263,11 @@ sub mtr_wait_lock_file { ...@@ -263,6 +263,11 @@ sub mtr_wait_lock_file {
return ($waited); return ($waited);
} }
sub uniq(@) {
my %seen = map { $_ => $_ } @_;
values %seen;
}
# Simple functions to start and check timers (have to be actively polled) # Simple functions to start and check timers (have to be actively polled)
# Timer can be "killed" by setting it to 0 # Timer can be "killed" by setting it to 0
......
...@@ -5101,8 +5101,8 @@ sub after_failure ($) { ...@@ -5101,8 +5101,8 @@ sub after_failure ($) {
my $save_dir= "$opt_vardir/log/"; my $save_dir= "$opt_vardir/log/";
$save_dir.= $tinfo->{name}; $save_dir.= $tinfo->{name};
# Add combination name if any # Add combination name if any
$save_dir.= "-$tinfo->{combination}" $save_dir.= '-' . join(',', sort @{$tinfo->{combinations}})
if defined $tinfo->{combination}; if defined $tinfo->{combinations};
# Save savedir path for server # Save savedir path for server
$tinfo->{savedir}= $save_dir; $tinfo->{savedir}= $save_dir;
......
...@@ -22,10 +22,10 @@ ...@@ -22,10 +22,10 @@
# http://dev.mysql.com/doc/refman/5.1/en/sql-syntax-data-definition.html # http://dev.mysql.com/doc/refman/5.1/en/sql-syntax-data-definition.html
# #
source include/master-slave.inc;
#CREATE TEMPORARY TABLE statements are not binlogged in row mode, #CREATE TEMPORARY TABLE statements are not binlogged in row mode,
#So it must be test by itself. #So it must be test by itself.
source include/have_binlog_format_mixed_or_statement.inc; source include/have_binlog_format_mixed_or_statement.inc;
source include/master-slave.inc;
disable_warnings; disable_warnings;
DROP DATABASE IF EXISTS mysqltest; DROP DATABASE IF EXISTS mysqltest;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment