Skip to content

Commit 2d28385

Browse files
refactor: centralize configuration mocking and module reloading utilities into TestBootstrap.pm to reduce test code duplication.
1 parent 7d299ce commit 2d28385

9 files changed

Lines changed: 111 additions & 242 deletions

File tree

.github/tests/lib/TestBootstrap.pm

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use Exporter qw(import);
77
use File::Basename qw(dirname);
88
use File::Spec;
99

10-
our @EXPORT_OK = qw(repo_root);
10+
our @EXPORT_OK = qw(repo_root mock_config with_mock_config reload_module_with_config);
1111

1212
BEGIN {
1313
# Ensure tests load modules from this checkout before any system-installed CSF copy.
@@ -23,4 +23,66 @@ sub repo_root {
2323
return $ENV{CSF_TEST_REPO_ROOT};
2424
}
2525

26+
# ---------------------------------------------------------------------------
27+
# Shared config-mocking helpers
28+
# ---------------------------------------------------------------------------
29+
30+
{
31+
package TestBootstrap::MockConfig;
32+
33+
sub new {
34+
my ($class, $config) = @_;
35+
return bless { config => $config }, $class;
36+
}
37+
38+
sub config {
39+
my ($self) = @_;
40+
return %{ $self->{config} };
41+
}
42+
}
43+
44+
sub mock_config {
45+
my ($config) = @_;
46+
return TestBootstrap::MockConfig->new($config);
47+
}
48+
49+
sub with_mock_config {
50+
my ($config, $code) = @_;
51+
52+
require ConfigServer::Config;
53+
54+
no warnings qw(redefine once);
55+
local *ConfigServer::Config::loadconfig = sub {
56+
return TestBootstrap::MockConfig->new($config);
57+
};
58+
59+
return $code->();
60+
}
61+
62+
sub reload_module_with_config {
63+
my ($module, $config, %opts) = @_;
64+
65+
require ConfigServer::Config;
66+
67+
no warnings qw(redefine once);
68+
local *ConfigServer::Config::loadconfig = sub {
69+
return TestBootstrap::MockConfig->new($config);
70+
};
71+
72+
my $path = $module;
73+
$path =~ s{::}{/}g;
74+
$path .= '.pm';
75+
delete $INC{$path};
76+
77+
for my $extra (@{ $opts{also_delete} || [] }) {
78+
my $ep = $extra;
79+
$ep =~ s{::}{/}g;
80+
$ep .= '.pm';
81+
delete $INC{$ep};
82+
}
83+
84+
eval "require $module; 1" or die $@;
85+
return 1;
86+
}
87+
2688
1;

.github/tests/unit/abuseip.t

Lines changed: 4 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -11,35 +11,6 @@ use lib "$Bin/../lib";
1111

1212
use TestBootstrap ();
1313

14-
{
15-
package Local::AbuseIPConfig;
16-
17-
sub new {
18-
my ($class, $config) = @_;
19-
return bless { config => $config }, $class;
20-
}
21-
22-
sub config {
23-
my ($self) = @_;
24-
return %{ $self->{config} };
25-
}
26-
}
27-
28-
sub reload_abuseip_module {
29-
my ($config) = @_;
30-
31-
require ConfigServer::Config;
32-
33-
no warnings qw(redefine once);
34-
local *ConfigServer::Config::loadconfig = sub {
35-
return Local::AbuseIPConfig->new($config);
36-
};
37-
38-
delete $INC{'ConfigServer/AbuseIP.pm'};
39-
require ConfigServer::AbuseIP;
40-
return 1;
41-
}
42-
4314
sub build_fake_host_binary {
4415
my ($dir, %opts) = @_;
4516

@@ -85,7 +56,7 @@ subtest 'abuseip resolves an IPv4 abuse contact and builds the human message' =>
8556
output => qq{$lookup has TXT record "abuse\@example.test"\n},
8657
);
8758

88-
reload_abuseip_module({ HOST => $host_bin });
59+
TestBootstrap::reload_module_with_config('ConfigServer::AbuseIP',{ HOST => $host_bin });
8960
my ($contact, $message) = ConfigServer::AbuseIP::abuseip('192.0.2.10');
9061

9162
is($contact, 'abuse@example.test', 'IPv4 lookup returns the TXT contact value');
@@ -106,7 +77,7 @@ subtest 'abuseip resolves an IPv6 abuse contact' => sub {
10677
output => qq{$lookup has TXT record "ipv6-contact\@example.test"\n},
10778
);
10879

109-
reload_abuseip_module({ HOST => $host_bin });
80+
TestBootstrap::reload_module_with_config('ConfigServer::AbuseIP',{ HOST => $host_bin });
11081
my ($contact, $message) = ConfigServer::AbuseIP::abuseip('2001:db8::20');
11182

11283
is($contact, 'ipv6-contact@example.test', 'IPv6 lookup returns the TXT contact value');
@@ -125,7 +96,7 @@ subtest 'abuseip returns nothing for invalid input and skips the host lookup ent
12596
output => qq{should not be used\n},
12697
);
12798

