Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ability to run single testcase via test_zone() #1312

Merged
merged 10 commits into from
May 3, 2024
2 changes: 2 additions & 0 deletions MANIFEST
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,8 @@ t/Test-zone09.data
t/Test-zone09.t
t/Test-zone11.data
t/Test-zone11.t
t/Test.data
t/Test.t
t/TestUtil.pm
t/translator.t
t/undelegated.data
Expand Down
13 changes: 8 additions & 5 deletions lib/Zonemaster/Engine.pm
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ sub all_tags {
my ( $class ) = @_;
my @res;

foreach my $module ( 'Basic', sort { $a cmp $b } Zonemaster::Engine::Test->modules ) {
foreach my $module ( sort { $a cmp $b } Zonemaster::Engine::Test->modules ) {
my $full = "Zonemaster::Engine::Test::$module";
my $ref = $full->metadata;
foreach my $list ( values %{$ref} ) {
Expand All @@ -95,7 +95,7 @@ sub all_methods {
my ( $class ) = @_;
my %res;

foreach my $module ( 'Basic', Zonemaster::Engine::Test->modules ) {
foreach my $module ( Zonemaster::Engine::Test->modules ) {
my $full = "Zonemaster::Engine::Test::$module";
my $ref = $full->metadata;
foreach my $method ( sort { $a cmp $b } keys %{$ref} ) {
Expand Down Expand Up @@ -262,9 +262,12 @@ Runs all available tests for the zone with the given name in the specified modul

=item test_method($module, $method, $name)

Run one particular test method in one particular module for one particular zone. The requested module must be in the list of active loaded modules (that is, not the Basic
module and not a module disabled by the current profile), and the method must be listed in the metadata the module exports. If those requirements
are fulfilled, the method will be called with the provided arguments.
Run one particular test method in one particular module for one particular zone.
The requested module must be in the list of currently enabled modules (that is,
not a module disabled by the current profile), and the method must be listed in
the metadata of the module exports.
If those requirements are fulfilled, the method will be called with the provided
arguments.

=item zone($name)

Expand Down
6 changes: 0 additions & 6 deletions lib/Zonemaster/Engine/Profile.pm
Original file line number Diff line number Diff line change
Expand Up @@ -907,12 +907,6 @@ Default is an arrayref listing all the test cases.

Specifies which test cases can be run by the testing suite.

Note that an exception applies to test cases C<basic01> and C<basic02>:
when running either the full testing suite or just the Basic test module,
these test cases are always run no matter if they're excluded from this
property. This is because their primary goal is to verify that the given
domain name can be tested at all.

=head2 test_cases_vars.dnssec04.REMAINING_SHORT

A positive integer value.
Expand Down
44 changes: 21 additions & 23 deletions lib/Zonemaster/Engine/Test.pm
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ use Zonemaster::LDNS;
use Zonemaster::Engine;
use Zonemaster::Engine::Profile;
use Zonemaster::Engine::Util;
use Zonemaster::Engine::Test::Basic;

use IO::Socket::INET6; # Lazy-loads, so make sure it's here for the version logging

Expand Down Expand Up @@ -137,8 +136,7 @@ sub _log_versions {

my @modules_array = modules();

Returns a list of strings containing the names of all available Test modules, with the
exception of L<Zonemaster::Engine::Test::Basic> (since that one is a bit special),
Returns a list of strings containing the names of all available Test modules,
based on the content of the B<share/modules.txt> file.

=back
Expand All @@ -157,16 +155,18 @@ sub modules {

Runs the L<default set of tests|/all()> of L<all Test modules found|/modules()> for the given zone.

This method always starts with the execution of the L<Basic Test module|Zonemaster::Engine::Test::Basic>.
If the L<Basic tests|Zonemaster::Engine::Test::Basic/TESTS> fail to indicate an extremely minimal
level of function for the zone (e.g., it must have a parent domain, and it must have at least one
functional name server), the testing suite is aborted. See L<Zonemaster::Engine::Test::Basic/can_continue()>
for more details.
Otherwise, other Test modules are L<looked up and loaded|/modules()> from the B<share/modules.txt> file,
and executed in the order in which they appear in the file.
Test modules are L<looked up and loaded|/modules()> from the
B<share/modules.txt> file, and executed in the order in which they appear in the
file.
The default set of tests (Test Cases) is specified in the L</all()> method of each Test module. They
can be individually disabled by the L<profile|Zonemaster::Engine::Profile/test_cases>.

A test module may implement a C<can_continue()> method to indicate lack of an
extremely minimal level of function for the zone (e.g., it must have a parent
domain, and it must have at least one functional name server).
If lack of such minimal function is indicated, the testing harness is aborted.
See L<Zonemaster::Engine::Test::Basic/can_continue()> for an example.

Takes a L<Zonemaster::Engine::Zone> object.

Returns a list of L<Zonemaster::Engine::Logger::Entry> objects.
Expand All @@ -188,32 +188,32 @@ sub run_all_for {
return info( NO_NETWORK => {} );
}

info( MODULE_VERSION => { module => 'Zonemaster::Engine::Test::Basic', version => Zonemaster::Engine::Test::Basic->version } );
push @results, Zonemaster::Engine::Test::Basic->all( $zone );
info( MODULE_END => { module => 'Zonemaster::Engine::Test::Basic' } );

if ( Zonemaster::Engine::Test::Basic->can_continue( $zone, @results ) and Zonemaster::Engine->can_continue() ) {
if ( Zonemaster::Engine->can_continue() ) {
foreach my $mod ( __PACKAGE__->modules ) {
my $module = "Zonemaster::Engine::Test::$mod";

info( MODULE_VERSION => { module => $module, version => $module->version } );
my @res = eval { $module->all( $zone ) };

my @module_results = eval { $module->all( $zone ) };
push @results, @module_results;
if ( $@ ) {
my $err = $@;
if ( blessed $err and $err->isa( 'Zonemaster::Engine::Exception' ) ) {
die $err; # Utility exception, pass it on
}
else {
push @res, info( MODULE_ERROR => { module => $module, msg => "$err" } );
push @results, info( MODULE_ERROR => { module => $module, msg => "$err" } );
}
}

info( MODULE_END => { module => $module } );

push @results, @res;
if ( $module->can( 'can_continue' ) && !$module->can_continue( $zone, @module_results ) ) {
push @results, info( CANNOT_CONTINUE => { domain => $zone->name->string } );
last;
}
}
}
else {
push @results, info( CANNOT_CONTINUE => { domain => $zone->name->string } );
}

return @results;
} ## end sub run_all_for
Expand Down Expand Up @@ -243,7 +243,6 @@ sub run_module {
my ( $class, $requested, $zone ) = @_;
my @res;
my ( $module ) = grep { lc( $requested ) eq lc( $_ ) } $class->modules;
$module = 'Basic' if ( not $module and lc( $requested ) eq 'basic' );

Zonemaster::Engine->start_time_now();
push @res, info( START_TIME => { time_t => time(), string => strftime( "%F %T %z", ( localtime() ) ) } );
Expand Down Expand Up @@ -307,7 +306,6 @@ sub run_one {
my ( $class, $requested, $test, $zone ) = @_;
my @res;
my ( $module ) = grep { lc( $requested ) eq lc( $_ ) } $class->modules;
$module = 'Basic' if ( not $module and lc( $requested ) eq 'basic' );

Zonemaster::Engine->start_time_now();
push @res, info( START_TIME => { time_t => time(), string => strftime( "%F %T %z", ( localtime() ) ) } );
Expand Down
21 changes: 15 additions & 6 deletions lib/Zonemaster/Engine/Test/Address.pm
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use Readonly;
use Zonemaster::Engine::Recursor;
use Zonemaster::Engine::Constants qw[:addresses :ip];
use Zonemaster::Engine::TestMethods;
use Zonemaster::Engine::Util;
use Zonemaster::Engine::Util qw[name should_run_test];

=head1 NAME

Expand Down Expand Up @@ -46,13 +46,22 @@ Returns a list of L<Zonemaster::Engine::Logger::Entry> objects.

sub all {
my ( $class, $zone ) = @_;

my @results;

push @results, $class->address01( $zone ) if Zonemaster::Engine::Util::should_run_test( q{address01} );
push @results, $class->address02( $zone ) if Zonemaster::Engine::Util::should_run_test( q{address02} );
# Perform ADDRESS03 if ADDRESS02 passed
if ( any { $_->tag eq q{NAMESERVERS_IP_WITH_REVERSE} } @results ) {
push @results, $class->address03( $zone ) if Zonemaster::Engine::Util::should_run_test( q{address03} );
push @results, $class->address01( $zone )
if should_run_test( q{address01} );

my $ns_with_reverse = 1;
if ( should_run_test( q{address02} ) ) {
push @results, $class->address02( $zone );
$ns_with_reverse = any { $_->tag eq q{NAMESERVERS_IP_WITH_REVERSE} } @results;
}

# Perform ADDRESS03 if ADDRESS02 passed or was skipped
if ( $ns_with_reverse ) {
push @results, $class->address03( $zone )
if should_run_test( q{address03} );
}

return @results;
Expand Down
61 changes: 38 additions & 23 deletions lib/Zonemaster/Engine/Test/Basic.pm
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use Zonemaster::Engine::Constants qw[:ip :name];
use Zonemaster::Engine::Test::Address;
use Zonemaster::Engine::Test::Syntax;
use Zonemaster::Engine::TestMethods;
use Zonemaster::Engine::Util;
use Zonemaster::Engine::Util qw[info name ns should_run_test];

=head1 NAME

Expand All @@ -33,10 +33,12 @@ Zonemaster::Engine::Test::Basic - Module implementing tests focused on basic zon

=item all()

my @logentry_array = all( $zone );
my @logentries = Zonamester::Engine::Test::Basic->all( $zone );

Runs the default set of tests for that module, i.e. between L<one and four tests|/TESTS> depending on the tested zone.
If L<BASIC01|/basic01()> passes, L<BASIC02|/basic02()> is run. If L<BASIC02|/basic02()> fails, L<BASIC03|/basic03()> is run.
Runs the test cases in the Basic test module.
A test is skipped if it is not included in
L<Zonemaster::Engine::Profile/"test_cases"> or if a previous test case has found
a condition that renders it superfluous.

Takes a L<Zonemaster::Engine::Zone> object.

Expand All @@ -48,25 +50,35 @@ Returns a list of L<Zonemaster::Engine::Logger::Entry> objects.

sub all {
my ( $class, $zone ) = @_;
my @results;

push @results, $class->basic01( $zone );
my @results;

if ( grep { $_->tag eq q{B01_CHILD_FOUND} } @results ) {
push @results, $class->basic02( $zone );
if ( should_run_test( q{basic01} ) ) {
push @results, $class->basic01( $zone );
if ( none { $_->tag eq q{B01_CHILD_FOUND} } @results ) {
return @results;
}
}

# Perform BASIC3 if BASIC2 failed
if ( none { $_->tag eq q{B02_AUTH_RESPONSE_SOA} } @results ) {
push @results, $class->basic03( $zone ) if Zonemaster::Engine::Util::should_run_test( q{basic03} );
my $auth_response_soa = 0;
if ( should_run_test( q{basic02} ) ) {
push @results, $class->basic02( $zone );
$auth_response_soa = any { $_->tag eq q{B02_AUTH_RESPONSE_SOA} } @results;
}
else {
push @results,
_emit_log(
HAS_NAMESERVER_NO_WWW_A_TEST => {
zname => $zone->name,
}
);

if ( should_run_test( q{basic03} ) ) {
# Perform BASIC3 if BASIC2 failed
if ( $auth_response_soa ) {
push @results,
_emit_log(
HAS_NAMESERVER_NO_WWW_A_TEST => {
zname => $zone->name,
}
);
}
else {
push @results, $class->basic03( $zone );
}
}

return @results;
Expand All @@ -90,15 +102,18 @@ Returns a boolean.

sub can_continue {
my ( $class, $zone, @results ) = @_;
my %tag = map { $_->tag => 1 } @results;
my $is_undelegated = Zonemaster::Engine::Recursor->has_fake_addresses( $zone->name->string );

if ( not $tag{B02_NO_DELEGATION} and $tag{B02_AUTH_RESPONSE_SOA} ) {
my $is_undelegated = Zonemaster::Engine::Recursor->has_fake_addresses( $zone->name->string );
if ( $is_undelegated ) {
return 1;
}
else {
return $is_undelegated;

if ( should_run_test( 'basic02' ) ) {
my %tag = map { $_->tag => 1 } @results;
return !$tag{B02_NO_DELEGATION} && $tag{B02_AUTH_RESPONSE_SOA};
}

return 1;
}

=over
Expand Down
Loading
Loading