use Pod::Usage;
use Getopt::Long;
use FindBin qw'$RealBin';
+use File::Copy;
use lib "$RealBin/lib";
use Exim::Runtest;
-use Exim::Utils qw(uniq numerically);
+use Exim::Utils qw(uniq numerically cp);
use if $ENV{DEBUG} && scalar($ENV{DEBUG} =~ /\bruntest\b/) => 'Smart::Comments' => '####';
use if $ENV{DEBUG} && scalar($ENV{DEBUG} =~ /\bruntest\b/) => 'Data::Dumper';
my($date1,$date2,$date3,$expired) = ($1,$2,$3,$4);
$expired = '' if !defined $expired;
- # Round the time-difference down to nearest even value
- my($increment) = ((date_seconds($date3) - date_seconds($date2)) >> 1) << 1;
+ # Round the time-difference up to nearest even value
+ my($increment) = ((date_seconds($date3) - date_seconds($date2) + 1) >> 1) << 1;
# We used to use globally unique replacement values, but timing
# differences make this impossible. Just show the increment on the
s/\bgid=\d+/gid=gggg/;
s/\begid=\d+/egid=gggg/;
- s/\b(pid=|PID: )\d+/$1pppp/;
+ s/\b(pid=|pid |PID: )\d+/$1pppp/;
s/\buid=\d+/uid=uuuu/;
s/\beuid=\d+/euid=uuuu/;
s/set_process_info:\s+\d+/set_process_info: pppp/;
- s/queue run pid \d+/queue run pid ppppp/;
s/process \d+ running as transport filter/process pppp running as transport filter/;
s/process \d+ writing to transport filter/process pppp writing to transport filter/;
s/reading pipe for subprocess \d+/reading pipe for subprocess pppp/;
s/remote delivery process \d+ ended/remote delivery process pppp ended/;
# Pid in temp file in appendfile transport
- s"test-mail/temp\.\d+\."test-mail/temp.pppp.";
+ s"test-mail/(subdir/)?temp\K\.\d+\.".pppp.";
# Optional pid in log lines
s/^(\d{4}-\d\d-\d\d\s\d\d:\d\d:\d\d)(\.\d{3}|)(\s[+-]\d{4}|)(\s\[\d+\])/
# This handles "connection from" and the like, when the port is given
if (!/listening for SMTP on/ && !/Connecting to/ && !/=>/ && !/->/
- && !/\*>/ && !/Connection refused/)
+ && !/\*>/&& !/==/ && !/\*\*/ && !/Connection refused/ && !/in response to/)
{
s/\[([a-z\d:]+|\d+(?:\.\d+){3})\]:(\d+)/"[".$1."]:".new_value($2,"%s",\$next_port)/ie;
}
s/conversion: german.xn--strae-oqa.de/conversion: german.straße.de/;
# subsecond timstamp info in reported header-files
- s/^(-received_time_usec \.)\d{6}$/$1uuuuuu/;
+ s/^-received_time_usec \.\K\d{6}$/uuuuuu/;
+ s/^-received_time_complete \K\d+\.\d{6}$/tttt.uuuuuu/;
# Postgres server takes varible time to shut down; lives in various places
s/^waiting for server to shut down\.+ done$/waiting for server to shut down.... done/;
# ARC is not always supported by the build
next if /^arc_sign =/;
+ # LIMITS is not always supported by the build
+ next if /^limits_advertise_hosts =/;
+
# TLS resumption is not always supported by the build
next if /^tls_resumption_hosts =/;
next if /^-tls_resumption/;
# this is timing-dependent
next if /^OpenSSL: creating STEK$/;
+ next if /^selfsign cert rotate$/;
# TLS preload
# only OpenSSL speaks of these
- next if /^TLS: preloading DH params for server/;
+ next if /^TLS: (preloading (DH params|ECDH curve|CA bundle) for server|generating selfsigned server cert)/;
next if /^Diffie-Hellman initialized from default/;
- next if /^TLS: preloading ECDH curve for server/;
- next if /^ECDH OpenSSL [< ]?[\d.+]+ temp key parameter settings:/;
- next if /^ECDH: .'*prime256v1'/;
- next if /^watch dir/;
+ next if /^ECDH OpenSSL (< )?[\d.+]+: temp key parameter settings:/;
+ next if /^ECDH: .*'prime256v1'/;
+ next if /^tls_verify_certificates: system$/;
+ next if /^tls_set_watch: .*\/cert.pem/;
+ next if /^Generating 2048 bit RSA key/;
# TLS preload
# only GnuTLS speaks of these
next if /^TLS: preloading cipher list for server: NULL$/;
s/^GnuTLS using default session cipher\/priority "NORMAL"$/TLS: not preloading cipher list for server/;
next if /^GnuTLS<2>: added \d+ protocols, \d+ ciphersuites, \d+ sig algos and \d+ groups into priority list$/;
+ next if /^GnuTLS<2>: (Disabling X.509 extensions|signing structure using RSA-SHA256)/;
+ next if /^GnuTLS.*(wrap_nettle_mpi_print|gnutls_subject_alt_names_get|get_alt_name)/;
+
+ # only kevent platforms (FreeBSD, OpenBSD) say this
+ next if /^watch dir/;
+ next if /^watch file .*\/usr\/local/;
+ next if /^watch file .*\/etc\/ssl/;
# TLS preload
# there happen in different orders for OpenSSL/GnuTLS/noTLS
+ next if /^TLS: generating selfsigned server cert/;
next if /^TLS: not preloading (CA bundle|cipher list) for server$/;
next if /^TLS: not preloading server certs$/;
# drop pdkim debugging header
next if /^DKIM( <<<<<<<<<<<<<<<<<<<<<<<<<<<<<+|: no signatures)$/;
+ # Some platforms have TIOCOUTome do not
+ next if /\d+ bytes remain in socket output buffer$/;
# Various other IPv6 lines must be omitted too
next if /using host_fake_gethostbyname for \S+ \(IPv6\)/;
# Experimental_REQUIRETLS
next if / in tls_advertise_requiretls?\? no \(end of list\)/;
+ # Experimental_LIMITS
+ next if / in limits_advertise_hosts?\? no \(matched "!\*"\)/;
+
# TCP Fast Open
next if /^(ppppp )?setsockopt FASTOPEN: Network Error/;
next if /\w+ in keep_environment\? (yes|no)/;
# Sizes vary with test hostname
- s/^cmd buf flush \d+ bytes$/cmd buf flush ddd bytes/;
+ s/^cmd buf flush \d+ bytes/cmd buf flush ddd bytes/;
# Spool filesystem free space changes on different systems.
s/^((?:spool|log) directory space =) -?\d+K (inodes =)\s*-?\d+/$1 nnnnnK $2 nnnnn/;
# Platform differences in errno strings
s/Arg list too long/Argument list too long/;
+
+ # OpenSSL vs. GnuTLS
+ s/session: \K\((SSL_connect|gnutls_handshake)\): timed out/(tls lib connect fn): timed out/;
+ s/TLS error on connection from .*\K\((SSL_accept|gnutls_handshake)\): timed out/(tls lib accept fn): timed out/;
+ s/TLS error on connection from .*\K(SSL_accept: TCP connection closed by peer|\(gnutls_handshake\): The TLS connection was non-properly terminated.)/(tls lib accept fn): TCP connection closed by peer/;
}
# ======== mail ========
if (-s $mf)
{
my $sf = /^u/i ? $sf_current : $sf_flavour;
- tests_exit(-1, "Failed to cp $mf $sf") if system("cp '$mf' '$sf'") != 0;
+ copy($mf, $sf) or tests_exit(-1, "Failed to copy $mf $sf");
}
else
{
$prcmd =~ s/; /;\n>> /;
print ">> $prcmd\n";
}
-system("$cmd");
+system($cmd);
}
'valgrind' => \$valgrind,
'range=s{2}' => \my @range_wanted,
'test=i@' => \my @tests_wanted,
+ 'fail-any!' => \my $fail_any,
'flavor|flavour=s' => \$flavour,
'help' => sub { pod2usage(-exit => 0) },
'man' => sub {
chomp(my @eximinfo = `$eximinfo 2>&1`);
die "$0: Can't run $eximinfo\n" if $? == -1;
-warn 'Got ' . $?>>8 . " from $eximinfo\n" if $?;
+warn 'Got ' . ($?>>8) . " from $eximinfo\n" if $?;
foreach (@eximinfo)
{
if (my ($version) = /^Exim version (\S+)/) {
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 { /^\Q$test_config\E$/ } <TCL>;
+ if not grep { /^\Q$test_config\E$/ } <TCL>;
}
else
{
($parm_exim_dir) = $parm_exim =~ m?^(.*)/exim?;
$dbm_build_deleted = 0;
-if (defined $parm_lookups{dbm} &&
- system("cp $parm_exim_dir/exim_dbmbuild eximdir") != 0)
+if (defined $parm_lookups{dbm} && not cp("$parm_exim_dir/exim_dbmbuild", "eximdir/exim_dbmbuild"))
{
delete $parm_lookups{dbm};
$dbm_build_deleted = 1;
}
-if (system("cp $parm_exim_dir/exim_dumpdb eximdir") != 0)
- {
- tests_exit(-1, "Failed to make a copy of exim_dumpdb: $!");
- }
-
-if (system("cp $parm_exim_dir/exim_lock eximdir") != 0)
- {
- tests_exit(-1, "Failed to make a copy of exim_lock: $!");
- }
-
-if (system("cp $parm_exim_dir/exinext eximdir") != 0)
- {
- tests_exit(-1, "Failed to make a copy of exinext: $!");
- }
-
-if (system("cp $parm_exim_dir/exigrep eximdir") != 0)
- {
- tests_exit(-1, "Failed to make a copy of exigrep: $!");
- }
-
-if (system("cp $parm_exim_dir/eximstats eximdir") != 0)
- {
- tests_exit(-1, "Failed to make a copy of eximstats: $!");
- }
+foreach my $tool (qw(exim_dumpdb exim_lock exinext exigrep eximstats)) {
+ cp("$parm_exim_dir/$tool" => "eximdir/$tool")
+ or tests_exit(-1, "Failed to make a copy of $tool: $!");
+}
# Collect some version information
print '-' x 78, "\n";
}
+my $failures = 0;
foreach $test (@test_list)
{
state $lasttestdir = '';
# the test-mail directory for appendfile deliveries.
system "sudo /bin/rm -rf spool test-*";
- system "mkdir test-mail 2>/dev/null";
+ mkdir "test-mail";
# A privileged Exim will normally make its own spool directory, but some of
# the tests run in unprivileged modes that don't always work if the spool
# directory isn't already there. What is more, we want anybody to be able
# to read it in order to find the daemon's pid.
- system "mkdir spool; " .
- "sudo chown $parm_eximuser:$parm_eximgroup spool; " .
+ mkdir "spool";
+ system "sudo chown $parm_eximuser:$parm_eximgroup spool; " .
"sudo chmod 0755 spool";
# Empty the cache that keeps track of things like message id mappings, and
print "\nshow stdErr, show stdOut, Retry, Continue (without file comparison), or Quit? [Q] ";
$_ = $force_continue ? "c" : <T>;
tests_exit(1) if /^q?$/i;
- if (/^c$/ && $force_continue) {
- log_failure($log_failed_filename, $testno, "exit code unexpected");
- log_test($log_summary_filename, $testno, 'F')
- }
+ if (/^c$/ && $force_continue)
+ {
+ log_failure($log_failed_filename, $testno, "exit code unexpected");
+ log_test($log_summary_filename, $testno, 'F');
+ $failures++;
+ }
if ($force_continue)
{
print "\nstdout tail:\n";
{
if (($? & 0xff) == 0)
{ printf("Server return code %d for test %d starting line %d", $?/256,
- $testno, $subtest_startline); }
+ $testno, $subtest_startline); }
elsif (($? & 0xff00) == 0)
{ printf("Server killed by signal %d", $? & 255); }
else
print "\nShow server stdout, Retry, Continue, or Quit? [Q] ";
$_ = $force_continue ? "c" : <T>;
tests_exit(1) if /^q?$/i;
- if (/^c$/ && $force_continue) {
- log_failure($log_failed_filename, $testno, "exit code unexpected");
- log_test($log_summary_filename, $testno, 'F')
- }
+ if (/^c$/ && $force_continue)
+ {
+ log_failure($log_failed_filename, $testno, "exit code unexpected");
+ log_test($log_summary_filename, $testno, 'F');
+ $failures++;
+ }
print "... continue forced\n" if $force_continue;
last if /^[rc]$/i;
{
sleep 1 if $slow;
my $rc = check_output($TEST_STATE->{munge});
- log_test($log_summary_filename, $testno, 'P') if ($rc == 0);
+ if ($rc == 0)
+ {
+ log_test($log_summary_filename, $testno, 'P');
+ }
+ else
+ {
+ $failures++;
+ }
if ($rc < 2)
{
print (" Script completed\n");
##################################################
tests_exit(-1, "No runnable tests selected") if not @test_list;
-tests_exit(0);
+tests_exit($fail_any ? $failures : 0);
__END__