Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
f5e7f12
MDEV-30281 Comment cleanup for my_load_defaults()
midenok Jul 21, 2026
5b160ac
MDEV-30281 MTR: cut server error log and shutdown warnings
midenok Jul 20, 2026
13e231a
MDEV-30281 MTR conf: document My::ConfigFactory config file handling
midenok Jul 20, 2026
ead91a9
MDEV-30281 MTR conf: options from .cnf file
midenok Jul 21, 2026
127c8aa
MDEV-30281 MTR conf: report config file errors as file:line without c…
midenok Jul 21, 2026
11745b6
MDEV-30281 MTR conf: honor standard --defaults-* options
midenok Jul 21, 2026
29a4237
MDEV-30281 MTR conf: add --mtr-config-only (-M)
midenok Jul 28, 2026
a1a9cc2
MDEV-30281 MTR: allow excluding suites with --suites=!NAME
midenok Jul 22, 2026
099e15c
MDEV-30281 MTR: add --combination-select to run one combination
midenok Jul 23, 2026
1b10b34
MDEV-30281 MTR: add --list-combinations to list a test's combinations
midenok Jul 23, 2026
f6f2d64
MDEV-30281 MTR: add --strip-hints to omit crash-report hints
midenok Jul 24, 2026
6c26db4
MDEV-30281 MTR: add --strip-limits to omit the resource-limits table
midenok Jul 24, 2026
f0ade4a
MDEV-30281 MTR: add --strip-backtrace and the --strip-log alias
midenok Jul 24, 2026
27999f8
MDEV-30281 MTR: test --tail-log / --tail-warnings in suite/mtr
midenok Jul 21, 2026
638bd56
MDEV-30281 MTR: add --exec-rr / --exec-gdb to wrap every --exec
midenok Jul 27, 2026
d60fe43
MDEV-30281 MTR: speed up test collection by caching result-dir listings
midenok Jul 28, 2026
9772870
MDEV-30281 MTR: make the debugger terminal configurable
midenok Jul 28, 2026
6d381ea
MDEV-30281 MTR: add --exit-line to stop a test at a given line
midenok Jul 28, 2026
4a986b1
MDEV-30281 MTR: fix --server-arg typo in embedded-server comments
midenok Jul 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions client/mysqltest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,9 @@ static uint my_end_arg= 0;
/* Number of lines of the result to include in failure report */
static uint opt_tail_lines= 0;

/* Stop the test before the command at this line of the test file (0 = off) */
static uint opt_exit_line= 0;

static uint opt_connect_timeout= 0;
static uint opt_wait_for_pos_timeout= 0;
static const uint default_wait_for_pos_timeout= 300;
Expand Down Expand Up @@ -3775,6 +3778,58 @@ static int execute_in_background(char *cmd)
mysqltest command(s) like "remove_file" for that
*/

/*
Find where a wrapper command (e.g. "rr record", "gdb --args") must be
injected into an --exec command line. Leading shell environment-variable
assignments (NAME=VALUE ...) must stay in front of the wrapper so that the
wrapped tool - not the assignment word - is what gets traced/debugged.
Returns the byte offset of the first non-assignment token.
*/

static size_t exec_wrap_offset(const char *cmd)
{
const char *p= cmd;
for (;;)
{
const char *tok;
while (*p == ' ' || *p == '\t')
p++;
tok= p;
/* A leading token counts as an assignment only if it is NAME= */
if (!(my_isalpha(charset_info, (uchar) *p) || *p == '_'))
return (size_t) (tok - cmd);
while (my_isalnum(charset_info, (uchar) *p) || *p == '_')
p++;
if (*p != '=')
return (size_t) (tok - cmd);
/* Skip the VALUE up to unquoted whitespace, honouring quotes/backslash */
for (p++; *p && *p != ' ' && *p != '\t'; )
{
if (*p == '\'')
{
for (p++; *p && *p != '\''; p++)
;
if (*p)
p++;
}
else if (*p == '"')
{
for (p++; *p && *p != '"'; p++)
{
if (*p == '\\' && p[1])
p++;
}
if (*p)
p++;
}
else if (*p == '\\' && p[1])
p+= 2;
else
p++;
}
}
}

void do_exec(struct st_command *command)
{
int error;
Expand Down Expand Up @@ -3824,6 +3879,28 @@ void do_exec(struct st_command *command)
dynstr_append_mem(&ds_cmd, STRING_WITH_LEN(" 2>&1"));
}

/*
--exec-rr / --exec-gdb: mariadb-test-run.pl sets MYSQLTEST_EXEC_WRAP to a
wrapper command (e.g. "rr record") that every --exec is run under. It is
injected after any leading NAME=VALUE assignments so the tool is wrapped,
not the assignment.
*/
{
const char *wrap= getenv("MYSQLTEST_EXEC_WRAP");
if (wrap && *wrap)
{
size_t off= exec_wrap_offset(ds_cmd.str);
DYNAMIC_STRING ds_wrap;
init_dynamic_string(&ds_wrap, "", ds_cmd.length + 64, 256);
dynstr_append_mem(&ds_wrap, ds_cmd.str, off);
dynstr_append_mem(&ds_wrap, wrap, strlen(wrap));
dynstr_append_mem(&ds_wrap, STRING_WITH_LEN(" "));
dynstr_append_mem(&ds_wrap, ds_cmd.str + off, ds_cmd.length - off);
dynstr_set(&ds_cmd, ds_wrap.str);
dynstr_free(&ds_wrap);
}
}

