{
$pid = $TEST_STATE->{exim_pid};
print "Tidyup: killing wait-mode daemon pid=$pid\n";
- system("sudo kill -SIGINT $pid");
+ system("sudo kill -INT $pid");
}
if (opendir(DIR, "spool"))
chomp($pid = <PID>);
close(PID);
print "Tidyup: killing daemon pid=$pid\n";
- system("sudo rm -f spool/$spool; sudo kill -SIGINT $pid");
+ system("sudo rm -f spool/$spool; sudo kill -INT $pid");
}
}
else
# Random local part in callout cache testing
s/myhost.test.ex-\d+-testing/myhost.test.ex-dddddddd-testing/;
+ s/the.local.host.name-\d+-testing/the.local.host.name-dddddddd-testing/;
# File descriptor numbers may vary
s/^writing data block fd=\d+/writing data block fd=dddd/;
s/\d\d-[A-Z][a-z]{2}-\d{4}\s\d\d:\d\d:\d\d/07-Mar-2000 12:21:52/g;
# Time on queue tolerance
- s/QT=1s/QT=0s/;
+ s/(QT|D)=1s/$1=0s/;
# Eximstats heading
s/Exim\sstatistics\sfrom\s\d{4}-\d\d-\d\d\s\d\d:\d\d:\d\d\sto\s
\d{4}-\d\d-\d\d\s\d\d:\d\d:\d\d/Exim statistics from <time> to <time>/x;
+ # Treat ECONNRESET the same as ECONNREFUSED. At least some systems give
+ # us the former on a new connection.
+ s/(could not connect to .*: Connection) reset by peer$/$1 refused/;
# ======== TLS certificate algorithms ========
# Test machines might have various different TLS library versions supporting
# different protocols; can't rely upon TLS 1.2's AES256-GCM-SHA384, so we
# treat the standard algorithms the same.
# So far, have seen:
+ # TLSv1:AES128-GCM-SHA256:128
# TLSv1:AES256-SHA:256
# TLSv1.1:AES256-SHA:256
# TLSv1.2:AES256-GCM-SHA384:256
# (and \b doesn't match between ' ' and '(' )
s/( (?: (?:\b|\s) [\(=] ) | \s )TLSv1\.[12]:/$1TLSv1:/xg;
+ s/\bAES128-GCM-SHA256:128\b/AES256-SHA:256/g;
+ s/\bAES128-GCM-SHA256\b/AES256-SHA/g;
s/\bAES256-GCM-SHA384\b/AES256-SHA/g;
s/\bDHE-RSA-AES256-SHA\b/AES256-SHA/g;
# (this new one is a generic channel-read error, but the testsuite
# only hits it in one place)
- s/TLS error on connection to \d{1,3}(.\d{1,3}){3} \[\d{1,3}(.\d{1,3}){3}\] \(gnutls_handshake\): Error in the pull function\./a TLS session is required for ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4], but an attempt to start TLS failed/g;
+ s/TLS error on connection \(gnutls_handshake\): Error in the pull function\./a TLS session is required but an attempt to start TLS failed/g;
# (replace old with new, hoping that old only happens in one situation)
s/TLS error on connection to \d{1,3}(.\d{1,3}){3} \[\d{1,3}(.\d{1,3}){3}\] \(gnutls_handshake\): A TLS packet with unexpected length was received./a TLS session is required for ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4], but an attempt to start TLS failed/g;
s/\buid=$parm_caller_uid\b/uid=CALLER_UID/g;
s/\bgid=$parm_caller_gid\b/gid=CALLER_GID/g;
- s/\bname=$parm_caller_gecos\b/name=CALLER_GECOS/g;
+ s/\bname="?$parm_caller_gecos"?/name=CALLER_GECOS/g;
# When looking at spool files with -Mvh, we will find not only the caller
# login, but also the uid and gid. It seems that $) in some Perls gives all
# ======== Other error numbers ========
s/errno=\d+/errno=dd/g;
+ # ======== System Error Messages ======
+ # depending on the underlaying file system the error message seems to differ
+ s/(?: is not a regular file)|(?: has too many links \(\d+\))/ not a regular file or too many links/;
# ======== Output from ls ========
# Different operating systems use different spacing on long output
s/this message = \d+\b/this message = sss/;
s/Size of headers = \d+/Size of headers = sss/;
s/sum=(?!0)\d+/sum=dddd/;
- s/(?<=sum=dddd )count=(?!0)\d+\b/count=dd/;
- s/(?<=sum=0 )count=(?!0)\d+\b/count=dd/;
+ s/(?<=sum=dddd )count=\d+\b/count=dd/;
+ s/(?<=sum=0 )count=\d+\b/count=dd/;
s/,S is \d+\b/,S is ddddd/;
s/\+0100,\d+;/+0100,ddd;/;
s/\(\d+ bytes written\)/(ddd bytes written)/;
# numbers, or handle specific bad conditions in different ways, leading to
# different wording in the error messages, so we cannot compare them.
- s/(TLS error on connection (?:from|to) .*? \(SSL_\w+\): error:)(.*)/$1 <<detail omitted>>/;
+ s/(TLS error on connection (?:from .* )?\(SSL_\w+\): error:)(.*)/$1 <<detail omitted>>/;
# ======== Maildir things ========
# timestamp output in maildir processing
# other output is fragile; perhaps the debug output should be revised instead.
s%(?<!sqlite)(?<!lsearch\*@)(?<!lsearch\*)(?<!lsearch)[0-?]TESTSUITE/aux-fixed/%0TESTSUITE/aux-fixed/%g;
+ # ==========================================================
+ # MIME boundaries in RFC3461 DSN messages
+ s/\d{8,10}-eximdsn-\d+/NNNNNNNNNN-eximdsn-MMMMMMMMMM/;
+
# ==========================================================
# Some munging is specific to the specific file types
next;
}
}
+
+ # openssl version variances
+ next if /^SSL info: unknown state/;
+ next if /^SSL info: SSLv2\/v3 write client hello A/;
+ next if /^SSL info: SSLv3 read server key exchange A/;
}
# ======== stderr ========
# As of Exim 4.74, we log when a setgid fails; because we invoke Exim
# with -be, privileges will have been dropped, so this will always
# be the case
- next if /^changing group to \d+ failed: Operation not permitted/;
+ next if /^changing group to \d+ failed: (Operation not permitted|Not owner)/;
# We might not keep this check; rather than change all the tests, just
# ignore it as long as it succeeds; then we only need to change the
@saved = ();
}
+ # Skip hosts_require_dane checks when the options
+ # are unset, because dane ain't always there.
+
+ next if /in\shosts_require_dane\?\sno\s\(option\sunset\)/x;
+
+ # Experimental_International
+ next if / in smtputf8_advertise_hosts\? no \(option unset\)/;
+
# Skip some lines that Exim puts out at the start of debugging output
# because they will be different in different binaries.
/^Fixed never_users:/ ||
/^Size of off_t:/
);
+
+
}
next;
}
+ # ======== log ========
+
+ elsif ($is_log)
+ {
+ # Berkeley DB version differences
+ next if / Berkeley DB error: /;
+ }
+
# ======== All files other than stderr ========
print MUNGED;
# paniclog, rejectlog, mainlog, stdout, stderr, msglog, mail
# Search strings starting with 's' do substitutions;
# with '/' do line-skips.
+# Triggered by a scriptfile line "munge <name>"
##################################################
$munges =
{ 'dnssec' =>
- { 'stderr' => '/^Reverse DNS security status: unverified\n/', },
+ { 'stderr' => '/^Reverse DNS security status: unverified\n/' },
'gnutls_unexpected' =>
- { 'mainlog' => '/\(recv\): A TLS packet with unexpected length was received./', },
+ { 'mainlog' => '/\(recv\): A TLS packet with unexpected length was received./' },
'gnutls_handshake' =>
- { 'mainlog' => 's/\(gnutls_handshake\): Error in the push function/\(gnutls_handshake\): A TLS packet with unexpected length was received/', },
+ { 'mainlog' => 's/\(gnutls_handshake\): Error in the push function/\(gnutls_handshake\): A TLS packet with unexpected length was received/' },
+
+ 'optional_events' =>
+ { 'stdout' => '/event_action =/' },
+
+ 'optional_ocsp' =>
+ { 'stderr' => '/127.0.0.1 in hosts_requ(ire|est)_ocsp/' },
+
+ 'no_tpt_filter_epipe' =>
+ { 'stderr' => '/^writing error 32: Broken pipe$/' },
+
+ 'optional_cert_hostnames' =>
+ { 'stderr' => '/in tls_verify_cert_hostnames\? no/' },
+
+ 'loopback' =>
+ { 'stdout' => 's/[[](127\.0\.0\.1|::1)]/[IP_LOOPBACK_ADDR]/' },
+
+ 'scanfile_size' =>
+ { 'stdout' => 's/(Content-length:) \d\d\d/$1 ddd/' },
};
# [4] TRUE if this is a log file whose deliveries must be sorted
# [5] an optional custom munge command
#
-# Arguments: Optionally, name of a custom munge to run.
+# Arguments: Optionally, name of a single custom munge to run.
# Returns: 0 if the output compared equal
# 1 if re-run needed (files may have been updated)
my(@temp);
print ">> ./eximdir/exim_dumpdb $parm_cwd/spool $which\n" if $debug;
open(IN, "./eximdir/exim_dumpdb $parm_cwd/spool $which |");
- @temp = <IN>;
- close(IN);
- if ($which eq "callout")
+ open(OUT, ">>test-stdout");
+ print OUT "+++++++++++++++++++++++++++\n";
+
+ if ($which eq "retry")
{
+ $/ = "\n ";
+ @temp = <IN>;
+ $/ = "\n";
+
@temp = sort {
- my($aa) = substr $a, 21;
- my($bb) = substr $b, 21;
- return $aa cmp $bb;
+ my($aa) = split(' ', $a);
+ my($bb) = split(' ', $b);
+ return $aa cmp $bb;
} @temp;
+
+ foreach $item (@temp)
+ {
+ $item =~ s/^\s*(.*)\n(.*)\n?\s*$/$1\n$2/m;
+ print OUT " $item\n";
+ }
}
- open(OUT, ">>test-stdout");
- print OUT "+++++++++++++++++++++++++++\n";
- print OUT @temp;
+ else
+ {
+ @temp = <IN>;
+ if ($which eq "callout")
+ {
+ @temp = sort {
+ my($aa) = substr $a, 21;
+ my($bb) = substr $b, 21;
+ return $aa cmp $bb;
+ } @temp;
+ }
+ print OUT @temp;
+ }
+
+ close(IN);
close(OUT);
return 1;
}
print ">> killdaemon: recovered pid $pid\n" if $debug;
if ($pid)
{
- run_system("sudo /bin/kill -SIGINT $pid");
+ run_system("sudo /bin/kill -INT $pid");
wait;
}
} else {
$pid = `cat $parm_cwd/spool/exim-daemon.*`;
if ($pid)
{
- run_system("sudo /bin/kill -SIGINT $pid");
+ run_system("sudo /bin/kill -INT $pid");
close DAEMONCMD; # Waits for process
}
}
for ($i = @msglist; $i > 0; $i--) { $args =~ s/\$msg$i/$msglist[$i-1]/g; }
if ( $args =~ /\$msg\d/ )
{
- tests_exit(-1, "Not enough messages in spool, for test $testno line $lineno\n");
+ tests_exit(-1, "Not enough messages in spool, for test $testno line $lineno\n")
+ unless $force_continue;
}
}
autoflush STDOUT 1;
print "Exim tester $testversion\n";
+# extend the PATH with .../sbin
+# we map all (.../bin) to (.../sbin:.../bin)
+$ENV{PATH} = do {
+ my %seen = map { $_, 1 } split /:/, $ENV{PATH};
+ join ':' => map { m{(.*)/bin$}
+ ? ( $seen{"$1/sbin"} ? () : ("$1/sbin"), $_)
+ : ($_) }
+ split /:/, $ENV{PATH};
+};
##################################################
# Some tests check created file modes #
print("Probing with config file: $parm_cwd/test-config\n");
open(EXIMINFO, "$parm_exim -d -C $parm_cwd/test-config -DDIR=$parm_cwd " .
- "-bP exim_user exim_group|") ||
+ "-bP exim_user exim_group 2>&1|") ||
die "** Cannot run $parm_exim: $!\n";
while(<EXIMINFO>)
{
$parm_eximuser = $1 if /^exim_user = (.*)$/;
$parm_eximgroup = $1 if /^exim_group = (.*)$/;
+ $parm_trusted_config_list = $1 if /^TRUSTED_CONFIG_LIST:.*?"(.*?)"$/;
}
close(EXIMINFO);
else { $parm_exim_gid = getgrnam($parm_eximgroup); }
}
+# check the permissions on the TRUSTED_CONFIG_LIST
+if (defined $parm_trusted_config_list)
+ {
+ die "TRUSTED_CONFIG_LIST: $parm_trusted_config_list: $!\n"
+ if not -f $parm_trusted_config_list;
+
+ die "TRUSTED_CONFIG_LIST $parm_trusted_config_list must not be world writable!\n"
+ if 02 & (stat _)[2];
+
+ die sprintf "TRUSTED_CONFIG_LIST: $parm_trusted_config_list %d is group writable, but not owned by group '%s' or '%s'.\n",
+ (stat _)[1],
+ scalar(getgrgid 0), scalar(getgrgid $>)
+ if (020 & (stat _)[2]) and not ((stat _)[5] == $> or (stat _)[5] == 0);
+
+ die sprintf "TRUSTED_CONFIG_LIST: $parm_trusted_config_list is not owned by user '%s' or '%s'.\n",
+ scalar(getpwuid 0), scalar(getpwuid $>)
+ if (not (-o _ or (stat _)[4] == 0));
+
+ open(TCL, $parm_trusted_config_list) or die "Can't open $parm_trusted_config_list: $!\n";
+ my $test_config = getcwd() . '/test-config';
+ die "Can't find '$test_config' in TRUSTED_CONFIG_LIST $parm_trusted_config_list."
+ if not grep { /^$test_config$/ } <TCL>;
+ }
+else
+ {
+ die "Unable to check the TRUSTED_CONFIG_LIST, seems to be empty?\n";
+ }
+
open(EXIMINFO, "$parm_exim -bV -C $parm_cwd/test-config -DDIR=$parm_cwd |") ||
die "** Cannot run $parm_exim: $!\n";
$parm_caller_group = getgrgid($parm_caller_gid);
-print "Program caller is $parm_caller, whose group is $parm_caller_group\n";
+print "Program caller is $parm_caller ($parm_caller_uid), whose group is $parm_caller_group ($parm_caller_gid)\n";
print "Home directory is $parm_caller_home\n";
unless (defined $parm_eximgroup)
$_ =~ /^\s*inet(?:\saddr)?:?\s?(\d+\.\d+\.\d+\.\d+)\s/i)
{
$ip = $1;
- next if ($ip eq "127.0.0.1");
+ next if ($ip =~ /^127\./);
$parm_ipv4 = $ip;
}
$stdout_skip = 0;
$rmfiltertest = 0;
$is_ipv6test = 0;
+ $TEST_STATE->{munge} = "";
# Remove the associative arrays used to hold checked mail files and msglogs
undef %expected_msglogs;
# Open the test's script
-
open(SCRIPT, "scripts/$test") ||
tests_exit(-1, "Failed to open \"scripts/$test\": $!");
+ # Run through the script once to set variables which should be global
+ while (<SCRIPT>)
+ {
+ if (/^no_message_check/) { $message_skip = 1; next; }
+ if (/^no_msglog_check/) { $msglog_skip = 1; next; }
+ if (/^no_stderr_check/) { $stderr_skip = 1; next; }
+ if (/^no_stdout_check/) { $stdout_skip = 1; next; }
+ if (/^rmfiltertest/) { $rmfiltertest = 1; next; }
+ if (/^sortlog/) { $sortlog = 1; next; }
+ }
+ # Reset to beginning of file for per test interpreting/processing
+ seek(SCRIPT, 0, 0);
# The first line in the script must be a comment that is used to identify
# the set of tests as a whole.
while (<SCRIPT>)
{
$lineno++;
+ # Could remove these variable settings because they are already
+ # set above, but doesn't hurt to leave them here.
if (/^no_message_check/) { $message_skip = 1; next; }
if (/^no_msglog_check/) { $msglog_skip = 1; next; }
if (/^no_stderr_check/) { $stderr_skip = 1; next; }