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

NAME

Test::AnyEvent::Time - Time-related tests for asynchronous routines using AnyEvent

VERSION

Version 0.01

SYNOPSIS

    use Test::AnyEvent::Time tests => 4;
    use Test::More;
    
    
    time_within_ok sub {
        my $cv = shift;
        your_asynchronous_func(
            data => 0.5,
            cb => sub {
                my ($result) = @_;
                note "This is the result: $result";
    
                ## Notify that this function is done.
                $cv->send();
            }
        );
    }, 10, "your_asynchronous_func() should return its result within 10 seconds.";
    
    
    time_within_ok sub {
        my $cv = shift;
        your_asynchronous_func(
            data => 1,
            cb => sub {
                ## Oops! I forgot to signal the CV!
            }
        );
    }, 4, "Timeout in 4 seconds and the test fails";
    
    
    time_between_ok sub {
        my $cv = shift;
        your_asynchronous_func(
            data => 1,
            cb => sub { $cv->send() }
        );
    }, 0.3, 1.5, "your_asynchronous_func() should return in between 0.3 seconds and 1.5 seconds";
    
    
    time_cmp_ok sub {
        my $cv = shift;
        your_asynchronous_func(
            data => 1,
            cb => sub { $cv->send() }
        );
    }, ">", 0.3, "your_asynchronous_func() should take more than 0.3 seconds. No timeout set.";
    
    
    ## You can just measure the time your asynchronous function takes.
    my $time = elapsed_time sub {
        my $cv = shift;
        your_asynchronous_func(
            data => 5,
            cb => sub { $cv->send }
        );
    };
    note("It takes $time seconds.");

DESCRIPTION

This module provides some functions that test an asynchronous routine in terms of its execution time. To measure their execution time, asynchronous routines to be tested have to notify the test functions of their finish by calling send() (or end()) method on a conditional variable in AnyEvent framework.

This module is built with Test::Builder module, so you can use this together with Test::More and other Test::Builder-based test modules.

EXPORTED FUNCTIONS

$ok = time_within_ok $cb->($cv), $max_time[, $description];

Tests whether the asynchronous subroutine $cb finishes within $max_time seconds. $description is the test description, which can be omitted.

The argument $cb is a subroutine reference. It gets a conditional variable $cv as its first argument. When the routine is done, you must call $cv->send() to signal that it's finished. So the typical usage of time_within_ok() would be:

    time_within_ok sub {
        my $cv = shift;
        your_testee_func($some_data, sub {
            ## callback function of your_testee_func
            ...           ## some processing on the result
            $cv->send();  ## "I'm done!"
        });
    }, 10, "your_testee_func should finish within 10 sec.";

You can also use $cv->begin() and $cv->end() in the routine $cb:

    time_within_ok sub {
        my $cv = shift;
        foreach my $single_data (@bunch_of_data) {
            $cv->begin();
            your_testee_func($single_data, sub { $cv->end() });
        }
    }, 10, "It should process all the bunch_of_data in parallel within 10 sec.";

time_within_ok() will block until either the $cv is signaled by the testee $cb or $max_time has passed. In the latter case, though, time_within_ok() does not stop the execution of $cb, because it does not know how to do it.

$ok = time_between_ok $cb->($cv), $min_time, $max_time[, $description];

Tests whether the asynchronous subroutine $cb finishes in between $min_time seconds and $max_time seconds. You have to signal $cv when $cb finishes, just as in time_within_ok() above.

$ok = time_cmp_ok $cb->($cv), $op, $expected_time[, $timeout, $description];

Generic form of the above two test functions. This function measures the time that the asynchronous routine $cb takes to finish, and compares it with $expected_time by the operator $op like cmp_ok() of Test::More module. I think time_within_ok() and time_between_ok() meet your need in most cases, though.

If $timeout is specified, time_cmp_ok() reports the result of "not ok" in $timeout seconds if $cb is not finished yet. Note that expiration of $timeout is always treated as error. For example:

    time_cmp_ok sub {
        my $cv = shift;
        my $w; $w = AE::timer 5, undef, sub {
            undef $w;
            $cv->send();
        };
    }, ">", 1, 2;

This times out in 2 seconds before the AE::timer fires. Because the test condition is "elapsed time > 1 second", it already meets the condition when it times out. However, the test result is "not ok". The testee routine must finish before the timeout.

If $timeout is not specified, there is no timeout. time_cmp_ok() will wait indefinitely for $cb to signal the $cv. It is possible that your $cb is somewhat broken and time_cmp_ok() never returns, so be careful!

$time = elapsed_time $cb->($cv)[, $timeout];

This function is not a test function, but measures the time that the asynchronous routine $cb takes to finish. If $timeout is specified, the function returns the result in $timeout seconds even if $cb is not finished yet.

elapsed_time() returns the time in seconds that $cb takes to signal $cv. It returns -1 if $timeout is specified and it expires. It returns undef in other erroneous situations, such as not providing $cb.

SEE ALSO

AnyEvent

AUTHOR

Toshio Ito, <debug.ito at gmail.com>

LICENSE

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.