1*e0c4386eSCy Schubert#! /usr/bin/env perl 2*e0c4386eSCy Schubert# Copyright 2015-2022 The OpenSSL Project Authors. All Rights Reserved. 3*e0c4386eSCy Schubert# 4*e0c4386eSCy Schubert# Licensed under the Apache License 2.0 (the "License"). You may not use 5*e0c4386eSCy Schubert# this file except in compliance with the License. You can obtain a copy 6*e0c4386eSCy Schubert# in the file LICENSE in the source distribution or at 7*e0c4386eSCy Schubert# https://www.openssl.org/source/license.html 8*e0c4386eSCy Schubert 9*e0c4386eSCy Schubertuse strict; 10*e0c4386eSCy Schubertuse warnings; 11*e0c4386eSCy Schubert 12*e0c4386eSCy Schubert# Recognise VERBOSE aka V which is common on other projects. 13*e0c4386eSCy Schubert# Additionally, recognise VERBOSE_FAILURE aka VF aka REPORT_FAILURES 14*e0c4386eSCy Schubert# and recognise VERBOSE_FAILURE_PROGRESS aka VFP aka REPORT_FAILURES_PROGRESS. 15*e0c4386eSCy SchubertBEGIN { 16*e0c4386eSCy Schubert $ENV{HARNESS_VERBOSE} = "yes" if $ENV{VERBOSE} || $ENV{V}; 17*e0c4386eSCy Schubert $ENV{HARNESS_VERBOSE_FAILURE} = "yes" 18*e0c4386eSCy Schubert if $ENV{VERBOSE_FAILURE} || $ENV{VF} || $ENV{REPORT_FAILURES}; 19*e0c4386eSCy Schubert $ENV{HARNESS_VERBOSE_FAILURE_PROGRESS} = "yes" 20*e0c4386eSCy Schubert if ($ENV{VERBOSE_FAILURE_PROGRESS} || $ENV{VFP} 21*e0c4386eSCy Schubert || $ENV{REPORT_FAILURES_PROGRESS}); 22*e0c4386eSCy Schubert} 23*e0c4386eSCy Schubert 24*e0c4386eSCy Schubertuse File::Spec::Functions qw/catdir catfile curdir abs2rel rel2abs/; 25*e0c4386eSCy Schubertuse File::Basename; 26*e0c4386eSCy Schubertuse FindBin; 27*e0c4386eSCy Schubertuse lib "$FindBin::Bin/../util/perl"; 28*e0c4386eSCy Schubertuse OpenSSL::Glob; 29*e0c4386eSCy Schubert 30*e0c4386eSCy Schubertmy $srctop = $ENV{SRCTOP} || $ENV{TOP}; 31*e0c4386eSCy Schubertmy $bldtop = $ENV{BLDTOP} || $ENV{TOP}; 32*e0c4386eSCy Schubertmy $recipesdir = catdir($srctop, "test", "recipes"); 33*e0c4386eSCy Schubertmy $libdir = rel2abs(catdir($srctop, "util", "perl")); 34*e0c4386eSCy Schubertmy $jobs = $ENV{HARNESS_JOBS} // 1; 35*e0c4386eSCy Schubert 36*e0c4386eSCy Schubert$ENV{OPENSSL_CONF} = rel2abs(catfile($srctop, "apps", "openssl.cnf")); 37*e0c4386eSCy Schubert$ENV{OPENSSL_CONF_INCLUDE} = rel2abs(catdir($bldtop, "test")); 38*e0c4386eSCy Schubert$ENV{OPENSSL_MODULES} = rel2abs(catdir($bldtop, "providers")); 39*e0c4386eSCy Schubert$ENV{OPENSSL_ENGINES} = rel2abs(catdir($bldtop, "engines")); 40*e0c4386eSCy Schubert$ENV{CTLOG_FILE} = rel2abs(catfile($srctop, "test", "ct", "log_list.cnf")); 41*e0c4386eSCy Schubert 42*e0c4386eSCy Schubertmy %tapargs = 43*e0c4386eSCy Schubert ( verbosity => $ENV{HARNESS_VERBOSE} ? 1 : 0, 44*e0c4386eSCy Schubert lib => [ $libdir ], 45*e0c4386eSCy Schubert switches => '-w', 46*e0c4386eSCy Schubert merge => 1, 47*e0c4386eSCy Schubert timer => $ENV{HARNESS_TIMER} ? 1 : 0, 48*e0c4386eSCy Schubert ); 49*e0c4386eSCy Schubert 50*e0c4386eSCy Schubertif ($jobs > 1) { 51*e0c4386eSCy Schubert if ($ENV{HARNESS_VERBOSE}) { 52*e0c4386eSCy Schubert print "Warning: HARNESS_JOBS > 1 ignored with HARNESS_VERBOSE\n"; 53*e0c4386eSCy Schubert } else { 54*e0c4386eSCy Schubert $tapargs{jobs} = $jobs; 55*e0c4386eSCy Schubert print "Using HARNESS_JOBS=$jobs\n"; 56*e0c4386eSCy Schubert } 57*e0c4386eSCy Schubert} 58*e0c4386eSCy Schubert 59*e0c4386eSCy Schubert# Additional OpenSSL special TAP arguments. Because we can't pass them via 60*e0c4386eSCy Schubert# TAP::Harness->new(), they will be accessed directly, see the 61*e0c4386eSCy Schubert# TAP::Parser::OpenSSL implementation further down 62*e0c4386eSCy Schubertmy %openssl_args = (); 63*e0c4386eSCy Schubert 64*e0c4386eSCy Schubert$openssl_args{'failure_verbosity'} = $ENV{HARNESS_VERBOSE} ? 0 : 65*e0c4386eSCy Schubert $ENV{HARNESS_VERBOSE_FAILURE_PROGRESS} ? 2 : 66*e0c4386eSCy Schubert 1; # $ENV{HARNESS_VERBOSE_FAILURE} 67*e0c4386eSCy Schubertprint "Warning: HARNESS_VERBOSE overrides HARNESS_VERBOSE_FAILURE*\n" 68*e0c4386eSCy Schubert if ($ENV{HARNESS_VERBOSE} && ($ENV{HARNESS_VERBOSE_FAILURE} 69*e0c4386eSCy Schubert || $ENV{HARNESS_VERBOSE_FAILURE_PROGRESS})); 70*e0c4386eSCy Schubertprint "Warning: HARNESS_VERBOSE_FAILURE_PROGRESS overrides HARNESS_VERBOSE_FAILURE\n" 71*e0c4386eSCy Schubert if ($ENV{HARNESS_VERBOSE_FAILURE_PROGRESS} && $ENV{HARNESS_VERBOSE_FAILURE}); 72*e0c4386eSCy Schubert 73*e0c4386eSCy Schubertmy $outfilename = $ENV{HARNESS_TAP_COPY}; 74*e0c4386eSCy Schubertopen $openssl_args{'tap_copy'}, ">$outfilename" 75*e0c4386eSCy Schubert or die "Trying to create $outfilename: $!\n" 76*e0c4386eSCy Schubert if defined $outfilename; 77*e0c4386eSCy Schubert 78*e0c4386eSCy Schubertmy @alltests = find_matching_tests("*"); 79*e0c4386eSCy Schubertmy %tests = (); 80*e0c4386eSCy Schubert 81*e0c4386eSCy Schubertsub reorder { 82*e0c4386eSCy Schubert my $key = pop; 83*e0c4386eSCy Schubert 84*e0c4386eSCy Schubert # for parallel test runs, do slow tests first 85*e0c4386eSCy Schubert if ($jobs > 1 && $key =~ m/test_ssl_new|test_fuzz/) { 86*e0c4386eSCy Schubert $key =~ s/(\d+)-/01-/; 87*e0c4386eSCy Schubert } 88*e0c4386eSCy Schubert return $key; 89*e0c4386eSCy Schubert} 90*e0c4386eSCy Schubert 91*e0c4386eSCy Schubertmy $initial_arg = 1; 92*e0c4386eSCy Schubertforeach my $arg (@ARGV ? @ARGV : ('alltests')) { 93*e0c4386eSCy Schubert if ($arg eq 'list') { 94*e0c4386eSCy Schubert foreach (@alltests) { 95*e0c4386eSCy Schubert (my $x = basename($_)) =~ s|^[0-9][0-9]-(.*)\.t$|$1|; 96*e0c4386eSCy Schubert print $x,"\n"; 97*e0c4386eSCy Schubert } 98*e0c4386eSCy Schubert exit 0; 99*e0c4386eSCy Schubert } 100*e0c4386eSCy Schubert if ($arg eq 'alltests') { 101*e0c4386eSCy Schubert warn "'alltests' encountered, ignoring everything before that...\n" 102*e0c4386eSCy Schubert unless $initial_arg; 103*e0c4386eSCy Schubert %tests = map { $_ => 1 } @alltests; 104*e0c4386eSCy Schubert } elsif ($arg =~ m/^(-?)(.*)/) { 105*e0c4386eSCy Schubert my $sign = $1; 106*e0c4386eSCy Schubert my $test = $2; 107*e0c4386eSCy Schubert my @matches = find_matching_tests($test); 108*e0c4386eSCy Schubert 109*e0c4386eSCy Schubert # If '-foo' is the first arg, it's short for 'alltests -foo' 110*e0c4386eSCy Schubert if ($sign eq '-' && $initial_arg) { 111*e0c4386eSCy Schubert %tests = map { $_ => 1 } @alltests; 112*e0c4386eSCy Schubert } 113*e0c4386eSCy Schubert 114*e0c4386eSCy Schubert if (scalar @matches == 0) { 115*e0c4386eSCy Schubert warn "Test $test found no match, skipping ", 116*e0c4386eSCy Schubert ($sign eq '-' ? "removal" : "addition"), 117*e0c4386eSCy Schubert "...\n"; 118*e0c4386eSCy Schubert } else { 119*e0c4386eSCy Schubert foreach $test (@matches) { 120*e0c4386eSCy Schubert if ($sign eq '-') { 121*e0c4386eSCy Schubert delete $tests{$test}; 122*e0c4386eSCy Schubert } else { 123*e0c4386eSCy Schubert $tests{$test} = 1; 124*e0c4386eSCy Schubert } 125*e0c4386eSCy Schubert } 126*e0c4386eSCy Schubert } 127*e0c4386eSCy Schubert } else { 128*e0c4386eSCy Schubert warn "I don't know what '$arg' is about, ignoring...\n"; 129*e0c4386eSCy Schubert } 130*e0c4386eSCy Schubert 131*e0c4386eSCy Schubert $initial_arg = 0; 132*e0c4386eSCy Schubert} 133*e0c4386eSCy Schubert 134*e0c4386eSCy Schubert# prep recipes are mandatory and need to be always run first 135*e0c4386eSCy Schubertmy @preps = glob(catfile($recipesdir,"00-prep_*.t")); 136*e0c4386eSCy Schubertforeach my $test (@preps) { 137*e0c4386eSCy Schubert delete $tests{$test}; 138*e0c4386eSCy Schubert} 139*e0c4386eSCy Schubert 140*e0c4386eSCy Schubertsub find_matching_tests { 141*e0c4386eSCy Schubert my ($glob) = @_; 142*e0c4386eSCy Schubert 143*e0c4386eSCy Schubert if ($glob =~ m|^[\d\[\]\?\-]+$|) { 144*e0c4386eSCy Schubert return glob(catfile($recipesdir,"$glob-*.t")); 145*e0c4386eSCy Schubert } 146*e0c4386eSCy Schubert 147*e0c4386eSCy Schubert return glob(catfile($recipesdir,"*-$glob.t")); 148*e0c4386eSCy Schubert} 149*e0c4386eSCy Schubert 150*e0c4386eSCy Schubert# The following is quite a bit of hackery to adapt to both TAP::Harness 151*e0c4386eSCy Schubert# and Test::Harness, depending on what's available. 152*e0c4386eSCy Schubert# The TAP::Harness hack allows support for HARNESS_VERBOSE_FAILURE* and 153*e0c4386eSCy Schubert# HARNESS_TAP_COPY, while the Test::Harness hack can't, because the pre 154*e0c4386eSCy Schubert# TAP::Harness Test::Harness simply doesn't have support for this sort of 155*e0c4386eSCy Schubert# thing. 156*e0c4386eSCy Schubert# 157*e0c4386eSCy Schubert# We use eval to avoid undue interruption if TAP::Harness isn't present. 158*e0c4386eSCy Schubert 159*e0c4386eSCy Schubertmy $package; 160*e0c4386eSCy Schubertmy $eres; 161*e0c4386eSCy Schubert 162*e0c4386eSCy Schubert$eres = eval { 163*e0c4386eSCy Schubert package TAP::Parser::OpenSSL; 164*e0c4386eSCy Schubert use parent -norequire, 'TAP::Parser'; 165*e0c4386eSCy Schubert require TAP::Parser; 166*e0c4386eSCy Schubert 167*e0c4386eSCy Schubert sub new { 168*e0c4386eSCy Schubert my $class = shift; 169*e0c4386eSCy Schubert my %opts = %{ shift() }; 170*e0c4386eSCy Schubert my $failure_verbosity = $openssl_args{failure_verbosity}; 171*e0c4386eSCy Schubert my @plans = (); # initial level, no plan yet 172*e0c4386eSCy Schubert my $output_buffer = ""; 173*e0c4386eSCy Schubert 174*e0c4386eSCy Schubert # We rely heavily on perl closures to make failure verbosity work 175*e0c4386eSCy Schubert # We need to do so, because there's no way to safely pass extra 176*e0c4386eSCy Schubert # objects down all the way to the TAP::Parser::Result object 177*e0c4386eSCy Schubert my @failure_output = (); 178*e0c4386eSCy Schubert my %callbacks = (); 179*e0c4386eSCy Schubert if ($failure_verbosity > 0 || defined $openssl_args{tap_copy}) { 180*e0c4386eSCy Schubert $callbacks{ALL} = sub { # on each line of test output 181*e0c4386eSCy Schubert my $self = shift; 182*e0c4386eSCy Schubert my $fh = $openssl_args{tap_copy}; 183*e0c4386eSCy Schubert print $fh $self->as_string, "\n" 184*e0c4386eSCy Schubert if defined $fh; 185*e0c4386eSCy Schubert 186*e0c4386eSCy Schubert my $failure_verbosity = $openssl_args{failure_verbosity}; 187*e0c4386eSCy Schubert if ($failure_verbosity > 0) { 188*e0c4386eSCy Schubert my $is_plan = $self->is_plan; 189*e0c4386eSCy Schubert my $tests_planned = $is_plan && $self->tests_planned; 190*e0c4386eSCy Schubert my $is_test = $self->is_test; 191*e0c4386eSCy Schubert my $is_ok = $is_test && $self->is_ok; 192*e0c4386eSCy Schubert 193*e0c4386eSCy Schubert # workaround for parser not coping with sub-test indentation 194*e0c4386eSCy Schubert if ($self->is_unknown) { 195*e0c4386eSCy Schubert my $level = $#plans; 196*e0c4386eSCy Schubert my $indent = $level < 0 ? "" : " " x ($level * 4); 197*e0c4386eSCy Schubert 198*e0c4386eSCy Schubert ($is_plan, $tests_planned) = (1, $1) 199*e0c4386eSCy Schubert if ($self->as_string =~ m/^$indent 1\.\.(\d+)/); 200*e0c4386eSCy Schubert ($is_test, $is_ok) = (1, !$1) 201*e0c4386eSCy Schubert if ($self->as_string =~ m/^$indent(not )?ok /); 202*e0c4386eSCy Schubert } 203*e0c4386eSCy Schubert 204*e0c4386eSCy Schubert if ($is_plan) { 205*e0c4386eSCy Schubert push @plans, $tests_planned; 206*e0c4386eSCy Schubert $output_buffer = ""; # ignore comments etc. until plan 207*e0c4386eSCy Schubert } elsif ($is_test) { # result of a test 208*e0c4386eSCy Schubert pop @plans if @plans && --($plans[-1]) <= 0; 209*e0c4386eSCy Schubert print $output_buffer if !$is_ok; 210*e0c4386eSCy Schubert print "\n".$self->as_string 211*e0c4386eSCy Schubert if !$is_ok || $failure_verbosity == 2; 212*e0c4386eSCy Schubert print "\n# ------------------------------------------------------------------------------" if !$is_ok; 213*e0c4386eSCy Schubert $output_buffer = ""; 214*e0c4386eSCy Schubert } elsif ($self->as_string ne "") { 215*e0c4386eSCy Schubert # typically is_comment or is_unknown 216*e0c4386eSCy Schubert $output_buffer .= "\n".$self->as_string; 217*e0c4386eSCy Schubert } 218*e0c4386eSCy Schubert } 219*e0c4386eSCy Schubert } 220*e0c4386eSCy Schubert } 221*e0c4386eSCy Schubert 222*e0c4386eSCy Schubert if ($failure_verbosity > 0) { 223*e0c4386eSCy Schubert $callbacks{EOF} = sub { 224*e0c4386eSCy Schubert my $self = shift; 225*e0c4386eSCy Schubert 226*e0c4386eSCy Schubert # We know we are a TAP::Parser::Aggregator object 227*e0c4386eSCy Schubert if (scalar $self->failed > 0 && @failure_output) { 228*e0c4386eSCy Schubert # We add an extra empty line, because in the case of a 229*e0c4386eSCy Schubert # progress counter, we're still at the end of that progress 230*e0c4386eSCy Schubert # line. 231*e0c4386eSCy Schubert print $_, "\n" foreach (("", @failure_output)); 232*e0c4386eSCy Schubert } 233*e0c4386eSCy Schubert # Echo any trailing comments etc. 234*e0c4386eSCy Schubert print "$output_buffer"; 235*e0c4386eSCy Schubert }; 236*e0c4386eSCy Schubert } 237*e0c4386eSCy Schubert 238*e0c4386eSCy Schubert if (keys %callbacks) { 239*e0c4386eSCy Schubert # If %opts already has a callbacks element, the order here 240*e0c4386eSCy Schubert # ensures we do not override it 241*e0c4386eSCy Schubert %opts = ( callbacks => { %callbacks }, %opts ); 242*e0c4386eSCy Schubert } 243*e0c4386eSCy Schubert 244*e0c4386eSCy Schubert return $class->SUPER::new({ %opts }); 245*e0c4386eSCy Schubert } 246*e0c4386eSCy Schubert 247*e0c4386eSCy Schubert package TAP::Harness::OpenSSL; 248*e0c4386eSCy Schubert use parent -norequire, 'TAP::Harness'; 249*e0c4386eSCy Schubert require TAP::Harness; 250*e0c4386eSCy Schubert 251*e0c4386eSCy Schubert package main; 252*e0c4386eSCy Schubert 253*e0c4386eSCy Schubert $tapargs{parser_class} = "TAP::Parser::OpenSSL"; 254*e0c4386eSCy Schubert $package = 'TAP::Harness::OpenSSL'; 255*e0c4386eSCy Schubert}; 256*e0c4386eSCy Schubert 257*e0c4386eSCy Schubertunless (defined $eres) { 258*e0c4386eSCy Schubert $eres = eval { 259*e0c4386eSCy Schubert # Fake TAP::Harness in case it's not loaded 260*e0c4386eSCy Schubert package TAP::Harness::fake; 261*e0c4386eSCy Schubert use parent 'Test::Harness'; 262*e0c4386eSCy Schubert 263*e0c4386eSCy Schubert sub new { 264*e0c4386eSCy Schubert my $class = shift; 265*e0c4386eSCy Schubert my %args = %{ shift() }; 266*e0c4386eSCy Schubert 267*e0c4386eSCy Schubert return bless { %args }, $class; 268*e0c4386eSCy Schubert } 269*e0c4386eSCy Schubert 270*e0c4386eSCy Schubert sub runtests { 271*e0c4386eSCy Schubert my $self = shift; 272*e0c4386eSCy Schubert 273*e0c4386eSCy Schubert # Pre TAP::Harness Test::Harness doesn't support [ filename, name ] 274*e0c4386eSCy Schubert # elements, so convert such elements to just be the filename 275*e0c4386eSCy Schubert my @args = map { ref($_) eq 'ARRAY' ? $_->[0] : $_ } @_; 276*e0c4386eSCy Schubert 277*e0c4386eSCy Schubert my @switches = (); 278*e0c4386eSCy Schubert if ($self->{switches}) { 279*e0c4386eSCy Schubert push @switches, $self->{switches}; 280*e0c4386eSCy Schubert } 281*e0c4386eSCy Schubert if ($self->{lib}) { 282*e0c4386eSCy Schubert foreach (@{$self->{lib}}) { 283*e0c4386eSCy Schubert my $l = $_; 284*e0c4386eSCy Schubert 285*e0c4386eSCy Schubert # It seems that $switches is getting interpreted with 'eval' 286*e0c4386eSCy Schubert # or something like that, and that we need to take care of 287*e0c4386eSCy Schubert # backslashes or they will disappear along the way. 288*e0c4386eSCy Schubert $l =~ s|\\|\\\\|g if $^O eq "MSWin32"; 289*e0c4386eSCy Schubert push @switches, "-I$l"; 290*e0c4386eSCy Schubert } 291*e0c4386eSCy Schubert } 292*e0c4386eSCy Schubert 293*e0c4386eSCy Schubert $Test::Harness::switches = join(' ', @switches); 294*e0c4386eSCy Schubert Test::Harness::runtests(@args); 295*e0c4386eSCy Schubert } 296*e0c4386eSCy Schubert 297*e0c4386eSCy Schubert package main; 298*e0c4386eSCy Schubert $package = 'TAP::Harness::fake'; 299*e0c4386eSCy Schubert }; 300*e0c4386eSCy Schubert} 301*e0c4386eSCy Schubert 302*e0c4386eSCy Schubertunless (defined $eres) { 303*e0c4386eSCy Schubert print $@,"\n" if $@; 304*e0c4386eSCy Schubert print $!,"\n" if $!; 305*e0c4386eSCy Schubert exit 127; 306*e0c4386eSCy Schubert} 307*e0c4386eSCy Schubert 308*e0c4386eSCy Schubertmy $harness = $package->new(\%tapargs); 309*e0c4386eSCy Schubertmy $ret = 310*e0c4386eSCy Schubert $harness->runtests(map { [ abs2rel($_, rel2abs(curdir())), basename($_) ] } 311*e0c4386eSCy Schubert @preps); 312*e0c4386eSCy Schubert 313*e0c4386eSCy Schubertif (ref($ret) ne "TAP::Parser::Aggregator" || !$ret->has_errors) { 314*e0c4386eSCy Schubert $ret = 315*e0c4386eSCy Schubert $harness->runtests(map { [ abs2rel($_, rel2abs(curdir())), basename($_) ] } 316*e0c4386eSCy Schubert sort { reorder($a) cmp reorder($b) } keys %tests); 317*e0c4386eSCy Schubert} 318*e0c4386eSCy Schubert 319*e0c4386eSCy Schubert# If this is a TAP::Parser::Aggregator, $ret->has_errors is the count of 320*e0c4386eSCy Schubert# tests that failed. We don't bother with that exact number, just exit 321*e0c4386eSCy Schubert# with an appropriate exit code when it isn't zero. 322*e0c4386eSCy Schubertif (ref($ret) eq "TAP::Parser::Aggregator") { 323*e0c4386eSCy Schubert exit 0 unless $ret->has_errors; 324*e0c4386eSCy Schubert exit 1 unless $^O eq 'VMS'; 325*e0c4386eSCy Schubert # On VMS, perl converts an exit 1 to SS$_ABORT (%SYSTEM-F-ABORT), which 326*e0c4386eSCy Schubert # is a bit harsh. As per perl recommendations, we explicitly use the 327*e0c4386eSCy Schubert # same VMS status code as typical C programs would for exit(1), except 328*e0c4386eSCy Schubert # we set the error severity rather than success. 329*e0c4386eSCy Schubert # Ref: https://perldoc.perl.org/perlport#exit 330*e0c4386eSCy Schubert # https://perldoc.perl.org/perlvms#$? 331*e0c4386eSCy Schubert exit 0x35a000 # C facility code 332*e0c4386eSCy Schubert + 8 # 1 << 3 (to make space for the 3 severity bits) 333*e0c4386eSCy Schubert + 2 # severity: E(rror) 334*e0c4386eSCy Schubert + 0x10000000; # bit 28 set => the shell stays silent 335*e0c4386eSCy Schubert} 336*e0c4386eSCy Schubert 337*e0c4386eSCy Schubert# If this isn't a TAP::Parser::Aggregator, it's the pre-TAP test harness, 338*e0c4386eSCy Schubert# which simply dies at the end if any test failed, so we don't need to bother 339*e0c4386eSCy Schubert# with any exit code in that case. 340