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/