mirror of
https://github.com/xcat2/xcat-core.git
synced 2026-09-04 20:17:55 +00:00
test(networkutils): cover shared IP address validation
This commit is contained in:
Executable
+112
@@ -0,0 +1,112 @@
|
||||
#!/usr/bin/env perl
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use File::Spec;
|
||||
use FindBin;
|
||||
use Test::More;
|
||||
|
||||
my $repo_root = $ENV{XCAT_REPO_ROOT}
|
||||
|| File::Spec->catdir( $FindBin::Bin, '..', '..' );
|
||||
unshift @INC, File::Spec->catdir( $repo_root, 'perl-xCAT' );
|
||||
require xCAT::NetworkUtils;
|
||||
|
||||
subtest 'isIpv4addr accepts host addresses' => sub {
|
||||
my @accepted = qw(10.0.0.1 192.168.0.1 172.16.254.10 255.255.255.255);
|
||||
foreach my $address (@accepted) {
|
||||
ok( xCAT::NetworkUtils->isIpv4addr($address), "$address is accepted" );
|
||||
}
|
||||
ok( xCAT::NetworkUtils::isIpv4addr('10.0.0.1'),
|
||||
'the function form works without a class argument' );
|
||||
ok( xCAT::NetworkUtils->isIpaddr('10.0.0.1'),
|
||||
'the deprecated isIpaddr alias still answers' );
|
||||
ok( !xCAT::NetworkUtils->isIpaddr('fe80::1'),
|
||||
'the alias keeps the strict IPv4 contract' );
|
||||
};
|
||||
|
||||
subtest 'isIpv4addr rejects invalid or ambiguous forms' => sub {
|
||||
my @rejected = (
|
||||
[ '192.168.001.010', 'leading-zero octets are octal to some resolvers' ],
|
||||
[ '0.1.2.3', 'a host address cannot start with zero' ],
|
||||
[ '0.0.0.0', 'all-zero is a call-site policy, not a host address' ],
|
||||
[ '256.1.1.1', 'octet above 255' ],
|
||||
[ '1.2.3', 'three-part form' ],
|
||||
[ '1.2.3.4.5', 'five-part form' ],
|
||||
[ 'fe80::1', 'IPv6 is outside the IPv4 contract' ],
|
||||
[ 'bmc.example.test', 'hostnames are not addresses' ],
|
||||
[ '', 'empty value' ],
|
||||
);
|
||||
foreach my $case (@rejected) {
|
||||
my ( $value, $reason ) = @{$case};
|
||||
ok( !xCAT::NetworkUtils->isIpv4addr($value), "'$value' is rejected: $reason" );
|
||||
}
|
||||
ok( !xCAT::NetworkUtils->isIpv4addr(undef), 'undef is rejected' );
|
||||
};
|
||||
|
||||
subtest 'isIpv6addr validates IPv6 syntax' => sub {
|
||||
my @accepted = ( 'fe80::1', '::1', '::', '2001:db8::1', '::ffff:10.1.1.1' );
|
||||
foreach my $address (@accepted) {
|
||||
ok( xCAT::NetworkUtils->isIpv6addr($address), "$address is accepted" );
|
||||
}
|
||||
my @rejected = (
|
||||
[ 'not:an:ip', 'colon text is not an address' ],
|
||||
[ ':::::', 'malformed compression' ],
|
||||
[ 'fe80::zzzz', 'invalid hex digits' ],
|
||||
[ 'fe80::1%eth0', 'zone identifiers are platform-dependent and rejected' ],
|
||||
[ '10.0.0.1', 'IPv4 is outside the IPv6 contract' ],
|
||||
[ '', 'empty value' ],
|
||||
);
|
||||
foreach my $case (@rejected) {
|
||||
my ( $value, $reason ) = @{$case};
|
||||
ok( !xCAT::NetworkUtils->isIpv6addr($value), "'$value' is rejected: $reason" );
|
||||
}
|
||||
ok( !xCAT::NetworkUtils->isIpv6addr(undef), 'undef is rejected' );
|
||||
ok( xCAT::NetworkUtils::isIpv6addr('::1'),
|
||||
'the function form works without a class argument' );
|
||||
};
|
||||
|
||||
sub socket6_fallback_ok {
|
||||
ok( !defined &Socket::inet_pton, 'core inet_pton is absent' );
|
||||
ok( xCAT::NetworkUtils->isIpv6addr('2001:db8::1'),
|
||||
'a valid IPv6 address is accepted through Socket6' );
|
||||
ok( !xCAT::NetworkUtils->isIpv6addr('fe80::zzzz'),
|
||||
'an invalid IPv6 address is still rejected through Socket6' );
|
||||
return;
|
||||
}
|
||||
|
||||
subtest 'isIpv6addr falls back to Socket6 without core inet_pton' => sub {
|
||||
no warnings qw(once redefine);
|
||||
if ( defined &Socket6::inet_pton ) {
|
||||
local *Socket::inet_pton;
|
||||
socket6_fallback_ok();
|
||||
return;
|
||||
}
|
||||
plan skip_all => 'neither core inet_pton nor Socket6 is available'
|
||||
unless defined &Socket::inet_pton;
|
||||
|
||||
# lend the core implementation to Socket6 so the fallback path runs
|
||||
# where Socket6 is not installed
|
||||
my $core_pton = \&Socket::inet_pton;
|
||||
my $af6 = Socket::AF_INET6();
|
||||
local *Socket6::inet_pton = sub { return $core_pton->(@_) };
|
||||
local *Socket6::AF_INET6 = sub { return $af6 };
|
||||
local *Socket::inet_pton;
|
||||
socket6_fallback_ok();
|
||||
};
|
||||
|
||||
subtest 'isValidIp accepts both families and nothing else' => sub {
|
||||
ok( xCAT::NetworkUtils->isValidIp('10.0.0.1'), 'IPv4 delegates to isIpv4addr' );
|
||||
ok( xCAT::NetworkUtils->isValidIp('fe80::1'), 'IPv6 delegates to isIpv6addr' );
|
||||
my @rejected = (
|
||||
'not:an:ip', 'fe80::1%eth0', '192.168.001.010', '0.0.0.0',
|
||||
'bmc.example.test', '',
|
||||
);
|
||||
foreach my $value (@rejected) {
|
||||
ok( !xCAT::NetworkUtils->isValidIp($value), "'$value' is rejected" );
|
||||
}
|
||||
ok( !xCAT::NetworkUtils->isValidIp(undef), 'undef is rejected' );
|
||||
ok( xCAT::NetworkUtils::isValidIp('10.0.0.1'),
|
||||
'the function form works without a class argument' );
|
||||
};
|
||||
|
||||
done_testing();
|
||||
Reference in New Issue
Block a user