ClamAV-Clamd
view release on metacpan or search on metacpan
t/70-async.t view on Meta::CPAN
next if length($p) >= ClamAV::Clamd::_sun_path_max();
$sock = $p; last;
}
}
unless ($sock) { done_testing; exit 0 }
my $c = ClamAV::Clamd->new(socket => $sock);
unless ($c->ping) { done_testing; exit 0 }
my $EICAR = 'X5O!P%@AP[4\PZX54(P^)7CC)7}' . '$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*';
sub write_file {
my ($n, $b) = @_;
my $p = "$dir/$n";
open my $fh, '>:raw', $p or die $!;
print {$fh} $b;
close $fh;
return $p;
}
my $eicar = write_file('e.txt', $EICAR);
my $clean = write_file('c.txt', 'nothing to see');
# --- THE GATE -----------------------------------------------------------
# The same scan, driven three ways, must give the same verdict. If the
# blocking and non-blocking paths can disagree then one of them is a
# second implementation of the protocol, which is exactly what this phase
# exists to prevent.
for my $case ([$eicar, 'infected'], [$clean, 'clean']) {
my ($path, $want) = @$case;
my $name = $path =~ /e\.txt/ ? 'eicar' : 'clean';
my $blocking = $c->scan_path($path);
is $blocking->state, $want, "$name: blocking gives $want";
my $async = $c->start_scan($path, 'path');
drive($async);
is $async->verdict->state, $want, "$name: driven under select gives $want";
is $async->verdict->signature, $blocking->signature,
"$name: and the same signature";
}
# --- interleaved, in one process ----------------------------------------
# Two scans in flight at once, stepped alternately. Nothing may leak from
# one connection into the other - the failure this would show up as is a
# scan reporting the OTHER scan's verdict.
{
my @scans = (
$c->start_scan($eicar, 'path'),
$c->start_scan($clean, 'path'),
$c->start_scan($EICAR),
$c->start_scan('harmless bytes'),
);
drive(@scans);
is $scans[0]->verdict->state, 'infected', 'interleaved scan 1: infected';
is $scans[1]->verdict->state, 'clean', 'interleaved scan 2: clean';
is $scans[2]->verdict->state, 'infected', 'interleaved scan 3: infected';
is $scans[3]->verdict->state, 'clean', 'interleaved scan 4: clean';
}
# --- a filehandle scan holds its source alive ---------------------------
# The handle keeps a reference, because the scan outlives the call that
# started it and reading a freed PV is not a bug that shows up locally.
{
my $s = do {
open my $fh, '<:raw', $eicar or die $!;
$c->start_scan($fh, 'fd');
}; # $fh out of scope, scan still live
drive($s);
is $s->verdict->state, 'infected', 'a scan outlives the handle it was given';
}
{
my $s = do {
my $bytes = $EICAR;
$c->start_scan($bytes);
}; # $bytes out of scope
drive($s);
is $s->verdict->state, 'infected', 'a byte scan outlives the scalar it was given';
}
done_testing;
( run in 0.799 second using v1.01-cache-2.11-cpan-14f38c9f855 )