Merge pull request #740 from rhansen/recap

Overhaul recap handling
This commit is contained in:
Richard Hansen 2024-09-02 03:59:15 -04:00 committed by GitHub
commit a7abfcb715
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 1068 additions and 837 deletions

View file

@ -100,6 +100,8 @@ repository history](https://github.com/ddclient/ddclient/commits/master).
### Bug fixes ### Bug fixes
* Fixed numerous bugs in cache file (recap) handling.
[#740](https://github.com/ddclient/ddclient/pull/740)
* Fixed numerous bugs in command-line option and configuration file * Fixed numerous bugs in command-line option and configuration file
processing. [#733](https://github.com/ddclient/ddclient/pull/733) processing. [#733](https://github.com/ddclient/ddclient/pull/733)
* `noip`: Fixed failure to honor IP discovery settings in some circumstances. * `noip`: Fixed failure to honor IP discovery settings in some circumstances.

View file

@ -78,6 +78,7 @@ handwritten_tests = \
t/protocol_directnic.pl \ t/protocol_directnic.pl \
t/protocol_dnsexit2.pl \ t/protocol_dnsexit2.pl \
t/protocol_dyndns2.pl \ t/protocol_dyndns2.pl \
t/read_recap.pl \
t/skip.pl \ t/skip.pl \
t/ssl-validate.pl \ t/ssl-validate.pl \
t/update_nics.pl \ t/update_nics.pl \

View file

@ -78,6 +78,7 @@ m4_foreach_w([_m], [
File::Spec::Functions File::Spec::Functions
File::Temp File::Temp
List::Util List::Util
Scalar::Util
re re
], [AX_PROG_PERL_MODULES([_m], [], ], [AX_PROG_PERL_MODULES([_m], [],
[AC_MSG_WARN([some tests will fail due to missing module _m])])]) [AC_MSG_WARN([some tests will fail due to missing module _m])])])
@ -95,7 +96,6 @@ m4_foreach_w([_m], [
HTTP::Response HTTP::Response
JSON::PP JSON::PP
LWP::UserAgent LWP::UserAgent
Scalar::Util
Test::MockModule Test::MockModule
Test::TCP Test::TCP
Test::Warnings Test::Warnings

File diff suppressed because it is too large Load diff

View file

@ -52,7 +52,7 @@ my @test_cases = (
{ {
desc => 'IPv4, good', desc => 'IPv4, good',
cfg => {h1 => {urlv4 => "$hostname/dns/gateway/abc/", wantipv4 => '192.0.2.1'}}, cfg => {h1 => {urlv4 => "$hostname/dns/gateway/abc/", wantipv4 => '192.0.2.1'}},
wantstatus => { wantrecap => {
h1 => {'status-ipv4' => 'good', 'ipv4' => '192.0.2.1', 'mtime' => $ddclient::now}, h1 => {'status-ipv4' => 'good', 'ipv4' => '192.0.2.1', 'mtime' => $ddclient::now},
}, },
wantlogs => [ wantlogs => [
@ -62,7 +62,7 @@ my @test_cases = (
{ {
desc => 'IPv4, failed', desc => 'IPv4, failed',
cfg => {h1 => {urlv4 => "$hostname/dns/gateway/bad_token/", wantipv4 => '192.0.2.1'}}, cfg => {h1 => {urlv4 => "$hostname/dns/gateway/bad_token/", wantipv4 => '192.0.2.1'}},
wantstatus => { wantrecap => {
h1 => {'status-ipv4' => 'failed'}, h1 => {'status-ipv4' => 'failed'},
}, },
wantlogs => [ wantlogs => [
@ -72,7 +72,7 @@ my @test_cases = (
{ {
desc => 'IPv4, bad', desc => 'IPv4, bad',
cfg => {h1 => {urlv4 => "$hostname/bad/path/", wantipv4 => '192.0.2.1'}}, cfg => {h1 => {urlv4 => "$hostname/bad/path/", wantipv4 => '192.0.2.1'}},
wantstatus => { wantrecap => {
h1 => {'status-ipv4' => 'bad'}, h1 => {'status-ipv4' => 'bad'},
}, },
wantlogs => [ wantlogs => [
@ -82,7 +82,7 @@ my @test_cases = (
{ {
desc => 'IPv4, unexpected response', desc => 'IPv4, unexpected response',
cfg => {h1 => {urlv4 => "$hostname/unexpected/path/", wantipv4 => '192.0.2.1'}}, cfg => {h1 => {urlv4 => "$hostname/unexpected/path/", wantipv4 => '192.0.2.1'}},
wantstatus => {h1 => {}}, wantrecap => {},
wantlogs => [ wantlogs => [
{label => 'FAILED', ctx => ['h1'], msg => qr/400 Bad Request/}, {label => 'FAILED', ctx => ['h1'], msg => qr/400 Bad Request/},
], ],
@ -90,7 +90,7 @@ my @test_cases = (
{ {
desc => 'IPv4, no urlv4', desc => 'IPv4, no urlv4',
cfg => {h1 => {wantipv4 => '192.0.2.1'}}, cfg => {h1 => {wantipv4 => '192.0.2.1'}},
wantstatus => {h1 => {}}, wantrecap => {},
wantlogs => [ wantlogs => [
{label => 'FAILED', ctx => ['h1'], msg => qr/missing urlv4 option/}, {label => 'FAILED', ctx => ['h1'], msg => qr/missing urlv4 option/},
], ],
@ -98,7 +98,7 @@ my @test_cases = (
{ {
desc => 'IPv6, good', desc => 'IPv6, good',
cfg => {h1 => {urlv6 => "$hostname/dns/gateway/abc/", wantipv6 => '2001:db8::1'}}, cfg => {h1 => {urlv6 => "$hostname/dns/gateway/abc/", wantipv6 => '2001:db8::1'}},
wantstatus => { wantrecap => {
h1 => {'status-ipv6' => 'good', 'ipv6' => '2001:db8::1', 'mtime' => $ddclient::now}, h1 => {'status-ipv6' => 'good', 'ipv6' => '2001:db8::1', 'mtime' => $ddclient::now},
}, },
wantlogs => [ wantlogs => [
@ -113,7 +113,7 @@ my @test_cases = (
wantipv4 => '192.0.2.1', wantipv4 => '192.0.2.1',
wantipv6 => '2001:db8::1', wantipv6 => '2001:db8::1',
}}, }},
wantstatus => { wantrecap => {
h1 => {'status-ipv4' => 'good', 'ipv4' => '192.0.2.1', h1 => {'status-ipv4' => 'good', 'ipv4' => '192.0.2.1',
'status-ipv6' => 'good', 'ipv6' => '2001:db8::1', 'status-ipv6' => 'good', 'ipv6' => '2001:db8::1',
'mtime' => $ddclient::now}, 'mtime' => $ddclient::now},
@ -132,7 +132,7 @@ my @test_cases = (
wantipv6 => '2001:db8::1', wantipv6 => '2001:db8::1',
}}, }},
wantips => {h1 => {wantipv4 => '192.0.2.1', wantipv6 => '2001:db8::1'}}, wantips => {h1 => {wantipv4 => '192.0.2.1', wantipv6 => '2001:db8::1'}},
wantstatus => { wantrecap => {
h1 => {'status-ipv4' => 'failed', h1 => {'status-ipv4' => 'failed',
'status-ipv6' => 'good', 'ipv6' => '2001:db8::1', 'status-ipv6' => 'good', 'ipv6' => '2001:db8::1',
'mtime' => $ddclient::now}, 'mtime' => $ddclient::now},
@ -152,20 +152,14 @@ for my $tc (@test_cases) {
local $ddclient::globals{verbose} = 1; local $ddclient::globals{verbose} = 1;
my $l = Logger->new($ddclient::_l); my $l = Logger->new($ddclient::_l);
local %ddclient::config = %{$tc->{cfg}}; local %ddclient::config = %{$tc->{cfg}};
local %ddclient::recap;
{ {
local $ddclient::_l = $l; local $ddclient::_l = $l;
ddclient::nic_directnic_update(sort(keys(%{$tc->{cfg}}))); ddclient::nic_directnic_update(undef, sort(keys(%{$tc->{cfg}})));
} }
# These are the properties in %ddclient::config to check against $tc->{wantstatus}. is_deeply(\%ddclient::recap, $tc->{wantrecap}, "$tc->{desc}: recap")
my %statuskeys = map(($_ => undef), qw(atime ip ipv4 ipv6 mtime status status-ipv4 status-ipv6 or diag(ddclient::repr(Values => [\%ddclient::recap, $tc->{wantrecap}],
wantip wantipv4 wantipv6 wtime)); Names => ['*got', '*want']));
my %gotstatus;
for my $h (keys(%ddclient::config)) {
$gotstatus{$h} = {map(($_ => $ddclient::config{$h}{$_}),
grep(exists($statuskeys{$_}), keys(%{$ddclient::config{$h}})))};
}
is_deeply(\%gotstatus, $tc->{wantstatus}, "$tc->{desc}: status")
or diag(ddclient::repr(\%ddclient::config, Names => ['*ddclient::config']));
$tc->{wantlogs} //= []; $tc->{wantlogs} //= [];
subtest("$tc->{desc}: logs" => sub { subtest("$tc->{desc}: logs" => sub {
my @got = @{$l->{logs}}; my @got = @{$l->{logs}};

View file

@ -41,7 +41,7 @@ my $ua = LWP::UserAgent->new;
sub test_nic_dnsexit2_update { sub test_nic_dnsexit2_update {
my ($config, @hostnames) = @_; my ($config, @hostnames) = @_;
%ddclient::config = %$config; %ddclient::config = %$config;
ddclient::nic_dnsexit2_update(@hostnames); ddclient::nic_dnsexit2_update(undef, @hostnames);
} }
sub decode_and_sort_array { sub decode_and_sort_array {

View file

@ -45,7 +45,7 @@ my @test_cases = (
cfg => {h1 => {wantipv4 => '192.0.2.1'}}, cfg => {h1 => {wantipv4 => '192.0.2.1'}},
resp => ['good'], resp => ['good'],
wantquery => 'hostname=h1&myip=192.0.2.1', wantquery => 'hostname=h1&myip=192.0.2.1',
wantstatus => { wantrecap => {
h1 => {'status-ipv4' => 'good', 'ipv4' => '192.0.2.1', 'mtime' => $ddclient::now}, h1 => {'status-ipv4' => 'good', 'ipv4' => '192.0.2.1', 'mtime' => $ddclient::now},
}, },
wantlogs => [ wantlogs => [
@ -57,7 +57,7 @@ my @test_cases = (
cfg => {h1 => {wantipv4 => '192.0.2.1'}}, cfg => {h1 => {wantipv4 => '192.0.2.1'}},
resp => ['nochg'], resp => ['nochg'],
wantquery => 'hostname=h1&myip=192.0.2.1', wantquery => 'hostname=h1&myip=192.0.2.1',
wantstatus => { wantrecap => {
h1 => {'status-ipv4' => 'good', 'ipv4' => '192.0.2.1', 'mtime' => $ddclient::now}, h1 => {'status-ipv4' => 'good', 'ipv4' => '192.0.2.1', 'mtime' => $ddclient::now},
}, },
wantlogs => [ wantlogs => [
@ -70,7 +70,7 @@ my @test_cases = (
cfg => {h1 => {wantipv4 => '192.0.2.1'}}, cfg => {h1 => {wantipv4 => '192.0.2.1'}},
resp => ['nohost'], resp => ['nohost'],
wantquery => 'hostname=h1&myip=192.0.2.1', wantquery => 'hostname=h1&myip=192.0.2.1',
wantstatus => { wantrecap => {
h1 => {'status-ipv4' => 'nohost'}, h1 => {'status-ipv4' => 'nohost'},
}, },
wantlogs => [ wantlogs => [
@ -82,7 +82,7 @@ my @test_cases = (
cfg => {h1 => {wantipv4 => '192.0.2.1'}}, cfg => {h1 => {wantipv4 => '192.0.2.1'}},
resp => ['WAT'], resp => ['WAT'],
wantquery => 'hostname=h1&myip=192.0.2.1', wantquery => 'hostname=h1&myip=192.0.2.1',
wantstatus => { wantrecap => {
h1 => {'status-ipv4' => 'WAT'}, h1 => {'status-ipv4' => 'WAT'},
}, },
wantlogs => [ wantlogs => [
@ -100,7 +100,7 @@ my @test_cases = (
'good', 'good',
], ],
wantquery => 'hostname=h1,h2&myip=192.0.2.1', wantquery => 'hostname=h1,h2&myip=192.0.2.1',
wantstatus => { wantrecap => {
h1 => {'status-ipv4' => 'good', 'ipv4' => '192.0.2.1', 'mtime' => $ddclient::now}, h1 => {'status-ipv4' => 'good', 'ipv4' => '192.0.2.1', 'mtime' => $ddclient::now},
h2 => {'status-ipv4' => 'good', 'ipv4' => '192.0.2.1', 'mtime' => $ddclient::now}, h2 => {'status-ipv4' => 'good', 'ipv4' => '192.0.2.1', 'mtime' => $ddclient::now},
}, },
@ -122,7 +122,7 @@ my @test_cases = (
'dnserr', 'dnserr',
], ],
wantquery => 'hostname=h1,h2,h3&myip=192.0.2.1', wantquery => 'hostname=h1,h2,h3&myip=192.0.2.1',
wantstatus => { wantrecap => {
h1 => {'status-ipv4' => 'good', 'ipv4' => '192.0.2.1', 'mtime' => $ddclient::now}, h1 => {'status-ipv4' => 'good', 'ipv4' => '192.0.2.1', 'mtime' => $ddclient::now},
h2 => {'status-ipv4' => 'good', 'ipv4' => '192.0.2.1', 'mtime' => $ddclient::now}, h2 => {'status-ipv4' => 'good', 'ipv4' => '192.0.2.1', 'mtime' => $ddclient::now},
h3 => {'status-ipv4' => 'dnserr'}, h3 => {'status-ipv4' => 'dnserr'},
@ -139,7 +139,7 @@ my @test_cases = (
cfg => {h1 => {wantipv6 => '2001:db8::1'}}, cfg => {h1 => {wantipv6 => '2001:db8::1'}},
resp => ['good'], resp => ['good'],
wantquery => 'hostname=h1&myip=2001:db8::1', wantquery => 'hostname=h1&myip=2001:db8::1',
wantstatus => { wantrecap => {
h1 => {'status-ipv6' => 'good', 'ipv6' => '2001:db8::1', 'mtime' => $ddclient::now}, h1 => {'status-ipv6' => 'good', 'ipv6' => '2001:db8::1', 'mtime' => $ddclient::now},
}, },
wantlogs => [ wantlogs => [
@ -151,7 +151,7 @@ my @test_cases = (
cfg => {h1 => {wantipv4 => '192.0.2.1', wantipv6 => '2001:db8::1'}}, cfg => {h1 => {wantipv4 => '192.0.2.1', wantipv6 => '2001:db8::1'}},
resp => ['good'], resp => ['good'],
wantquery => 'hostname=h1&myip=192.0.2.1,2001:db8::1', wantquery => 'hostname=h1&myip=192.0.2.1,2001:db8::1',
wantstatus => { wantrecap => {
h1 => {'status-ipv4' => 'good', 'ipv4' => '192.0.2.1', h1 => {'status-ipv4' => 'good', 'ipv4' => '192.0.2.1',
'status-ipv6' => 'good', 'ipv6' => '2001:db8::1', 'status-ipv6' => 'good', 'ipv6' => '2001:db8::1',
'mtime' => $ddclient::now}, 'mtime' => $ddclient::now},
@ -173,7 +173,7 @@ my @test_cases = (
'WAT', 'WAT',
], ],
wantquery => 'hostname=h1,h2&myip=192.0.2.1', wantquery => 'hostname=h1,h2&myip=192.0.2.1',
wantstatus => { wantrecap => {
h1 => {'status-ipv4' => 'good', 'ipv4' => '192.0.2.1', 'mtime' => $ddclient::now}, h1 => {'status-ipv4' => 'good', 'ipv4' => '192.0.2.1', 'mtime' => $ddclient::now},
h2 => {'status-ipv4' => 'good', 'ipv4' => '192.0.2.1', 'mtime' => $ddclient::now}, h2 => {'status-ipv4' => 'good', 'ipv4' => '192.0.2.1', 'mtime' => $ddclient::now},
}, },
@ -191,7 +191,7 @@ my @test_cases = (
}, },
resp => ['abuse'], resp => ['abuse'],
wantquery => 'hostname=h1,h2&myip=192.0.2.1', wantquery => 'hostname=h1,h2&myip=192.0.2.1',
wantstatus => { wantrecap => {
h1 => {'status-ipv4' => 'abuse'}, h1 => {'status-ipv4' => 'abuse'},
h2 => {'status-ipv4' => 'abuse'}, h2 => {'status-ipv4' => 'abuse'},
}, },
@ -208,7 +208,7 @@ my @test_cases = (
}, },
resp => ['good'], resp => ['good'],
wantquery => 'hostname=h1,h2&myip=192.0.2.1', wantquery => 'hostname=h1,h2&myip=192.0.2.1',
wantstatus => { wantrecap => {
h1 => {'status-ipv4' => 'good', 'ipv4' => '192.0.2.1', 'mtime' => $ddclient::now}, h1 => {'status-ipv4' => 'good', 'ipv4' => '192.0.2.1', 'mtime' => $ddclient::now},
h2 => {'status-ipv4' => 'good', 'ipv4' => '192.0.2.1', 'mtime' => $ddclient::now}, h2 => {'status-ipv4' => 'good', 'ipv4' => '192.0.2.1', 'mtime' => $ddclient::now},
}, },
@ -230,7 +230,7 @@ my @test_cases = (
'nochg', 'nochg',
], ],
wantquery => 'hostname=h1,h2,h3&myip=192.0.2.1', wantquery => 'hostname=h1,h2,h3&myip=192.0.2.1',
wantstatus => { wantrecap => {
h1 => {'status-ipv4' => 'good', 'ipv4' => '192.0.2.1', 'mtime' => $ddclient::now}, h1 => {'status-ipv4' => 'good', 'ipv4' => '192.0.2.1', 'mtime' => $ddclient::now},
h2 => {'status-ipv4' => 'good', 'ipv4' => '192.0.2.1', 'mtime' => $ddclient::now}, h2 => {'status-ipv4' => 'good', 'ipv4' => '192.0.2.1', 'mtime' => $ddclient::now},
h3 => {'status-ipv4' => 'unknown'}, h3 => {'status-ipv4' => 'unknown'},
@ -252,6 +252,7 @@ for my $tc (@test_cases) {
local $ddclient::globals{verbose} = 1; local $ddclient::globals{verbose} = 1;
my $l = Logger->new($ddclient::_l); my $l = Logger->new($ddclient::_l);
local %ddclient::config; local %ddclient::config;
local %ddclient::recap;
$ddclient::config{$_} = { $ddclient::config{$_} = {
login => 'username', login => 'username',
password => 'password', password => 'password',
@ -265,20 +266,11 @@ for my $tc (@test_cases) {
map("line: $_", @{$tc->{resp}}), map("line: $_", @{$tc->{resp}}),
); );
local $ddclient::_l = $l; local $ddclient::_l = $l;
ddclient::nic_dyndns2_update(sort(keys(%{$tc->{cfg}}))); ddclient::nic_dyndns2_update(undef, sort(keys(%{$tc->{cfg}})));
} }
# These are the properties in %ddclient::config to check against $tc->{wantstatus}. Keys are is_deeply(\%ddclient::recap, $tc->{wantrecap}, "$tc->{desc}: recap")
# explicitly listed here rather than read from $tc->{wantstatus} to ensure that entries that or diag(ddclient::repr(Values => [\%ddclient::recap, $tc->{wantrecap}],
# should not exist (e.g., wantipv4 and friends) are deleted (or never set). Names => ['*got', '*want']));
my %statuskeys = map(($_ => undef), qw(atime ip ipv4 ipv6 mtime status status-ipv4 status-ipv6
wantip wantipv4 wantipv6 wtime));
my %gotstatus;
for my $h (keys(%ddclient::config)) {
$gotstatus{$h} = {map(($_ => $ddclient::config{$h}{$_}),
grep(exists($statuskeys{$_}), keys(%{$ddclient::config{$h}})))};
}
is_deeply(\%gotstatus, $tc->{wantstatus}, "$tc->{desc}: status")
or diag(ddclient::repr(\%ddclient::config, Names => ['*ddclient::config']));
$tc->{wantlogs} //= []; $tc->{wantlogs} //= [];
subtest("$tc->{desc}: logs" => sub { subtest("$tc->{desc}: logs" => sub {
my @got = @{$l->{logs}}; my @got = @{$l->{logs}};

107
t/read_recap.pl Normal file
View file

@ -0,0 +1,107 @@
use Test::More;
use File::Temp;
SKIP: { eval { require Test::Warnings; } or skip($@, 1); }
eval { require 'ddclient'; } or BAIL_OUT($@);
local $ddclient::globals{debug} = 1;
local $ddclient::globals{verbose} = 1;
local %ddclient::protocols = (
protocol_a => ddclient::Protocol->new(
recapvars => {
host => ddclient::T_STRING(),
var_a => ddclient::T_BOOL(),
},
),
protocol_b => ddclient::Protocol->new(
recapvars => {
host => ddclient::T_STRING(),
var_b => ddclient::T_NUMBER(),
},
cfgvars => {
var_b_non_recap => {type => ddclient::T_ANY()},
},
),
);
local %ddclient::cfgvars = (merged => {map({ %{$ddclient::protocols{$_}{cfgvars} // {}}; }
sort(keys(%ddclient::protocols)))});
my @test_cases = (
{
desc => "ok value",
cachefile_lines => ["var_a=yes host_a"],
want => {host_a => {host => 'host_a', var_a => 1}},
},
{
desc => "unknown host",
cachefile_lines => ["var_a=yes host_c"],
want => {},
},
{
desc => "unknown var",
cachefile_lines => ["var_b=123 host_a"],
want => {host_a => {host => 'host_a'}},
},
{
desc => "invalid value",
cachefile_lines => ["var_a=wat host_a"],
want => {host_a => {host => 'host_a'}},
},
{
desc => "multiple entries",
cachefile_lines => [
"var_a=yes host_a",
"var_b=123 host_b",
],
want => {
host_a => {host => 'host_a', var_a => 1},
host_b => {host => 'host_b', var_b => 123},
},
},
{
desc => "non-recap vars are not loaded to %recap",
cachefile_lines => ["var_b_non_recap=foo host_b"],
want => {host_b => {host => 'host_b'}},
},
{
desc => "non-recap vars are scrubbed from %recap",
cachefile_lines => ["var_b_non_recap=foo host_b"],
recap => {host_b => {host => 'host_b', var_b_non_recap => 'foo'}},
want => {host_b => {host => 'host_b'}},
},
{
desc => "unknown hosts are scrubbed from %recap",
cachefile_lines => ["host_a", "host_c"],
recap => {host_a => {host => 'host_a'}, host_c => {host => 'host_c'}},
want => {host_a => {host => 'host_a'}},
},
);
for my $tc (@test_cases) {
my $cachef = File::Temp->new();
print($cachef join('', map("$_\n", "## $ddclient::program-$ddclient::version",
@{$tc->{cachefile_lines}})));
$cachef->close();
local $ddclient::globals{cache} = "$cachef";
local %ddclient::recap = %{$tc->{recap} // {}};
my %want_config = (
host_a => {protocol => 'protocol_a'},
host_b => {protocol => 'protocol_b'},
);
# Deep clone %want_config so we can check for changes.
local %ddclient::config;
$ddclient::config{$_} = {%{$want_config{$_}}} for keys(%want_config);
ddclient::read_recap($cachef->filename());
TODO: {
local $TODO = $tc->{want_TODO};
is_deeply(\%ddclient::recap, $tc->{want}, "$tc->{desc}: %recap")
or diag(ddclient::repr(Values => [\%ddclient::recap, $tc->{want}],
Names => ['*got', '*want']));
}
is_deeply(\%ddclient::config, \%want_config, "$tc->{desc}: %config")
or diag(ddclient::repr(Values => [\%ddclient::config, \%want_config],
Names => ['*got', '*want']));
}
done_testing();

View file

@ -47,19 +47,21 @@ local %ddclient::protocols = (
# The `legacy` protocol reads the legacy `wantip` property and sets the legacy `ip` and `status` # The `legacy` protocol reads the legacy `wantip` property and sets the legacy `ip` and `status`
# properties. (Modern protocol implementations read `wantipv4` and `wantipv6` and set `ipv4`, # properties. (Modern protocol implementations read `wantipv4` and `wantipv6` and set `ipv4`,
# `ipv6`, `status-ipv4`, and `status-ipv6`.) It always succeeds. # `ipv6`, `status-ipv4`, and `status-ipv6`.) It always succeeds.
legacy => { legacy => ddclient::LegacyProtocol->new(
update => sub { update => sub {
my $self = shift;
ddclient::debug('in update');
for my $h (@_) { for my $h (@_) {
local $ddclient::_l = ddclient::pushlogctx($h);
ddclient::debug('updating host');
push(@updates, [@_]); push(@updates, [@_]);
$ddclient::config{$h}{status} = 'good'; $ddclient::recap{$h}{status} = 'good';
$ddclient::config{$h}{ip} = delete($ddclient::config{$h}{wantip}); $ddclient::recap{$h}{ip} = delete($ddclient::config{$h}{wantip});
$ddclient::config{$h}{mtime} = $ddclient::now; $ddclient::recap{$h}{mtime} = $ddclient::now;
} }
ddclient::debug('returning from update');
}, },
variables => { ),
%{$ddclient::variables{'protocol-common-defaults'}},
},
},
); );
my @test_cases = ( my @test_cases = (
@ -79,12 +81,6 @@ my @test_cases = (
'mtime' => $ddclient::now, 'mtime' => $ddclient::now,
'status-ipv4' => 'good', 'status-ipv4' => 'good',
}, },
want_cfg_changes => {
'atime' => $ddclient::now,
'ipv4' => '192.0.2.1',
'mtime' => $ddclient::now,
'status-ipv4' => 'good',
},
%$_, %$_,
}; };
} {cfg => {use => 'web'}}, {cfg => {usev4 => 'webv4'}}), } {cfg => {use => 'web'}}, {cfg => {usev4 => 'webv4'}}),
@ -103,12 +99,6 @@ my @test_cases = (
'mtime' => $ddclient::now, 'mtime' => $ddclient::now,
'status-ipv6' => 'good', 'status-ipv6' => 'good',
}, },
want_cfg_changes => {
'atime' => $ddclient::now,
'ipv6' => '2001:db8::1',
'mtime' => $ddclient::now,
'status-ipv6' => 'good',
},
}, },
{ {
desc => 'legacy, fresh, usev6=webv6', desc => 'legacy, fresh, usev6=webv6',
@ -124,12 +114,6 @@ my @test_cases = (
'mtime' => $ddclient::now, 'mtime' => $ddclient::now,
'status-ipv6' => 'good', 'status-ipv6' => 'good',
}, },
want_cfg_changes => {
'atime' => $ddclient::now,
'ipv6' => '2001:db8::1',
'mtime' => $ddclient::now,
'status-ipv6' => 'good',
},
}, },
{ {
desc => 'legacy, fresh, usev4=webv4 usev6=webv6', desc => 'legacy, fresh, usev4=webv4 usev6=webv6',
@ -146,12 +130,6 @@ my @test_cases = (
'mtime' => $ddclient::now, 'mtime' => $ddclient::now,
'status-ipv4' => 'good', 'status-ipv4' => 'good',
}, },
want_cfg_changes => {
'atime' => $ddclient::now,
'ipv4' => '192.0.2.1',
'mtime' => $ddclient::now,
'status-ipv4' => 'good',
},
}, },
map({ map({
my %cfg = %{delete($_->{cfg})}; my %cfg = %{delete($_->{cfg})};
@ -231,11 +209,6 @@ my @test_cases = (
'ipv4' => '192.0.2.1', 'ipv4' => '192.0.2.1',
'mtime' => $ddclient::now, 'mtime' => $ddclient::now,
}, },
want_cfg_changes => {
'atime' => $ddclient::now,
'ipv4' => '192.0.2.1',
'mtime' => $ddclient::now,
},
%$_, %$_,
}; };
} {cfg => {use => 'web'}}, {cfg => {usev4 => 'webv4'}}), } {cfg => {use => 'web'}}, {cfg => {usev4 => 'webv4'}}),
@ -283,12 +256,6 @@ my @test_cases = (
'mtime' => $ddclient::now, 'mtime' => $ddclient::now,
'status-ipv4' => 'good', 'status-ipv4' => 'good',
}, },
want_cfg_changes => {
'atime' => $ddclient::now,
'ipv4' => '192.0.2.1',
'mtime' => $ddclient::now,
'status-ipv4' => 'good',
},
%$_, %$_,
}; };
} {cfg => {use => 'web'}}, {cfg => {usev4 => 'webv4'}}), } {cfg => {use => 'web'}}, {cfg => {usev4 => 'webv4'}}),
@ -307,7 +274,6 @@ for my $tc (@test_cases) {
# $cachef is an object that stringifies to a filename. # $cachef is an object that stringifies to a filename.
local $ddclient::globals{cache} = "$cachef"; local $ddclient::globals{cache} = "$cachef";
my %cfg = ( my %cfg = (
%{$tc->{recap} // {}}, # Simulate a previous update.
web => 'v4', web => 'v4',
webv4 => 'v4', webv4 => 'v4',
webv6 => 'v6', webv6 => 'v6',
@ -335,7 +301,6 @@ for my $tc (@test_cases) {
Names => ['*got', '*want'])); Names => ['*got', '*want']));
} }
my %want_cfg = (host => { my %want_cfg = (host => {
$tc->{want_update} ? (update => 1) : (),
%cfg, %cfg,
%{$tc->{want_cfg_changes} // {}}, %{$tc->{want_cfg_changes} // {}},
}); });

View file

@ -4,8 +4,8 @@ SKIP: { eval { require Test::Warnings; } or skip($@, 1); }
eval { require 'ddclient'; } or BAIL_OUT($@); eval { require 'ddclient'; } or BAIL_OUT($@);
my %variable_collections = ( my %variable_collections = (
map({ ($_ => $ddclient::variables{$_}) } grep($_ ne 'merged', keys(%ddclient::variables))), map({ ($_ => $ddclient::cfgvars{$_}) } grep($_ ne 'merged', keys(%ddclient::cfgvars))),
map({ ("protocol=$_" => $ddclient::protocols{$_}{variables}); } keys(%ddclient::protocols)), map({ ("protocol=$_" => $ddclient::protocols{$_}{cfgvars}); } keys(%ddclient::protocols)),
); );
my %seen; my %seen;
my @test_cases = ( my @test_cases = (
@ -24,10 +24,10 @@ for my $tc (@test_cases) {
if ($tc->{def}{required}) { if ($tc->{def}{required}) {
is($tc->{def}{default}, undef, "'$tc->{desc}' (required) has no default"); is($tc->{def}{default}, undef, "'$tc->{desc}' (required) has no default");
} else { } else {
# Preserve all existing variables in $variables{merged} so that variables with dynamic # Preserve all existing variables in $cfgvars{merged} so that variables with dynamic
# defaults can reference them. # defaults can reference them.
local %ddclient::variables = (merged => { local %ddclient::cfgvars = (merged => {
%{$ddclient::variables{merged}}, %{$ddclient::cfgvars{merged}},
'var for test' => $tc->{def}, 'var for test' => $tc->{def},
}); });
# Variables with dynamic defaults will need their own unit tests, but we can still check the # Variables with dynamic defaults will need their own unit tests, but we can still check the
@ -77,13 +77,12 @@ my @use_test_cases = (
); );
for my $tc (@use_test_cases) { for my $tc (@use_test_cases) {
my $desc = "'use' dynamic default: $tc->{desc}"; my $desc = "'use' dynamic default: $tc->{desc}";
local %ddclient::protocols = local %ddclient::protocols = (protocol => ddclient::Protocol->new());
(protocol => {variables => $ddclient::variables{'protocol-common-defaults'}}); local %ddclient::cfgvars = (merged => {
local %ddclient::variables = (merged => { 'protocol' => $ddclient::cfgvars{'merged'}{'protocol'},
'protocol' => $ddclient::variables{'merged'}{'protocol'}, 'use' => $ddclient::cfgvars{'protocol-common-defaults'}{'use'},
'use' => $ddclient::variables{'protocol-common-defaults'}{'use'}, 'usev4' => $ddclient::cfgvars{'merged'}{'usev4'},
'usev4' => $ddclient::variables{'merged'}{'usev4'}, 'usev6' => $ddclient::cfgvars{'merged'}{'usev6'},
'usev6' => $ddclient::variables{'merged'}{'usev6'},
}); });
local %ddclient::config = (host => {protocol => 'protocol', %{$tc->{cfg} // {}}}); local %ddclient::config = (host => {protocol => 'protocol', %{$tc->{cfg} // {}}});
local %ddclient::opt; local %ddclient::opt;