Email-Fingerprint
view release on metacpan or search on metacpan
package main;
# Construction should fail
throws_ok
{ $cache = new Email::Fingerprint::Cache({ backend => 'Backend8' }) }
qr{Can't load},
"Dies when constructor returns undef";
}
# Clean up a little
undef $cache;
############################################################################
# Exercise the lock() and unlock() methods
############################################################################
SKIP: {
my $perl = $EXECUTABLE_NAME;
my $lib = "$FindBin::Bin/../lib";
# We make a massive effort to make this test work on Windows,
# even though fork() is completely broken there. We do skip this
# part of the test if we simply can't launch Perl, though.
my $status = system (
$perl, '-I', $lib, qw/ -MPOSIX -MEmail::Fingerprint::Cache -e 0 /
);
if ($status != 0)
{
diag "Perl: $perl";
diag "Lib: $lib";
diag "\$0: $0";
skip "can't run perl; your system looks broken", 3 unless $status == 0;
}
# Clean up the lockfile from any crashed test runs
unlink "$file.lock";
# Open two caches and make 'em fight.
my $cache1 = new Email::Fingerprint::Cache({ file => $file });
skip "failed to create cache for lock test", 3 unless $cache1;
# Locking cache 1 should prevent locking the same cache in another process.
# NOTE: It prevents locking cache2 in the *same* process on most UNIX
# variants, except Solaris.
ok $cache1->lock ? 1 : 0,
"Locking a cache should succeed when nobody else has a lock";
# Now attempt a second lock, in a separate process, without forking.
# Good luck with that!
$status = system(
$perl, '-I', $lib, qw/ -MPOSIX -MEmail::Fingerprint::Cache -e /,
qq{
\$cache = Email::Fingerprint::Cache->new({ file => '$file' });
POSIX::_exit(0) if \$cache->lock;
POSIX::_exit(1);
},
);
ok +($status >> 8 == 1), "... and other processes should be unable to lock the locked cache";
skip "failed to unlock test cache", 1 unless $cache1->unlock;
$status = system(
$perl, '-I', $lib, qw/ -MPOSIX -MEmail::Fingerprint::Cache -e /,
qq{
\$cache = Email::Fingerprint::Cache->new({ file => '$file' });
POSIX::_exit(0) unless \$cache->lock;
POSIX::_exit(0) unless \$cache->unlock;
POSIX::_exit(1);
},
);
ok +($status >> 8 == 1), "... until after the original process releases its lock";
# Destroy the caches
undef $cache1;
}
############################################################################
# Test the ugly failsafe in the DESTROY() method
############################################################################
$cache = new Email::Fingerprint::Cache({
file => $file,
hash => {},
});
# Open and lock the cache.
if (not $cache or not $cache->open or not $cache->lock)
{
# Suppress spurious warnings
$cache->close;
$cache->unlock;
undef $cache;
ok 0, "Create an open, locked cache for warning test";
}
else
{
warning_like
{ undef $cache }
{ carped => qr/before it was close/ },
"Destroying an open, locked cache should generate a warning";
}
# Create another one
$cache = new Email::Fingerprint::Cache({
file => $file,
hash => {},
});
# This time, we open but don't lock the cache.
if (not $cache or not $cache->open)
{
$cache->close;
undef $cache;
ok 0, "Create an open, unlocked cache for warning test";
}
else
{
warning_like
{ undef $cache }
{ carped => qr/before it was close/},
"Destroying an open, unlocked cache should generate a warning";
}
# Create another one
$cache = new Email::Fingerprint::Cache({
file => $file,
hash => {},
});
# This time, we lock but don't open the cache.
if (not $cache or not $cache->lock)
{
$cache->close;
undef $cache;
ok 0, "Create a locked but unopened cache for warning test";
}
else
{
warning_is { undef $cache } undef,
"Destroying a locked but unopened cache should not generate warnings";
}
############################################################################
# Exercise purge() more thoroughly
############################################################################
SKIP: {
%fingerprints = ();
$cache = new Email::Fingerprint::Cache({
file => $file,
hash => \%fingerprints,
ttl => 60,
});
# Open the cache.
ok $cache, "New cache for TTL test";
ok $cache->open, "Opened cache";
ok scalar(keys %fingerprints) == 0, "Cache initially empty";
# Populate the cache with 500 items each: less than 60 seconds old;
# between 60 and 119 seconds old; older than 120 seconds.
for my $n ( 1..500 ) {
my $timestamp = time;
my $key = sprintf "%03i", $n;
$fingerprints{"a$key"} = $timestamp - int(rand(58)) - 1; # Less than 1 minute
$fingerprints{"b$key"} = $timestamp - int(rand(58)) - 61; # Less than 2 minutes
$fingerprints{"c$key"} = $timestamp - int(rand(59)) - 121; # More than 2 minutes
}
# Add a fingerprint with no defined timestamp, or a timestamp
# that evaluates to false.
$fingerprints{101} = undef;
$fingerprints{102} = 0;
$fingerprints{103} = '';
# And finally, add one entry that WON'T be purged.
$fingerprints{104} = 60 + time; # Just in case the test runs slow...
# Now confirm that they're there
my $count = scalar(keys %fingerprints);
ok $count == 1504, "The cache should contain 1,504 fingerprints, and contains: $count";
# First, purge the invalid timestamps
$cache->purge( ttl => 200 );
$count = scalar(keys %fingerprints);
ok $count == 1501, "... 3 with invalid timestamps, which should now be purged ($count remaining)";
# Next, purge items older than 2 minutes, and check. The "false"
# fingerprints should also be gone.
$cache->purge( ttl => 120 );
$count = scalar(keys %fingerprints);
ok $count == 1001, "... 500 older than two minutes, which should now be purged ($count remaining)";
# Then purge using the default TTL, which we set earlier to 60.
# Confirm that the default TTL is used and not, e.g., 120.
$cache->purge;
############################################################################
# Test the dump() method, which prints to STDOUT
############################################################################
$file = 't/data/cache';
my %hash;
our $data;
# Read the data, stored in Perl format: loads hashref $data
require "$file.pl";
$cache = new Email::Fingerprint::Cache({
file => $file,
hash => \%hash,
});
# Open the cache file
ok $cache->open, "Opening the test cache should succeed";
# Purge the cache, in case there's leftover test data around
$cache->purge( ttl => -1 );
# Add our data to the hash
$hash{$_} = $data->{$_} for keys %$data;
# Close and reopen
ok $cache->close, "... and closing it should also be successful";
ok $cache->open, "... as should reopening it";
my $output;
# Dump the cache, catching the output
tie *STDOUT, 'Test::Stdout', \$output;
$cache->dump;
untie *STDOUT;
# Read the test data
open IN, '<', "$file.txt";
my $standard = join '', <IN>;
close IN;
# Compare
ok $output eq $standard, "... and the contents should match our test data";
# Clean up
lives_ok { $cache->close } "Closing the cache should not throw an exception";
warning_is { undef $cache } undef, "Destroying the closed cache should not generate warnings";
############################################################################
# Test the set_file method, which only works when no file is open.
############################################################################
# Get a fresh cache
$cache = new Email::Fingerprint::Cache({
file => $file,
hash => {},
});
# Nothing should happen, either, if the file is locked
$cache->lock;
ok !defined $cache->set_file('foo'), "Setting a new cache file should fail when the cache is locked";
$cache->unlock;
# Nothing should happen, either, if the file is locked
$cache->open;
ok !defined $cache->set_file('foo'), "... or when the file is open";
$cache->close;
# Finally, the file is closed and unlocked, so it should work
ok $cache->set_file('foo'), "... but it should be successful if the cache is closed and unlocked";
# Clean up
unlink "t/data/cache.db";
# That's all, folks!
done_testing();
( run in 1.017 second using v1.01-cache-2.11-cpan-0bb4e1dffa6 )