Hi all,
I'm at wit's end about this and any guidance would be appreciated.
I have a class which needs to maintain state based on pid. So how do I test
that? I fork, of course (can't use threads as our Perl is built without thread
support). That's when things go bad. As far as I can tell, Tassilo von
Parseval's patch for making Test::More work with across forks hasn't been
implemented:
http://www.nntp.perl.org/group/perl.qa/2006/03/msg5651.html
http://tinyurl.com/yp69e3
So I have the following simple test case:
#!/usr/bin/perl
use strict;
use warnings;
use Test::More 'no_plan';
use Test::Builder;
use IPC::SysV qw< IPC_PRIVATE IPC_RMID S_IRWXU >;
ok 1, 'mytest called';
my $test = Test::Builder->new;
my $id = shmget( IPC_PRIVATE, 2000, S_IRWXU ) or die $!;
my $test_num;
if ( !defined( my $child_pid = fork() ) ) {
diag "Cannot fork: $!";
}
elsif ( !$child_pid ) {
ok 1, 'in the child';
shmwrite( $id, $test->current_test, 0, 60 ) or die $!;
}
else {
waitpid( $child_pid, 0 );
shmread( $id, $test_num, 0, 60 ) or die $!;
$test->current_test($test_num);
ok 1, 'in the parent';
}
Basically, if I fork a child, when we return, Test::Builder will not have the
new test count, so I explicitly use shared memory [1]. While the above runs
just fine with prove, runtests (from the TAP::Parser distribution), fails with
the following:
ok 1 - mytest called
ok 2 - in the child
ok 3 - in the parent
1..3
All 3 subtests passed
Test Summary Report
-------------------
forkingtest.pl (Wstat: 0 Tests: 3 Failed: 0)
Parse errors: No plan found in TAP output
Files=1, Tests=3, 0 wallclock secs ( 0.05 cusr + 0.02 csys = 0.07 CPU)
However, both prove and runtests fail if I use this in Test::Class:
#!/usr/bin/perl
use strict;
use warnings;
{
package TestBase;
use base 'Test::Class';
INIT { Test::Class->runtests }
}
{
package My::Test::Class;
use Test::More;
use Test::Builder;
use IPC::SysV qw< IPC_PRIVATE IPC_RMID S_IRWXU >;
BEGIN { @My::Test::Class::ISA = 'TestBase' }
sub mytest : Tests(3) {
ok 1, 'mytest called';
my $test = Test::Builder->new;
my $id = shmget(IPC_PRIVATE, 2000, S_IRWXU) or die $!;
my $test_num;
if ( !defined( my $child_pid = fork() ) ) {
diag "Cannot fork: $!";
}
elsif ( !$child_pid ) {
ok 1, 'in the child';
shmwrite( $id, $test->current_test, 0, 60 ) or die $!;
}
else {
waitpid( $child_pid, 0 );
shmread( $id, $test_num, 0, 60 ) or die $!;
$test->current_test($test_num);
ok 1, 'in the parent';
}
}
}
1;
Both of them give results like this (note the spurious SKIP):
TestBase....#
# My::Test::Class->mytest
1..3
ok 1 - mytest called
ok 2 - in the child
ok 3 # skip 1
ok 3 - in the parent
Don't know which tests failed: got 4 ok, expected 3
Failed Test Stat Wstat Total Fail List of Failed
-------------------------------------------------------------------------------
TestBase.pm 3 ?? ??
1 subtest skipped.
Failed 1/1 test scripts. -1/3 subtests failed.
Files=1, Tests=3, 1 wallclock secs ( 0.12 cusr + 0.02 csys = 0.14 CPU)
Failed 1/1 test programs. -1/3 subtests failed.
Am I doing something really stupid here? Could I be using shared memory
incorrectly?
Cheers,
Ovid
[1] I don't use IPC::Shareable because it won't build due to a bug that's been
reported for over a year. http://rt.cpan.org/Public/Bug/Display.html?id=19169
--
Buy the book - http://www.oreilly.com/catalog/perlhks/
Perl and CGI - http://users.easystreet.com/ovid/cgi_course/
Personal blog - http://publius-ovidius.livejournal.com/
Tech blog - http://use.perl.org/~Ovid/journal/