mirror of
https://github.com/webmin/webmin.git
synced 2026-09-16 02:20:39 +01:00
174 lines
6.4 KiB
Perl
174 lines
6.4 KiB
Perl
#!/usr/bin/perl
|
|
# Unit tests for MySQL module binary logging helpers.
|
|
|
|
use strict;
|
|
use warnings;
|
|
no warnings 'once';
|
|
use Test::More;
|
|
use File::Basename qw(dirname);
|
|
use File::Spec;
|
|
use Cwd qw(abs_path);
|
|
|
|
BEGIN {
|
|
# mysql-lib.pl imports WebminCore and initializes module globals at
|
|
# load time. Stub only those load-time dependencies so its pure helpers
|
|
# can be tested without a Webmin installation.
|
|
$INC{'WebminCore.pm'} = 1;
|
|
$INC{'view-lib.pl'} = 1;
|
|
package WebminCore;
|
|
sub import
|
|
{
|
|
my $caller = caller;
|
|
no strict 'refs';
|
|
*{$caller.'::init_config'} = sub { };
|
|
*{$caller.'::get_module_acl'} = sub { return (); };
|
|
*{$caller.'::read_file_contents'} = sub { return "10.5.29-MariaDB\n"; };
|
|
*{$caller.'::compare_version_numbers'} = sub {
|
|
my ($left, $right) = @_;
|
|
my @left = split(/\./, $left);
|
|
my @right = split(/\./, $right);
|
|
my $count = @left > @right ? scalar(@left) : scalar(@right);
|
|
for(my $i = 0; $i < $count; $i++) {
|
|
my $cmp = ($left[$i] || 0) <=> ($right[$i] || 0);
|
|
return $cmp if ($cmp);
|
|
}
|
|
return 0;
|
|
};
|
|
*{$caller.'::has_command'} = sub { return $_[0]; };
|
|
*{$caller.'::quote_path'} = sub { return $_[0]; };
|
|
*{$caller.'::backquote_command'} = sub { return ''; };
|
|
}
|
|
}
|
|
|
|
my $root = abs_path(File::Spec->catdir(dirname(__FILE__), '..'));
|
|
chdir($root) or die "chdir($root): $!";
|
|
do './mysql/mysql-lib.pl' or die $@ || $!;
|
|
|
|
subtest 'binary log retention display round-trips exactly' => sub {
|
|
# The page shows seconds as days, and saving converts the shown days
|
|
# back with int(days * 86400 + 0.5), which must reproduce the exact
|
|
# stored seconds even for non-round values
|
|
foreach my $secs (0, 1, 43200, 86400, 100000, 123456789, 2592000,
|
|
4294967295) {
|
|
my $days = main::format_binlog_expire_days($secs);
|
|
like($days, qr/^\d+(\.\d+)?$/,
|
|
"$secs seconds display as plain decimal ($days)");
|
|
is(int($days * 86400 + 0.5), $secs,
|
|
"$secs seconds round-trip through $days days");
|
|
}
|
|
is(main::format_binlog_expire_days(43200), '0.5',
|
|
'half a day is shown without trailing zeros');
|
|
is(main::format_binlog_expire_days(2592000), '30',
|
|
'whole days are shown without a decimal point');
|
|
};
|
|
|
|
subtest 'default logging state considers variant, version and downtime' => sub {
|
|
no warnings 'redefine';
|
|
my $live;
|
|
local *main::get_remote_mysql_variant = sub {
|
|
return $live ? @$live : (-1);
|
|
};
|
|
|
|
$live = [ '8.0.36', 'mysql' ];
|
|
ok(main::get_binlog_default_on(),
|
|
'a running MySQL 8 logs by default');
|
|
$live = [ '5.7.44', 'mysql' ];
|
|
ok(!main::get_binlog_default_on(),
|
|
'a running MySQL 5.7 does not log by default');
|
|
$live = [ '10.11.6', 'mariadb' ];
|
|
ok(!main::get_binlog_default_on(),
|
|
'a running MariaDB does not log by default');
|
|
|
|
# When the server is stopped, the version cached at module setup
|
|
# time must be used instead
|
|
$live = undef;
|
|
local $main::mysql_version = '8.0.36';
|
|
ok(main::get_binlog_default_on(),
|
|
'a stopped MySQL 8 still counts as logging by default');
|
|
is_deeply([ main::get_mysql_variant_cached() ],
|
|
[ '8.0.36', 'mysql' ],
|
|
'a stopped MySQL 8 falls back to the cached version');
|
|
local $main::mysql_version = '10.5.29-MariaDB';
|
|
ok(!main::get_binlog_default_on(),
|
|
'a stopped MariaDB does not count as logging by default');
|
|
is_deeply([ main::get_mysql_variant_cached() ],
|
|
[ '10.5.29', 'mariadb' ],
|
|
'a stopped MariaDB falls back to the cached version');
|
|
};
|
|
|
|
subtest 'maximum log file size units and range' => sub {
|
|
is(main::parse_binlog_max_size(100, 'M'), 104857600,
|
|
'100 MB converts to bytes');
|
|
is(main::parse_binlog_max_size(4, 'K'), 4096,
|
|
'the 4 kB minimum is accepted');
|
|
is(main::parse_binlog_max_size(1, 'G'), 1073741824,
|
|
'the 1 GB maximum is accepted');
|
|
is(main::parse_binlog_max_size(8192, ''), 8192,
|
|
'plain bytes are accepted');
|
|
ok(!defined(main::parse_binlog_max_size(1, 'K')),
|
|
'below the 4 kB minimum is rejected');
|
|
ok(!defined(main::parse_binlog_max_size(2, 'G')),
|
|
'above the 1 GB maximum is rejected');
|
|
ok(!defined(main::parse_binlog_max_size('abc', 'M')),
|
|
'a non-numeric size is rejected');
|
|
ok(!defined(main::parse_binlog_max_size(100, 'T')),
|
|
'an unknown unit is rejected');
|
|
};
|
|
|
|
subtest 'rotation issues the expected statement' => sub {
|
|
no warnings 'redefine';
|
|
my @sql;
|
|
local *main::execute_sql_logged = sub { push(@sql, [ @_ ]); };
|
|
main::rotate_binary_logs();
|
|
is_deeply(\@sql, [ [ 'mysql', 'flush binary logs' ] ],
|
|
'rotation runs FLUSH BINARY LOGS on the master database');
|
|
};
|
|
|
|
subtest 'binary log retention limit covers the full 32-bit range' => sub {
|
|
# Saving validates the converted seconds against the variable's
|
|
# 32-bit maximum, so the displayed maximum must be accepted while
|
|
# anything above it is rejected
|
|
my $maxdays = main::format_binlog_expire_days(4294967295);
|
|
is($maxdays, '49710.269618', 'the 32-bit maximum displays in days');
|
|
is(main::parse_binlog_expire_days($maxdays), 4294967295,
|
|
'the displayed maximum converts back within the limit');
|
|
cmp_ok(main::parse_binlog_expire_days('49710.27'), '>', 4294967295,
|
|
'days just past the maximum exceed the seconds limit');
|
|
cmp_ok(main::parse_binlog_expire_days(49710), '<=', 4294967295,
|
|
'whole days below the maximum stay within the limit');
|
|
};
|
|
|
|
subtest 'retention maximum is variant specific' => sub {
|
|
is(main::get_binlog_expire_max('mysql'), 4294967295,
|
|
'MySQL accepts the full 32-bit seconds range');
|
|
is(main::get_binlog_expire_max('mariadb'), 8553600,
|
|
'MariaDB is limited to 99 days of seconds');
|
|
is(main::parse_binlog_expire_days(99),
|
|
main::get_binlog_expire_max('mariadb'),
|
|
'exactly 99 days is accepted on MariaDB');
|
|
cmp_ok(main::parse_binlog_expire_days('99.000012'), '>',
|
|
main::get_binlog_expire_max('mariadb'),
|
|
'just over 99 days exceeds the MariaDB limit');
|
|
is(main::format_binlog_expire_days(8553600), '99',
|
|
'the MariaDB maximum displays as 99 days');
|
|
};
|
|
|
|
subtest 'preferred MySQL server configuration section' => sub {
|
|
my $mariadb = { 'name' => 'mariadb' };
|
|
my $mariadbd = { 'name' => 'mariadbd' };
|
|
my $mysqld = { 'name' => 'mysqld' };
|
|
my $client = { 'name' => 'client' };
|
|
|
|
is(main::get_mysqld_config_section(
|
|
[ $mariadb, $mariadbd, $mysqld ]), $mysqld,
|
|
'mysqld is preferred regardless of file order');
|
|
is(main::get_mysqld_config_section([ $mariadb, $mariadbd ]), $mariadbd,
|
|
'mariadbd is preferred when mysqld is absent');
|
|
is(main::get_mysqld_config_section([ $client, $mariadb ]), $mariadb,
|
|
'mariadb is used as the final server-section fallback');
|
|
ok(!defined(main::get_mysqld_config_section([ $client ])),
|
|
'no server section returns undef');
|
|
};
|
|
|
|
done_testing();
|