128-
reload_abuseip_module({ HOST => $host_bin });
99+
TestBootstrap::reload_module_with_config('ConfigServer::AbuseIP',{ HOST => $host_bin });
129100
my $result = ConfigServer::AbuseIP::abuseip('not-an-ip');
130101

131102
ok(!$result, 'invalid input returns a false value');
@@ -140,7 +111,7 @@ subtest 'abuseip returns nothing when the lookup output contains no quoted conta
140111
output => qq{$lookup lookup failed\n},
141112
);
142113

143-
reload_abuseip_module({ HOST => $host_bin });
114+
TestBootstrap::reload_module_with_config('ConfigServer::AbuseIP',{ HOST => $host_bin });
144115
my $result = ConfigServer::AbuseIP::abuseip('192.0.2.10');
145116

146117
ok(!$result, 'missing TXT contact produces a false value');

.github/tests/unit/getips.t

Lines changed: 3 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -11,35 +11,6 @@ use lib "$Bin/../lib";
1111

1212
use TestBootstrap ();
1313

14-
{
15-
package Local::GetIPsConfig;
16-
17-
sub new {
18-
my ($class, $config) = @_;
19-
return bless { config => $config }, $class;
20-
}
21-
22-
sub config {
23-
my ($self) = @_;
24-
return %{ $self->{config} };
25-
}
26-
}
27-
28-
sub reload_getips_module {
29-
my ($config) = @_;
30-
31-
require ConfigServer::Config;
32-
33-
no warnings qw(redefine once);
34-
local *ConfigServer::Config::loadconfig = sub {
35-
return Local::GetIPsConfig->new($config);
36-
};
37-
38-
delete $INC{'ConfigServer/GetIPs.pm'};
39-
require ConfigServer::GetIPs;
40-
return 1;
41-
}
42-
4314
sub build_fake_host_binary {
4415
my ($dir, %opts) = @_;
4516

@@ -88,7 +59,7 @@ this line contains no address
8859
OUT
8960
);
9061

91-
reload_getips_module({ HOST => $host_bin });
62+
TestBootstrap::reload_module_with_config('ConfigServer::GetIPs',{ HOST => $host_bin });
9263
my @ips = ConfigServer::GetIPs::getips('example.test');
9364

9465
is_deeply(
@@ -114,14 +85,14 @@ example.test is unreachable
11485
OUT
11586
);
11687

117-
reload_getips_module({ HOST => $host_bin });
88+
TestBootstrap::reload_module_with_config('ConfigServer::GetIPs',{ HOST => $host_bin });
11889
my @ips = ConfigServer::GetIPs::getips('example.test');
11990

12091
is_deeply(\@ips, [], 'non-address output produces no results');
12192
};
12293

