From 474a086d90731ee3a953659d83904d3577925465 Mon Sep 17 00:00:00 2001 From: Jared Johnson Date: Tue, 30 Dec 2014 13:06:22 -0600 Subject: [PATCH] Tests for Qpsmtpd::DB::Redis --- t/qpsmtpd-db-redis.t | 179 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 t/qpsmtpd-db-redis.t diff --git a/t/qpsmtpd-db-redis.t b/t/qpsmtpd-db-redis.t new file mode 100644 index 0000000..3c42fe5 --- /dev/null +++ b/t/qpsmtpd-db-redis.t @@ -0,0 +1,179 @@ +use strict; +use warnings; + +use Test::More; + +use lib 'lib'; # test lib/Qpsmtpd (vs site_perl) +use lib 't'; + +use_ok('Qpsmtpd::DB::Redis'); + +my $db; +eval 'use Redis; Redis->new'; +if ( $@ ) { + warn "Could not connect to redis to test; using mock redis"; + $db = bless { name => 'testing', redis => FakeRedis->new }, 'Qpsmtpd::DB::Redis'; +} +else { + Redis->new->flushall; + $db = Qpsmtpd::DB::Redis->new( name => 'testing' ); + + __new(); + +} + +__index(); +__redis(); +__get(); +__set(); +__delete(); +__get_keys(); +__size(); +__flush(); + +done_testing(); + +sub __new { + is( ref $db->{redis}, 'MyRedis', 'Redis object populated' ); + my $redis = $db->{redis}; + $redis->select(0); + is( $redis->get('___smtpd_reserved___'), 1, 'DB properly initialized' ); + is( join( '|', $redis->keys('*') ), '___smtpd_reserved___', + 'Nothing else has happened to DB yet' ); +} + +sub __redis { + $db->{redis}->flushall; + $db->{redis}->select(0); + delete $db->{index}; + my $redis = $db->redis; + is( $redis->selected, 1, 'redis() selects the correct index' ); +} + +sub __index { + my $redis = $db->{redis}; + $redis->flushall; + is( stores($db), '', 'stores unpopulated initially' ); + is( $db->{index}, undef, 'index cache unpopulated initially' ); + is( $db->index, 1, 'get first index given an empty db' ); + is( stores($db), 'testing=1', 'stores populated correctly for index=1' ); + is( $db->{index}, 1, 'index is cached' ); + $db->{index} = 999; + is( $db->index, 999, 'index cache is honored' ); + delete $db->{index}; + $redis->flushall; + $redis->select(0); + $redis->hset( 'smtpd_stores', testing => 99 ); + is( $db->index, 99, 'redis zero table is honored' ); + delete $db->{index}; + $redis->flushall; + $redis->select(1); + $redis->set( bugus => 1 ); + is( $db->index, 2, 'index() skips already-populated db' ); + is( stores($db), 'testing=2', 'stores populated correclty for index=2' ); + delete $db->{index}; + $redis->flushall; + $redis->select(0); + $redis->hset( 'smtpd_stores', foo => 1 ); + $redis->hset( 'smtpd_stores', bar => 2 ); + is( $db->index, 3, 'index() skips already-earmarked db' ); +} + +sub stores { + my $redis = $db->{redis}; + $redis->select(0); + my %store = $redis->hgetall('smtpd_stores'); + return join ';', map { "$_=$store{$_}" } keys %store; +} + +sub __get { + my $redis = $db->redis; + $redis->flushdb; + $redis->set( moo => 'oooo' ); + is( $db->get('moo'), 'oooo', 'get() retrieves key' ); +} + +sub __set { + my $redis = $db->redis; + $redis->flushdb; + $db->set( mee => 'ow' ); + is( $redis->get('mee'), 'ow', 'set() stores key' ); +} + +sub __delete { + my $redis = $db->redis; + $redis->flushdb; + $redis->set( oink => 1 ); + $redis->set( quack => 1 ); + $db->delete('quack'); + is( join( '|', $redis->keys('*') ), 'oink', 'delete() removes key' ); +} + +sub __get_keys { + my $redis = $db->redis; + $redis->flushdb; + $redis->set( asdf => 1 ); + $redis->set( qwerty => 1 ); + is( join( '|', sort $db->get_keys ), 'asdf|qwerty', + 'get_keys() lists all keys in the db' ); +} + +sub __size { + my $redis = $db->redis; + $redis->flushdb; + $redis->set( baz => 1 ); + $redis->set( blah => 1 ); + is( $db->size, 2, 'size() shows key count for db' ); +} + +sub __flush { + $db->redis->flushall; + my $redis = $db->redis; + $redis->flushdb; + $redis->set( bogus => 1 ); + is( join( '|', $redis->keys('*') ), 'bogus', 'redis db populated' ); + $db->flush; + is( join( '|', $redis->keys('*') ), '', 'flush() empties db' ); +} + +package FakeRedis; +sub new { + my $class = shift; + return bless {@_}, $class; +} + +sub flushall { delete $_[0]->{fakestore} } +sub selected { $_[0]->{selected} } +sub select { $_[0]->{selected} = $_[1] } +sub dbsize { scalar keys %{ $_[0]->fakestore } } +sub get { $_[0]->fakestore->{ $_[1] } } +sub set { $_[0]->fakestore->{ $_[1] } = $_[2] } +sub del { delete $_[0]->fakestore->{ $_[1] } } + +sub hgetall { + my ( $self, $h ) = @_; + return %{ $self->fakestore->{ $h } || {} }; +} + +sub hset { + my ( $self, $h, $key, $value ) = @_; + $self->fakestore->{ $h }{ $key } = $value; +} + +sub keys { + my ( $self, $pattern ) = @_; + die "invalid pattern '$pattern': Mock Redis only understands '*'" + if $pattern ne '*'; + return keys %{ $self->fakestore }; +} + +sub flushdb { + my ( $self ) = @_; + delete $self->{fakestore}{ $self->selected }; +} + +sub fakestore { + my ( $self ) = @_; + return $self->{fakestore}{ $self->selected } ||= {}; +} +