shell bypass 403
######################################################################
# $Id: CacheTester.pm,v 1.20 2002/04/07 17:04:46 dclinton Exp $
# Copyright (C) 2001-2003 DeWitt Clinton All Rights Reserved
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either expressed or
# implied. See the License for the specific language governing
# rights and limitations under the License.
######################################################################
package Cache::CacheTester;
use strict;
use Cache::BaseCacheTester;
use Cache::Cache;
use Error qw( :try );
use vars qw( @ISA $EXPIRES_DELAY );
@ISA = qw ( Cache::BaseCacheTester );
$EXPIRES_DELAY = 2;
$Error::Debug = 1;
sub test
{
my ( $self, $cache ) = @_;
try
{
$cache->Clear( );
$self->_test_one( $cache );
$self->_test_two( $cache );
$self->_test_three( $cache );
$self->_test_four( $cache );
$self->_test_five( $cache );
$self->_test_six( $cache );
$self->_test_seven( $cache );
$self->_test_eight( $cache );
$self->_test_nine( $cache );
$self->_test_ten( $cache );
$self->_test_eleven( $cache );
$self->_test_twelve( $cache );
$self->_test_thirteen( $cache );
$self->_test_fourteen( $cache );
$self->_test_fifteen( $cache );
$self->_test_sixteen( $cache );
$self->_test_seventeen( $cache );
}
catch Error with
{
my $error = shift;
print STDERR "\nError:\n";
print STDERR $error->stringify( ) . "\n";
print STDERR $error->stacktrace( ) . "\n";
print STDERR "\n";
}
}
# Test the getting, setting, and removal of a scalar
sub _test_one
{
my ( $self, $cache ) = @_;
$cache or
croak( "cache required" );
my $key = 'Test Key';
my $value = 'Test Value';
$cache->set( $key, $value );
my $fetched_value = $cache->get( $key );
( $fetched_value eq $value ) ?
$self->ok( ) : $self->not_ok( '$fetched_value eq $value' );
$cache->remove( $key );
my $fetched_removed_value = $cache->get( $key );
( not defined $fetched_removed_value ) ?
$self->ok( ) : $self->not_ok( 'not defined $fetched_removed_value' );
}
# Test the getting, setting, and removal of a list
sub _test_two
{
my ( $self, $cache ) = @_;
$cache or
croak( "cache required" );
my $key = 'Test Key';
my @value_list = ( 'One', 'Two', 'Three' );
$cache->set( $key, \@value_list );
my $fetched_value_list_ref = $cache->get( $key );
if ( ( $fetched_value_list_ref->[0] eq 'One' ) and
( $fetched_value_list_ref->[1] eq 'Two' ) and
( $fetched_value_list_ref->[2] eq 'Three' ) )
{
$self->ok( );
}
else
{
$self->not_ok( 'fetched list does not match set list' );
}
$cache->remove( $key );
my $fetched_removed_value = $cache->get( $key );
( not defined $fetched_removed_value ) ?
$self->ok( ) : $self->not_ok( 'not defined $fetched_removed_value' );
}
# Test the getting, setting, and removal of a blessed object
sub _test_three
{
my ( $self, $cache ) = @_;
$cache or
croak( "cache required" );
my $key = 'Test Key';
my $value = 'Test Value';
$cache->set( $key, $value );
my $cache_key = 'Cache Key';
$cache->set( $cache_key, $cache );
my $fetched_cache = $cache->get( $cache_key );
( defined $fetched_cache ) ?
$self->ok( ) : $self->not_ok( 'defined $fetched_cache' );
my $fetched_value = $fetched_cache->get( $key );
( $fetched_value eq $value ) ?
$self->ok( ) : $self->not_ok( '$fetched_value eq $value' );
}
# Test the expiration of an object
sub _test_four
{
my ( $self, $cache ) = @_;
my $expires_in = $EXPIRES_DELAY;
my $key = 'Test Key';
my $value = 'Test Value';
my $start = time;
$cache->set( $key, $value, $expires_in );
my $fetched_value = $cache->get( $key );
if (time - $start < $expires_in) {
( $fetched_value eq $value ) ?
$self->ok( ) : $self->not_ok( '$fetched_value eq $value' );
} else {
$self->skip( '$fetched_value eq $value (not finished in ' .
$expires_in . ' s)' );
}
sleep( $EXPIRES_DELAY + 1 );
my $fetched_expired_value = $cache->get( $key );
( not defined $fetched_expired_value ) ?
$self->ok( ) : $self->not_ok( 'not defined $fetched_expired_value' );
}
# Test that caches make deep copies of values
sub _test_five
{
my ( $self, $cache ) = @_;
$cache or
croak( "cache required" );
my $key = 'Test Key';
my @value_list = ( 'One', 'Two', 'Three' );
$cache->set( $key, \@value_list );
@value_list = ( );
my $fetched_value_list_ref = $cache->get( $key );
if ( ( $fetched_value_list_ref->[0] eq 'One' ) and
( $fetched_value_list_ref->[1] eq 'Two' ) and
( $fetched_value_list_ref->[2] eq 'Three' ) )
{
$self->ok( );
}
else
{
$self->not_ok( 'fetched deep list does not match set deep list' );
}
}
# Test clearing a cache
sub _test_six
{
my ( $self, $cache ) = @_;
$cache or
croak( "cache required" );
my $key = 'Test Key';
my $value = 'Test Value';
$cache->set( $key, $value );
$cache->clear( );
my $fetched_cleared_value = $cache->get( $key );
( not defined $fetched_cleared_value ) ?
$self->ok( ) : $self->not_ok( 'not defined $fetched_cleared_value' );
}
# Test sizing of the cache
sub _test_seven
{
my ( $self, $cache ) = @_;
my $empty_size = $cache->size( );
( $empty_size == 0 ) ?
$self->ok( ) : $self->not_ok( '$empty_size == 0' );
my $first_key = 'First Test Key';
my $value = 'Test Value';
$cache->set( $first_key, $value );
my $first_size = $cache->size( );
( $first_size > $empty_size ) ?
$self->ok( ) : $self->not_ok( '$first_size > $empty_size' );
my $second_key = 'Second Test Key';
$cache->set( $second_key, $value );
my $second_size = $cache->size( );
( $second_size > $first_size ) ?
$self->ok( ) : $self->not_ok( '$second_size > $first_size' );
}
# Test purging the cache
sub _test_eight
{
my ( $self, $cache ) = @_;
$cache->clear( );
my $empty_size = $cache->size( );
( $empty_size == 0 ) ?
$self->ok( ) : $self->not_ok( '$empty_size == 0' );
my $expires_in = $EXPIRES_DELAY;
my $key = 'Test Key';
my $value = 'Test Value';
$cache->set( $key, $value, $expires_in );
my $pre_purge_size = $cache->size( );
( $pre_purge_size > $empty_size ) ?
$self->ok( ) : $self->not_ok( '$pre_purge_size > $empty_size' );
sleep( $EXPIRES_DELAY + 1 );
$cache->purge( );
my $post_purge_size = $cache->size( );
( $post_purge_size == $empty_size ) ?
$self->ok( ) : $self->not_ok( '$post_purge_size == $empty_size' );
}
# Test the getting, setting, and removal of a scalar across cache instances
sub _test_nine
{
my ( $self, $cache1 ) = @_;
$cache1 or
croak( "cache required" );
my $cache2 = $cache1->new( ) or
croak( "Couldn't construct new cache" );
my $key = 'Test Key';
my $value = 'Test Value';
$cache1->set( $key, $value );
my $fetched_value = $cache2->get( $key );
( $fetched_value eq $value ) ?
$self->ok( ) : $self->not_ok( '$fetched_value eq $value' );
}
# Test Clear() and Size() as instance methods
sub _test_ten
{
my ( $self, $cache ) = @_;
$cache or
croak( "cache required" );
my $key = 'Test Key';
my $value = 'Test Value';
$cache->set( $key, $value );
my $full_size = $cache->Size( );
( $full_size > 0 ) ?
$self->ok( ) : $self->not_ok( '$full_size > 0' );
$cache->Clear( );
my $empty_size = $cache->Size( );
( $empty_size == 0 ) ?
$self->ok( ) : $self->not_ok( '$empty_size == 0' );
}
# Test Purge(), Clear(), and Size() as instance methods
sub _test_eleven
{
my ( $self, $cache ) = @_;
$cache->Clear( );
my $empty_size = $cache->Size( );
( $empty_size == 0 ) ?
$self->ok( ) : $self->not_ok( '$empty_size == 0' );
my $expires_in = $EXPIRES_DELAY;
my $key = 'Test Key';
my $value = 'Test Value';
$cache->set( $key, $value, $expires_in );
my $pre_purge_size = $cache->Size( );
( $pre_purge_size > $empty_size ) ?
$self->ok( ) : $self->not_ok( '$pre_purge_size > $empty_size' );
sleep( $EXPIRES_DELAY + 1 );
$cache->Purge( );
my $purged_object = $cache->get_object( $key );
( not defined $purged_object ) ?
$self->ok( ) : $self->not_ok( 'not defined $purged_object' );
}
# Test Purge(), Clear(), and Size() as static methods
sub _test_twelve
{
my ( $self, $cache ) = @_;
my $class = ref $cache or
croak( "Couldn't get ref \$cache" );
no strict 'refs';
&{"${class}::Clear"}( );
my $empty_size = &{"${class}::Size"}( );
( $empty_size == 0 ) ?
$self->ok( ) : $self->not_ok( '$empty_size == 0' );
my $expires_in = $EXPIRES_DELAY;
my $key = 'Test Key';
my $value = 'Test Value';
$cache->set( $key, $value, $expires_in );
my $pre_purge_size = &{"${class}::Size"}( );
( $pre_purge_size > $empty_size ) ?
$self->ok( ) : $self->not_ok( '$pre_purge_size > $empty_size' );
sleep( $EXPIRES_DELAY + 1 );
&{"${class}::Purge"}( );
my $purged_object = $cache->get_object( $key );
( not defined $purged_object ) ?
$self->ok( ) : $self->not_ok( 'not defined $purged_object' );
use strict;
}
# Test the expiration of an object with extended syntax
sub _test_thirteen
{
my ( $self, $cache ) = @_;
my $expires_in = $EXPIRES_DELAY;
my $key = 'Test Key';
my $value = 'Test Value';
my $start = time;
$cache->set( $key, $value, $expires_in );
my $fetched_value = $cache->get( $key );
if (time - $start < $expires_in) {
( $fetched_value eq $value ) ?
$self->ok( ) : $self->not_ok( '$fetched_value eq $value' );
} else {
$self->skip( '$fetched_value eq $value (not finished in ' .
$expires_in . ' s)' );
}
sleep( $EXPIRES_DELAY + 1 );
my $fetched_expired_value = $cache->get( $key );
( not defined $fetched_expired_value ) ?
$self->ok( ) : $self->not_ok( 'not defined $fetched_expired_value' );
}
# test the get_keys method
sub _test_fourteen
{
my ( $self, $cache ) = @_;
$cache->Clear( );
my $empty_size = $cache->Size( );
( $empty_size == 0 ) ?
$self->ok( ) : $self->not_ok( '$empty_size == 0' );
my @keys = sort ( 'John', 'Paul', 'Ringo', 'George' );
my $value = 'Test Value';
foreach my $key ( @keys )
{
$cache->set( $key, $value );
}
my @cached_keys = sort $cache->get_keys( );
my $arrays_equal = Arrays_Are_Equal( \@keys, \@cached_keys );
( $arrays_equal == 1 ) ?
$self->ok( ) : $self->not_ok( '$arrays_equal == 1' );
}
# test the auto_purge on set functionality
sub _test_fifteen
{
my ( $self, $cache ) = @_;
$cache->Clear( );
my $expires_in = $EXPIRES_DELAY;
$cache->set_auto_purge_interval( $expires_in );
$cache->set_auto_purge_on_set( 1 );
my $key = 'Test Key';
my $value = 'Test Value';
my $start = time;
$cache->set( $key, $value, $expires_in );
my $fetched_value = $cache->get( $key );
if (time - $start < $expires_in) {
( $fetched_value eq $value ) ?
$self->ok( ) : $self->not_ok( '$fetched_value eq $value' );
} else {
$self->skip( '$fetched_value eq $value (not finished in ' .
$expires_in . ' s)' );
}
sleep( $EXPIRES_DELAY + 1 );
$cache->set( "Trigger auto_purge", "Empty" );
my $fetched_expired_object = $cache->get_object( $key );
( not defined $fetched_expired_object ) ?
$self->ok( ) : $self->not_ok( 'not defined $fetched_expired_object' );
$cache->Clear( );
}
# test the auto_purge_interval functionality
sub _test_sixteen
{
my ( $self, $cache ) = @_;
my $expires_in = $EXPIRES_DELAY;
my $ok = eval {
$cache = $cache->new( { 'auto_purge_interval' => $expires_in } );
1;
};
$ok ? $self->ok( )
: $self->not_ok( "couldn't create autopurge cache" );
}
# test the get_namespaces method
sub _test_seventeen
{
my ( $self, $cache ) = @_;
$cache->set( 'a', '1' );
$cache->set_namespace( 'namespace' );
$cache->set( 'b', '2' );
if ( Arrays_Are_Equal( [ sort( $cache->get_namespaces( ) ) ],
[ sort( 'Default', 'namespace' ) ] ) )
{
$self->ok( );
}
else
{
$self->not_ok( "get_namespaces returned the wrong namespaces" );
}
$cache->Clear( );
}
sub Arrays_Are_Equal
{
my ( $first_array_ref, $second_array_ref ) = @_;
local $^W = 0; # silence spurious -w undef complaints
return 0 unless @$first_array_ref == @$second_array_ref;
for (my $i = 0; $i < @$first_array_ref; $i++)
{
return 0 if $first_array_ref->[$i] ne $second_array_ref->[$i];
}
return 1;
}
1;
__END__
=pod
=head1 NAME
Cache::CacheTester -- a class for regression testing caches
=head1 DESCRIPTION
The CacheTester is used to verify that a cache implementation honors
its contract.
=head1 SYNOPSIS
use Cache::MemoryCache;
use Cache::CacheTester;
my $cache = new Cache::MemoryCache( );
my $cache_tester = new Cache::CacheTester( 1 );
$cache_tester->test( $cache );
=head1 METHODS
=over
=item B<new( $initial_count )>
Construct a new CacheTester object, with the counter starting at
I<$initial_count>.
=item B<test( )>
Run the tests.
=back
=head1 SEE ALSO
Cache::Cache, Cache::BaseCacheTester
=head1 AUTHOR
Original author: DeWitt Clinton <dewitt@unto.net>
Last author: $Author: dclinton $
Copyright (C) 2001-2003 DeWitt Clinton
=cut