The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
# $Id$
# -*-perl-*-

use strict;
use warnings;

require 't/lib/db-common.pl';

use TheSchwartz;
use Test::More tests => 2;

# how we keep track of if job was done twice:  signal from children back up to us
my $work_count = 0;
my $lost_race  = 0;
$SIG{USR1} = sub { $work_count++; };
$SIG{USR2} = sub { $lost_race++; };

# tell our parent when we lost a race
{
    no warnings 'once';
    $TheSchwartz::FIND_JOB_BATCH_SIZE = 2;

    $TheSchwartz::T_LOST_RACE = sub {
        $lost_race = 1;    # this one's in our child process.
        kill 'USR2', getppid();
    };

    $TheSchwartz::T_AFTER_GRAB_SELECT_BEFORE_UPDATE = sub {

       # force the race condition to happen, at least until we've triggered it
        select undef, undef, undef, 0.25
            unless $lost_race;
    };

}

# kill children on exit
my %children;    # pid -> 1

END {
    my @pids = keys %children;
    kill -9, @pids if @pids;
}

my $jobs = 40;

run_tests_innodb(
    2,
    sub {

        # get one job into database, to see if children do it twice:
        {
            my $client = test_client( dbs => ['ts1'] );
            for ( 1 .. $jobs ) {
                $client->insert( "Worker::Addition", { numbers => [ 1, 2 ] } )
                    or die;
            }
        }

        # two children to race
        work();
        work();

        # hang out waiting for children to init/race/finish
        #
        while ( $work_count < $jobs ) {
            sleep 1;
        }
        my $now = time();
        while ( time < $now + 2 ) {
            sleep 1;
        }

        is( $work_count, $jobs, "$jobs jobs done" );
        ok( $lost_race, "lost the race at least once" );
        teardown_dbs('ts1');
    }
);

sub work {

    # parent:
    if ( my $childpid = fork() ) {
        $children{$childpid} = 1;
        return;
    }

    my $client = test_client(
        dbs  => ['ts1'],
        init => 0
    );

    # child:
    while ( my $job = Worker::Addition->grab_job($client) ) {
        eval { Worker::Addition->work($job); };
    }
    exit 0;
}

############################################################################
package Worker::Addition;
use base 'TheSchwartz::Worker';

sub work {
    my ( $class, $job ) = @_;
    kill 'USR1', getppid();
    $job->completed;
}

# tell framework to set 'grabbed_until' to time() + 60.  because if
# we can't  add some numbers in 30 seconds, our process probably
# failed and work should be reassigned.
sub grab_for {5}