DBUG_PRINT("info", ("Executing '%s' as '%s'",
command->first_argument, ds_cmd.str));

Expand Down Expand Up @@ -10060,6 +10137,11 @@ static struct my_option my_long_options[] =
{"debug-info", 0, "Print some debug info at exit.",
&debug_info_flag, &debug_info_flag,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"exit-line", 'l',
"Stop the test before executing the command at this line of the test "
"file, as if an --exit directive were placed there.",
&opt_exit_line, &opt_exit_line, 0,
GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"host", 'h', "Connect to host.", &opt_host, &opt_host, 0,
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"prologue", 0, "Include SQL before each test case.", &opt_prologue,
Expand Down Expand Up @@ -13099,6 +13181,19 @@ int main(int argc, char **argv)
{
my_bool ok_to_do;
int current_line_inc = 1, processed = 0;

/*
--exit-line: stop before the command at this line of the top-level test
file, exactly as if an --exit directive were placed there. Gated to the
main file so that line numbers of sourced files do not trigger it.
*/
if (opt_exit_line && cur_file == file_stack &&
start_lineno >= opt_exit_line)
{
abort_flag= 1;
break;
}

if (command->type == Q_UNKNOWN || command->type == Q_COMMENT_WITH_COMMAND)
get_command_type(command);

Expand Down
46 changes: 36 additions & 10 deletions mysql-test/lib/My/Config.pm
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ sub new {
My::Config::Group::OPT->new('OPT'),
] }, $class;
my $F= IO::File->new($path, "<")
or croak "Could not open '$path': $!";
or die "Can't open config file '$path': $!\n";

while ( my $line= <$F> ) {
chomp($line);
Expand All @@ -282,39 +282,65 @@ sub new {
# Magic #! comments
elsif ( $line =~ /^(#\!\S+)(?:\s*(.*?)\s*)?$/) {
my ($magic, $arg)= ($1, $2);
croak "Found magic comment '$magic' outside of group"
die "$path:$.: magic comment '$magic' outside of any group\n"
unless $group_name;

#print "$magic\n";
$self->insert($group_name, $magic, $arg);
}

# Empty lines
elsif ( $line =~ /^$/ ) {
# Empty lines (including whitespace-only)
elsif ( $line =~ /^\s*$/ ) {
# Skip empty lines
next;
}

# !includedir <dir> - include all .cnf files in the directory
elsif ( $line =~ /^\!includedir\s+(.*?)\s*$/ ) {
# Resolve relative to the including file first, like !include; fall back
# to the raw path only if that directory does not exist.
my $dir= dirname($path)."/".$1;
$dir= $1 unless -d $dir;

# A missing includedir is silently ignored, as libmariadb does
if ( opendir(my $dh, $dir) ) {
foreach my $name ( sort grep { /\.cnf$/ } readdir($dh) ) {
my $file= "$dir/$name";
# Skip subdirectories or symlinks named *.cnf, as libmariadb does,
# so a stray non-file entry does not turn into a hard open failure.
next unless -f $file;
$self->append(My::Config->new($file));
}
closedir($dh);
}
}

# !include <filename>
elsif ( $line =~ /^\!include\s*(.*?)\s*$/ ) {
elsif ( $line =~ /^\!include\s+(.*?)\s*$/ ) {
my $include_file_name= dirname($path)."/".$1;

# Check that the file exists relative to path of first config file
if (! -f $include_file_name){
# Try to include file relativ to current dir
$include_file_name= $1;
}
croak "The include file '$include_file_name' does not exist"
die "$path:$.: include file '$include_file_name' does not exist\n"
unless -f $include_file_name;

$self->append(My::Config->new($include_file_name));
}

# <option>
# Any other !directive is ignored
elsif ( $line =~ /^\!/ ) {
next;
}

# <option> (a leading '#' makes it a pseudo-option, e.g. #galera_port,
# used in .cnf templates as an addressable name - not a comment)
elsif ( $line =~ /^(#?[\w-]+)\s*$/ ) {
my $option= $1;

croak "Found option '$option' outside of group"
die "$path:$.: option '$option' outside of any group\n"
unless $group_name;

#print "$option\n";
Expand All @@ -326,7 +352,7 @@ sub new {
my $option= $1;
my $value= $2;

croak "Found option '$option=$value' outside of group"
die "$path:$.: option '$option=$value' outside of any group\n"
unless $group_name;

#print "$option=$value\n";
Expand All @@ -346,7 +372,7 @@ sub new {
$self->insert($group_name, $option, $value);
}
else {
croak "Unexpected line '$line' found in '$path'";
die "$path:$.: unexpected line '$line'\n";
}
}
undef $F; # Close the file
Expand Down
Loading