Async-Event-Interval

 view release on metacpan or  search on metacpan

t/53-timeout.t  view on Meta::CPAN

{
    my $e = Async::Event::Interval->new(0.5, sub {});
    my $ok = eval { $e->timeout(0.5); 1 };
    my $err = $@;
    is $ok, undef, "timeout(0.5) croaks";
    like $err, qr/must be a non-negative integer/,
        "...with validation message";
}

# Empty string croaks (only undef or a non-negative integer are valid).
{
    my $e = Async::Event::Interval->new(0.5, sub {});
    my $ok = eval { $e->timeout(""); 1 };
    my $err = $@;
    is $ok, undef, "timeout('') croaks";
    like $err, qr/must be a non-negative integer/,
        "...with validation message";
}

# timeout(0) disables the timeout.
{
    my $e = Async::Event::Interval->new(0.5, sub {});
    $e->timeout(5);
    is $e->timeout, 5, "timeout set to 5";
    $e->timeout(0);
    is $e->timeout, 0, "timeout(0) disables";
}

# timeout(undef) also disables.
{
    my $e = Async::Event::Interval->new(0.5, sub {});
    $e->timeout(5);
    is $e->timeout, 5, "timeout set to 5";
    $e->timeout(undef);
    is $e->timeout, undef, "timeout(undef) disables";
}

# Run-once: callback completes under timeout, no error.
{
    my $e = Async::Event::Interval->new(0, sub {});
    $e->timeout(2);
    $e->start;
    select(undef, undef, undef, 0.25);
    is $e->runs,  1, "run-once under timeout: callback ran";
    is $e->errors, 0, "run-once under timeout: no errors";
}

# Run-once: callback exceeds timeout, error recorded.
{
    my $e = Async::Event::Interval->new(0, sub {
        select(undef, undef, undef, 5);
    });
    $e->timeout(1);
    $e->start;
    select(undef, undef, undef, 2);
    is $e->errors, 1, "run-once over timeout: errors incremented";
    like $e->error_message, qr/Callback timed out after 1 second/,
        "run-once over timeout: error_message records timeout";
}

# Interval mode: callback completes under timeout, multiple iterations.
{
    my $count = 0;
    my $e = Async::Event::Interval->new(0.1, sub { $count++ });
    $e->timeout(2);
    $e->start;
    select(undef, undef, undef, 0.5);
    $e->stop;
    cmp_ok $e->runs, '>=', 2, "interval under timeout: ran at least twice";
    is $e->errors, 0, "interval under timeout: no errors";
}

# Interval mode: callback exceeds timeout, child exits with error.
# A timeout in interval mode terminates the whole loop (the child dies
# via _pm->finish(1), same as any other crash); the user must restart()
# to resume. This pins down that design choice.
{
    my $e = Async::Event::Interval->new(0.1, sub {
        select(undef, undef, undef, 5);
    });
    $e->timeout(1);
    $e->start;
    select(undef, undef, undef, 2);
    is $e->errors, 1, "interval over timeout: errors incremented";
    like $e->error_message, qr/Callback timed out after 1 second/,
        "interval over timeout: error_message records timeout";
    is $e->status, 0,
        "interval over timeout: status() is 0 (child no longer running)";
    is $e->error, 1,
        "interval over timeout: error() is 1 (event needs restart)";
    is $e->pid, undef,
        "interval over timeout: pid() cleared by _detect_crash";
}

# Changing timeout() mid-stream takes effect on the next iteration.
# _run_callback reads $self->timeout from shared %events on each entry,
# so a setter call in the parent is visible to the child's next call.
{
    my $e = Async::Event::Interval->new(0.1, sub {
        select(undef, undef, undef, 2);
    });
    $e->timeout(5);                          # generous, 2s callback completes
    $e->start;
    my $waited = 0;
    until ($e->runs >= 1 || $waited >= 10) {
        select(undef, undef, undef, 0.1);
        $waited += 0.1;
    }
    is $e->errors, 0,
        "dynamic timeout: no errors under generous initial timeout";
    cmp_ok $e->runs, '>=', 1,
        "dynamic timeout: at least one iteration completed";

    $e->timeout(1);                          # shorten below callback runtime
    select(undef, undef, undef, 3.5);        # next iteration starts & fires
    is $e->errors, 1,
        "dynamic timeout: error recorded after timeout was shortened";
    like $e->error_message, qr/timed out after 1 second/,
        "dynamic timeout: error_message reflects the new timeout";
}



( run in 1.782 second using v1.01-cache-2.11-cpan-71847e10f99 )