Plugin testing framework.

git-svn-id: https://svn.perl.org/qpsmtpd/trunk@313 958fd67b-6ff1-0310-b445-bb7760255be9
This commit is contained in:
Matt Sergeant 2004-09-08 16:26:33 +00:00
parent 0b16ec9418
commit 9224e436bb
5 changed files with 137 additions and 15 deletions

View File

@ -63,6 +63,18 @@ sub config {
} }
} }
sub config_dir {
my ($self, $config) = @_;
my $configdir = ($ENV{QMAIL} || '/var/qmail') . '/control';
my ($name) = ($0 =~ m!(.*?)/([^/]+)$!);
$configdir = "$name/config" if (-e "$name/config/$config");
return $configdir;
}
sub plugin_dir {
my ($name) = ($0 =~ m!(.*?)/([^/]+)$!);
my $dir = "$name/plugins";
}
sub get_qmail_config { sub get_qmail_config {
my ($self, $config, $type) = @_; my ($self, $config, $type) = @_;
@ -70,9 +82,7 @@ sub get_qmail_config {
if ($self->{_config_cache}->{$config}) { if ($self->{_config_cache}->{$config}) {
return wantarray ? @{$self->{_config_cache}->{$config}} : $self->{_config_cache}->{$config}->[0]; return wantarray ? @{$self->{_config_cache}->{$config}} : $self->{_config_cache}->{$config}->[0];
} }
my $configdir = ($ENV{QMAIL} || '/var/qmail') . '/control'; my $configdir = $self->config_dir($config);
my ($name) = ($0 =~ m!(.*?)/([^/]+)$!);
$configdir = "$name/config" if (-e "$name/config/$config");
my $configfile = "$configdir/$config"; my $configfile = "$configdir/$config";
@ -112,7 +122,7 @@ sub _config_from_file {
} }
sub _compile { sub _compile {
my ($plugin, $package, $file) = @_; my ($self, $plugin, $package, $file) = @_;
my $sub; my $sub;
open F, $file or die "could not open $file: $!"; open F, $file or die "could not open $file: $!";
@ -124,6 +134,15 @@ sub _compile {
my $line = "\n#line 1 $file\n"; my $line = "\n#line 1 $file\n";
if ($self->{_test_mode}) {
if (open(F, "t/plugin_tests/$plugin")) {
local $/ = undef;
$sub .= "#line 1 t/plugin_tests/$plugin\n";
$sub .= <F>;
close F;
}
}
my $eval = join( my $eval = join(
"\n", "\n",
"package $package;", "package $package;",
@ -131,6 +150,7 @@ sub _compile {
"require Qpsmtpd::Plugin;", "require Qpsmtpd::Plugin;",
'use vars qw(@ISA);', 'use vars qw(@ISA);',
'@ISA = qw(Qpsmtpd::Plugin);', '@ISA = qw(Qpsmtpd::Plugin);',
($self->{_test_mode} ? 'use Test::More;' : ''),
"sub plugin_name { qq[$plugin] }", "sub plugin_name { qq[$plugin] }",
$line, $line,
$sub, $sub,
@ -149,42 +169,43 @@ sub _compile {
sub load_plugins { sub load_plugins {
my $self = shift; my $self = shift;
$self->{hooks} ||= {}; $self->log(LOGERROR, "Plugins already loaded") if $self->{hooks};
$self->{hooks} = {};
my @plugins = $self->config('plugins'); my @plugins = $self->config('plugins');
my ($name) = ($0 =~ m!(.*?)/([^/]+)$!); my $dir = $self->plugin_dir;
my $dir = "$name/plugins";
$self->log(LOGNOTICE, "loading plugins from $dir"); $self->log(LOGNOTICE, "loading plugins from $dir");
$self->_load_plugins($dir, @plugins); @plugins = $self->_load_plugins($dir, @plugins);
return @plugins;
} }
sub _load_plugins { sub _load_plugins {
my $self = shift; my $self = shift;
my ($dir, @plugins) = @_; my ($dir, @plugins) = @_;
my @ret;
for my $plugin (@plugins) { for my $plugin (@plugins) {
$self->log(LOGINFO, "Loading $plugin"); $self->log(LOGINFO, "Loading $plugin");
($plugin, my @args) = split /\s+/, $plugin; ($plugin, my @args) = split /\s+/, $plugin;
if (lc($plugin) eq '$include') { if (lc($plugin) eq '$include') {
my $inc = shift @args; my $inc = shift @args;
my $config_dir = ($ENV{QMAIL} || '/var/qmail') . '/control'; my $config_dir = $self->config_dir($inc);
my ($name) = ($0 =~ m!(.*?)/([^/]+)$!);
$config_dir = "$name/config" if (-e "$name/config/$inc");
if (-d "$config_dir/$inc") { if (-d "$config_dir/$inc") {
$self->log(LOGDEBUG, "Loading include dir: $config_dir/$inc"); $self->log(LOGDEBUG, "Loading include dir: $config_dir/$inc");
opendir(DIR, "$config_dir/$inc") || die "opendir($config_dir/$inc): $!"; opendir(DIR, "$config_dir/$inc") || die "opendir($config_dir/$inc): $!";
my @plugconf = sort grep { -f $_ } map { "$config_dir/$inc/$_" } grep { !/^\./ } readdir(DIR); my @plugconf = sort grep { -f $_ } map { "$config_dir/$inc/$_" } grep { !/^\./ } readdir(DIR);
closedir(DIR); closedir(DIR);
foreach my $f (@plugconf) { foreach my $f (@plugconf) {
$self->_load_plugins($dir, $self->_config_from_file($f, "plugins")); push @ret, $self->_load_plugins($dir, $self->_config_from_file($f, "plugins"));
} }
} }
elsif (-f "$config_dir/$inc") { elsif (-f "$config_dir/$inc") {
$self->log(LOGDEBUG, "Loading include file: $config_dir/$inc"); $self->log(LOGDEBUG, "Loading include file: $config_dir/$inc");
$self->_load_plugins($dir, $self->_config_from_file("$config_dir/$inc", "plugins")); push @ret, $self->_load_plugins($dir, $self->_config_from_file("$config_dir/$inc", "plugins"));
} }
else { else {
$self->log(LOGCRIT, "CRITICAL PLUGIN CONFIG ERROR: Include $config_dir/$inc not found"); $self->log(LOGCRIT, "CRITICAL PLUGIN CONFIG ERROR: Include $config_dir/$inc not found");
@ -209,13 +230,16 @@ sub _load_plugins {
my $package = "Qpsmtpd::Plugin::$plugin_name"; my $package = "Qpsmtpd::Plugin::$plugin_name";
# don't reload plugins if they are already loaded # don't reload plugins if they are already loaded
_compile($plugin_name, $package, "$dir/$plugin") unless $self->_compile($plugin_name, $package, "$dir/$plugin") unless
defined &{"${package}::register"}; defined &{"${package}::register"};
my $plug = $package->new(); my $plug = $package->new();
push @ret, $plug;
$plug->_register($self, @args); $plug->_register($self, @args);
} }
return @ret;
} }
sub transaction { sub transaction {

View File

@ -4,6 +4,7 @@ use Carp qw(croak);
use base qw(Qpsmtpd::SMTP); use base qw(Qpsmtpd::SMTP);
use Test::More; use Test::More;
use Qpsmtpd::Constants; use Qpsmtpd::Constants;
use Test::Qpsmtpd::Plugin;
sub new_conn { sub new_conn {
ok(my $smtpd = __PACKAGE__->new(), "new"); ok(my $smtpd = __PACKAGE__->new(), "new");
@ -65,9 +66,46 @@ sub input {
alarm $timeout; alarm $timeout;
} }
sub config_dir {
'./config';
}
sub plugin_dir {
'./plugins';
}
sub log {
my ($self, $trace, @log) = @_;
my $level = Qpsmtpd::TRACE_LEVEL();
$level = $self->init_logger unless defined $level;
diag(join(" ", $$, @log)) if $trace <= $level;
}
# sub run # sub run
# sub disconnect # sub disconnect
sub run_plugin_tests {
my $self = shift;
$self->{_test_mode} = 1;
my @plugins = $self->load_plugins();
# First count test number
my $num_tests = 0;
foreach my $plugin (@plugins) {
$plugin->register_tests();
$num_tests += $plugin->total_tests();
}
require Test::Builder;
my $Test = Test::Builder->new();
$Test->plan( tests => $num_tests );
# Now run them
foreach my $plugin (@plugins) {
$plugin->run_tests();
}
}
1; 1;

41
t/Test/Qpsmtpd/Plugin.pm Normal file
View File

@ -0,0 +1,41 @@
# $Id$
package Test::Qpsmtpd::Plugin;
1;
# Additional plugin methods used during testing
package Qpsmtpd::Plugin;
use Test::More;
use strict;
sub register_tests {
# Virtual base method - implement in plugin
}
sub register_test {
my ($plugin, $test, $num_tests) = @_;
$num_tests = 1 unless defined($num_tests);
# print STDERR "Registering test $test ($num_tests)\n";
push @{$plugin->{_tests}}, { name => $test, num => $num_tests };
}
sub total_tests {
my ($plugin) = @_;
my $total = 0;
foreach my $t (@{$plugin->{_tests}}) {
$total += $t->{num};
}
return $total;
}
sub run_tests {
my ($plugin) = @_;
foreach my $t (@{$plugin->{_tests}}) {
my $method = $t->{name};
diag "Running $method tests for plugin " . $plugin->plugin_name;
$plugin->$method();
}
}
1;

10
t/plugin_tests.t Normal file
View File

@ -0,0 +1,10 @@
#!/usr/bin/perl -w
use strict;
use lib 't';
use Test::Qpsmtpd;
my $qp = Test::Qpsmtpd->new();
$qp->run_plugin_tests();

View File

@ -0,0 +1,9 @@
sub register_tests {
my $self = shift;
$self->register_test("foo", 1);
}
sub foo {
ok(1);
}