12394
subtest 'getips falls back to local resolver logic when no host binary is available' => sub {
124-
reload_getips_module({ HOST => '/definitely/missing/host-binary' });
95+
TestBootstrap::reload_module_with_config('ConfigServer::GetIPs',{ HOST => '/definitely/missing/host-binary' });
12596
my @ips = ConfigServer::GetIPs::getips('localhost');
12697

12798
ok(@ips >= 1, 'resolver fallback returns at least one address for localhost');

.github/tests/unit/killssh.t

Lines changed: 16 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -13,33 +13,9 @@ use lib "$Bin/../lib";
1313

1414
use TestBootstrap ();
1515

16-
{
17-
package Local::KillSSHConfig;
1816

19-
sub new {
20-
my ($class, $config) = @_;
21-
return bless { config => $config }, $class;
22-
}
23-
24-
sub config {
25-
my ($self) = @_;
26-
return %{ $self->{config} };
27-
}
28-
}
29-
30-
sub reload_killssh_module {
31-
require ConfigServer::Config;
3217

33-
no warnings qw(redefine once);
34-
local *ConfigServer::Config::loadconfig = sub {
35-
return Local::KillSSHConfig->new({ SYSLOG => 0 });
36-
};
3718

38-
delete $INC{'ConfigServer/Logger.pm'};
39-
delete $INC{'ConfigServer/KillSSH.pm'};
40-
require ConfigServer::KillSSH;
41-
return 1;
42-
}
4319

4420
sub write_text_file {
4521
my ($path, $content) = @_;
@@ -120,7 +96,10 @@ sub with_mock_proc_root {
12096
}
12197

12298
subtest 'hex2ip decodes proc-style IPv4 and IPv6 socket addresses' => sub {
123-
reload_killssh_module();
99+
TestBootstrap::reload_module_with_config(
100+
'ConfigServer::KillSSH', { SYSLOG => 0 },
101+
also_delete => ['ConfigServer::Logger'],
102+
);
124103

125104
is(
126105
ConfigServer::KillSSH::hex2ip('0100007F'),
@@ -136,7 +115,10 @@ subtest 'hex2ip decodes proc-style IPv4 and IPv6 socket addresses' => sub {
136115
};
137116

138117
subtest 'find returns immediately when the target IP or ports list is empty' => sub {
139-
reload_killssh_module();
118+
TestBootstrap::reload_module_with_config(
119+
'ConfigServer::KillSSH', { SYSLOG => 0 },
120+
also_delete => ['ConfigServer::Logger'],
121+
);
140122

141123
my @killed;
142124
my @logs;
@@ -184,7 +166,10 @@ EOF
184166
},
185167
],
186168
code => sub {
187-
reload_killssh_module();
169+
TestBootstrap::reload_module_with_config(
170+
'ConfigServer::KillSSH', { SYSLOG => 0 },
171+
also_delete => ['ConfigServer::Logger'],
172+
);
188173
local *ConfigServer::Logger::logfile = sub { push @logs, @_ };
189174

190175
is(
@@ -225,7 +210,10 @@ EOF
225210
},
226211
],
227212
code => sub {
228-
reload_killssh_module();
213+
TestBootstrap::reload_module_with_config(
214+
'ConfigServer::KillSSH', { SYSLOG => 0 },
215+
also_delete => ['ConfigServer::Logger'],
216+
);
229217
local *ConfigServer::Logger::logfile = sub { push @logs, @_ };
230218
ConfigServer::KillSSH::find('203.0.113.10', '22');
231219
},

.github/tests/unit/ports.t

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10,33 +10,9 @@ use lib "$Bin/../lib";
1010
use TestBootstrap ();
1111
use ConfigServer::Ports ();
1212

13-
{
14-
package Local::PortsConfig;
15-
16-
sub new {
17-
my ($class, $config) = @_;
18-
return bless { config => $config }, $class;
19-
}
20-
21-
sub config {
22-
my ($self) = @_;
23-
return %{ $self->{config} };
24-
}
25-
}
26-
27-
sub with_mock_config {
28-
my ($config, $code) = @_;
29-
30-
no warnings qw(redefine once);
31-
local *ConfigServer::Config::loadconfig = sub {
32-
return Local::PortsConfig->new($config);
33-
};
34-
35-
return $code->();
36-
}
3713

3814
subtest 'openports expands configured port lists across all protocol families' => sub {
39-
my %ports = with_mock_config(
15+
my %ports = TestBootstrap::with_mock_config(
4016
{
4117
TCP_IN => '22,80,3000:3002',
4218
TCP6_IN => '443,8443:8444',
@@ -72,7 +48,7 @@ subtest 'openports expands configured port lists across all protocol families' =
7248
};
7349

7450
subtest 'openports strips whitespace, skips empty entries, and de-duplicates overlaps' => sub {
75-
my %ports = with_mock_config(
51+
my %ports = TestBootstrap::with_mock_config(
7652
{
7753
TCP_IN => ' 22 , , 80 , 80 , 1000:1002 , 1002 ',
7854
TCP6_IN => ' , 443 , , ',

0 commit comments

Comments
 (0)