The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Test::MultiFork - Test suite support for multi-process programs

SYNOPSIS

        use Test::MultiFork;

        ($name, $letter, $number) = procname([new name])
        lockcommon()
        @oldvalues = getcommon()
        setcommon(@newvalues)
        unlockcommon()

        use Test::MultiFork qw(groupwait setgroup dofork stderr bail_on_bad_plan)

        groupwait([$tag])
        $oldgroup = setgroup([$newgroup])
        dofork(fork_specification)

DESCRIPTION

This test module is to support creating test suites for programs and modules that run as multiple processes and do mostly blocking I/O.

Test::MultiFork handles the forking so that it can set up each child to coordinate the output. The output from each child fork is redirected to the parent. Each fork produces normal test output -- possibly using normal test modules like Test::Simple. The output is collected and rewritten by the parent process.

Each child fork has a letter and number designation. The forks are created by dofork(). Dofork takes a specifiction on the form: ([a-z](\d*))+. That is to say, one or more lower-case letters, each optionally followd by a number. The number says how many children to fork for that letter (default one). The specifier ab2c3 means have one a child (numbered 1); two b children (numbered 1, 2); and three c children (numbered 1, 2, 3).

To aid in writing tests, Test::MultiFork will pass data between the child processes. The data is test-writer defined.

SOURCE FILTER

Test::MultiFork acts as a source filter on your code. It does this so that it can do lock-step execution control.

The source filtering is controlled with pseudo labels. The labels must be the only thing on the line. The main source control is a label like FORK_abc:. This label tells Test::MultiFork how many times to fork (see above). Whatever comes after the FORK_ and before the : is a fork specifier.

With a FORK_abc: label, varient execution labels are enabled. Varient execution labels must be all lowercase. This is to allow you to use something different for you loop control labels. This module can be used without putting in any special labels.

Outside of a function, a varient execution label will synchronize all the program forks to that line of code. As each fork reaches that line, it will stop and wait until all forks get there. At that point, all of the forks will start up and run again.

Inside or outside of a function, once a varient execution labels is seen, source code is turned on or off (commented out) depending on if the process fork letter is in the label.

For example:

        # let's fork 5 times
        FORK_abc2d:

        ab:
        print "I'm an 'a' or 'b' process\n";

        cd:
        print "I'm an 'c' or 'd' process\n";

        abcd:
        print "we are all running in lockstep\n";

        sub xyz {
        a: 
                print "only a does something in this function\n";
        abcd:
        }

Since the processes run in lockstep (synchronized at the labels), loop controls must cover all processes.

In addition to fork() and the varient execution labels, you can override a default signal selection for debugging. By default the USR1 signal is used to aid debugging: if the parent process bails out, it will send USR1 signals to all the children to ask them to print out some diagnostics. The special label SIGNAL_xyz: changes which signal to use. Substitute xyz with your choice of signal or none to disable this feature.

IMPORTS

stderr

Import 'stderr' to send the STDERR output from each fork through the parent for tagging. The default is to leave STDERR alone.

bail_on_bad_plan

Bail out if a test plan isn't followed. This is most useful as a way to exit early if one of the fork()ed children exits early.

colorize

If $ENV{TERM} =~ /xterm/, then escape codes will be printed to change the background and foreground text colors so that each fork()ed child has a different color scheme.

FUNCTIONS

lockcommon()

Sets a lock on the shared common data.

getcommon()

Returns the current value of the common data. The common data is an array. In scalar context, the first element is returned. getcommon does not care if the common data is locked.

setcommon(@newvalues)

Sets the value of the common data to the new values. Dies if common data lock isn't held.

unlockcommon()

Releases a lock on the shared common data. Dies if the lock isn't already held.

groupwait([$tag])

Wait for all process forks in the process group to get reach this same synchronization point as designated by the $tag. The default tag is the current source file name and line number. All processes start in the default group. This is the function used to implement the varient execution lockstep synchronization.

setgroup([$newgroup])

With a $newgroup, changes the process' group identity. All processes start in group default. Returns the old group name.

dofork($fork_specification)

Fork off children processes. The parent process becomes the special-purpose test coordinator. The specification is as detailed in the DESCRIPTION above.

procname([$new_name])

Change the fork's name. The return value is a list: the current name, process' letter, the process' number.

INTEGRATION WITH TEST::*

Test::Simple and Test::More encourage you to specify a test plan at compile time. Make sure that dofork() is called before the test plan is specified.

When using Test::MultiFork's source filter in conjunction with Test::Builder anything built on top of it (eg: Test::Simple or Test::More) put Test::MultiFork first in the use list.

SEE ALSO

Test::Harness Test::Builder Test::Simple Test::More Test

BUGS

This is new and bearly tested. Please provide feedback!

LICENSE

Copyright (C) 2003-2006 David Muir Sharnoff <muir@idiom.com>. This module may be used/copied/etc on the same terms as Perl itself.

4 POD Errors

The following errors were encountered while parsing the POD:

Around line 102:

'=item' outside of any '=over'

Around line 118:

You forgot a '=back' before '=head1'

Around line 120:

'=item' outside of any '=over'

Around line 166:

You forgot a '=back' before '=head1'