From e27ced91f9e72edc37fd92249235cd444152a28a Mon Sep 17 00:00:00 2001 From: Sergiotarxz Date: Mon, 12 Feb 2024 17:21:23 +0100 Subject: [PATCH] Migrating reactor_ev to subtests. --- t/mojo/reactor_ev.t | 590 +++++++++++++++++++++++--------------------- 1 file changed, 306 insertions(+), 284 deletions(-) diff --git a/t/mojo/reactor_ev.t b/t/mojo/reactor_ev.t index dddfde11f1..a0ee749a83 100644 --- a/t/mojo/reactor_ev.t +++ b/t/mojo/reactor_ev.t @@ -8,307 +8,329 @@ plan skip_all => 'EV 4.32+ required for this test!' unless eval use IO::Socket::INET; use Mojo::Util qw(steady_time); -# Instantiation -use_ok 'Mojo::Reactor::EV'; -my $reactor = Mojo::Reactor::EV->new; -is ref $reactor, 'Mojo::Reactor::EV', 'right object'; -is ref Mojo::Reactor::EV->new, 'Mojo::Reactor::Poll', 'right object'; -undef $reactor; -is ref Mojo::Reactor::EV->new, 'Mojo::Reactor::EV', 'right object'; -use_ok 'Mojo::IOLoop'; -$reactor = Mojo::IOLoop->singleton->reactor; -is ref $reactor, 'Mojo::Reactor::EV', 'right object'; +my ($reactor, $reactor2, $listen, $readable, $writable); +my ($client, $port, $server, $recurring); -# Make sure it stops automatically when not watching for events -my $triggered; -Mojo::IOLoop->next_tick(sub { $triggered++ }); -Mojo::IOLoop->start; -ok $triggered, 'reactor waited for one event'; -my $time = time; -Mojo::IOLoop->start; -Mojo::IOLoop->one_tick; -ok time < ($time + 10), 'stopped automatically'; +subtest 'Instantiation' => sub { + use_ok 'Mojo::Reactor::EV'; + $reactor = Mojo::Reactor::EV->new; -# Listen -my $listen = IO::Socket::INET->new(Listen => 5, LocalAddr => '127.0.0.1'); -my $port = $listen->sockport; -my ($readable, $writable); -$reactor->io($listen => sub { pop() ? $writable++ : $readable++ })->watch($listen, 0, 0)->watch($listen, 1, 1); -$reactor->timer(0.025 => sub { shift->stop }); -$reactor->start; -ok !$readable, 'handle is not readable'; -ok !$writable, 'handle is not writable'; + is ref $reactor, 'Mojo::Reactor::EV', 'right object'; + is ref Mojo::Reactor::EV->new, 'Mojo::Reactor::Poll', 'right object'; + undef $reactor; + is ref Mojo::Reactor::EV->new, 'Mojo::Reactor::EV', 'right object'; + use_ok 'Mojo::IOLoop'; + $reactor = Mojo::IOLoop->singleton->reactor; + is ref $reactor, 'Mojo::Reactor::EV', 'right object'; +}; -# Connect -my $client = IO::Socket::INET->new(PeerAddr => '127.0.0.1', PeerPort => $port); -$reactor->timer(1 => sub { shift->stop }); -$reactor->start; -ok $readable, 'handle is readable'; -ok !$writable, 'handle is not writable'; +subtest 'Make sure it stops automatically when not watching for events' => sub { + my $triggered; + Mojo::IOLoop->next_tick(sub { $triggered++ }); + Mojo::IOLoop->start; + ok $triggered, 'reactor waited for one event'; + my $time = time; + Mojo::IOLoop->start; + Mojo::IOLoop->one_tick; + ok time < ($time + 10), 'stopped automatically'; +}; -# Accept -my $server = $listen->accept; -ok $reactor->remove($listen), 'removed'; -ok !$reactor->remove($listen), 'not removed again'; -($readable, $writable) = (); -$reactor->io($client => sub { pop() ? $writable++ : $readable++ }); -$reactor->again($reactor->timer(0.025 => sub { shift->stop })); -$reactor->start; -ok !$readable, 'handle is not readable'; -ok $writable, 'handle is writable'; -print $client "hello!\n"; -sleep 1; -ok $reactor->remove($client), 'removed'; -($readable, $writable) = (); -$reactor->io($server => sub { pop() ? $writable++ : $readable++ }); -$reactor->watch($server, 1, 0); -$reactor->timer(0.025 => sub { shift->stop }); -$reactor->start; -ok $readable, 'handle is readable'; -ok !$writable, 'handle is not writable'; -($readable, $writable) = (); -$reactor->watch($server, 1, 1); -$reactor->timer(0.025 => sub { shift->stop }); -$reactor->start; -ok $readable, 'handle is readable'; -ok $writable, 'handle is writable'; -($readable, $writable) = (); -$reactor->watch($server, 0, 0); -$reactor->timer(0.025 => sub { shift->stop }); -$reactor->start; -ok !$readable, 'handle is not readable'; -ok !$writable, 'handle is not writable'; -($readable, $writable) = (); -$reactor->watch($server, 1, 0); -$reactor->timer(0.025 => sub { shift->stop }); -$reactor->start; -ok $readable, 'handle is readable'; -ok !$writable, 'handle is not writable'; -($readable, $writable) = (); -$reactor->io($server => sub { pop() ? $writable++ : $readable++ }); -$reactor->timer(0.025 => sub { shift->stop }); -$reactor->start; -ok $readable, 'handle is readable'; -ok $writable, 'handle is writable'; +subtest 'Listen' => sub { + $listen = IO::Socket::INET->new(Listen => 5, LocalAddr => '127.0.0.1'); + $port = $listen->sockport; + $reactor->io($listen => sub { pop() ? $writable++ : $readable++ })->watch($listen, 0, 0)->watch($listen, 1, 1); + $reactor->timer(0.025 => sub { shift->stop }); + $reactor->start; + ok !$readable, 'handle is not readable'; + ok !$writable, 'handle is not writable'; +}; -# Timers -my ($timer, $recurring); -$reactor->timer(0 => sub { $timer++ }); -ok $reactor->remove($reactor->timer(0 => sub { $timer++ })), 'removed'; -my $id = $reactor->recurring(0 => sub { $recurring++ }); -($readable, $writable) = (); -$reactor->timer(0.025 => sub { shift->stop }); -$reactor->start; -ok $readable, 'handle is readable again'; -ok $writable, 'handle is writable again'; -ok $timer, 'timer was triggered'; -ok $recurring, 'recurring was triggered'; -my $done; -($readable, $writable, $timer, $recurring) = (); -$reactor->timer(0.025 => sub { $done = shift->is_running }); -$reactor->one_tick while !$done; -ok $readable, 'handle is readable again'; -ok $writable, 'handle is writable again'; -ok !$timer, 'timer was not triggered'; -ok $recurring, 'recurring was triggered again'; -($readable, $writable, $timer, $recurring) = (); -$reactor->timer(0.025 => sub { shift->stop }); -$reactor->start; -ok $readable, 'handle is readable again'; -ok $writable, 'handle is writable again'; -ok !$timer, 'timer was not triggered'; -ok $recurring, 'recurring was triggered again'; -ok $reactor->remove($id), 'removed'; -ok !$reactor->remove($id), 'not removed again'; -($readable, $writable, $timer, $recurring) = (); -$reactor->timer(0.025 => sub { shift->stop }); -$reactor->start; -ok $readable, 'handle is readable again'; -ok $writable, 'handle is writable again'; -ok !$timer, 'timer was not triggered'; -ok !$recurring, 'recurring was not triggered again'; -($readable, $writable, $timer, $recurring) = (); -my $next_tick; -is $reactor->next_tick(sub { $next_tick++ }), undef, 'returned undef'; -$id = $reactor->recurring(0 => sub { $recurring++ }); -$reactor->timer(0.025 => sub { shift->stop }); -$reactor->start; -ok $readable, 'handle is readable again'; -ok $writable, 'handle is writable again'; -ok !$timer, 'timer was not triggered'; -ok $recurring, 'recurring was triggered again'; -ok $next_tick, 'next tick was triggered'; +subtest 'Connect' => sub { + $client = IO::Socket::INET->new(PeerAddr => '127.0.0.1', PeerPort => $port); + $reactor->timer(1 => sub { shift->stop }); + $reactor->start; + ok $readable, 'handle is readable'; + ok !$writable, 'handle is not writable'; +}; -# Reset -$reactor->next_tick(sub { die 'Reset failed' }); -$reactor->reset; -($readable, $writable, $recurring) = (); -$reactor->next_tick(sub { shift->stop }); -$reactor->start; -ok !$readable, 'io event was not triggered again'; -ok !$writable, 'io event was not triggered again'; -ok !$recurring, 'recurring was not triggered again'; -my $reactor2 = Mojo::Reactor::EV->new; -is ref $reactor2, 'Mojo::Reactor::Poll', 'right object'; +subtest 'Accept' => sub { + $server = $listen->accept; + ok $reactor->remove($listen), 'removed'; + ok !$reactor->remove($listen), 'not removed again'; + ($readable, $writable) = (); + $reactor->io($client => sub { pop() ? $writable++ : $readable++ }); + $reactor->again($reactor->timer(0.025 => sub { shift->stop })); + $reactor->start; + ok !$readable, 'handle is not readable'; + ok $writable, 'handle is writable'; + print $client "hello!\n"; + sleep 1; + ok $reactor->remove($client), 'removed'; + ($readable, $writable) = (); + $reactor->io($server => sub { pop() ? $writable++ : $readable++ }); + $reactor->watch($server, 1, 0); + $reactor->timer(0.025 => sub { shift->stop }); + $reactor->start; + ok $readable, 'handle is readable'; + ok !$writable, 'handle is not writable'; + ($readable, $writable) = (); + $reactor->watch($server, 1, 1); + $reactor->timer(0.025 => sub { shift->stop }); + $reactor->start; + ok $readable, 'handle is readable'; + ok $writable, 'handle is writable'; + ($readable, $writable) = (); + $reactor->watch($server, 0, 0); + $reactor->timer(0.025 => sub { shift->stop }); + $reactor->start; + ok !$readable, 'handle is not readable'; + ok !$writable, 'handle is not writable'; + ($readable, $writable) = (); + $reactor->watch($server, 1, 0); + $reactor->timer(0.025 => sub { shift->stop }); + $reactor->start; + ok $readable, 'handle is readable'; + ok !$writable, 'handle is not writable'; + ($readable, $writable) = (); + $reactor->io($server => sub { pop() ? $writable++ : $readable++ }); + $reactor->timer(0.025 => sub { shift->stop }); + $reactor->start; + ok $readable, 'handle is readable'; + ok $writable, 'handle is writable'; +}; -# Ordered next_tick -my $result = []; -for my $i (1 .. 10) { - $reactor->next_tick(sub { push @$result, $i }); -} -$reactor->start; -is_deeply $result, [1 .. 10], 'right result'; +subtest 'Timers' => sub { + my $timer; + $reactor->timer(0 => sub { $timer++ }); + ok $reactor->remove($reactor->timer(0 => sub { $timer++ })), 'removed'; + my $id = $reactor->recurring(0 => sub { $recurring++ }); + ($readable, $writable) = (); + $reactor->timer(0.025 => sub { shift->stop }); + $reactor->start; + ok $readable, 'handle is readable again'; + ok $writable, 'handle is writable again'; + ok $timer, 'timer was triggered'; + ok $recurring, 'recurring was triggered'; + my $done; + ($readable, $writable, $timer, $recurring) = (); + $reactor->timer(0.025 => sub { $done = shift->is_running }); + $reactor->one_tick while !$done; + ok $readable, 'handle is readable again'; + ok $writable, 'handle is writable again'; + ok !$timer, 'timer was not triggered'; + ok $recurring, 'recurring was triggered again'; + ($readable, $writable, $timer, $recurring) = (); + $reactor->timer(0.025 => sub { shift->stop }); + $reactor->start; + ok $readable, 'handle is readable again'; + ok $writable, 'handle is writable again'; + ok !$timer, 'timer was not triggered'; + ok $recurring, 'recurring was triggered again'; + ok $reactor->remove($id), 'removed'; + ok !$reactor->remove($id), 'not removed again'; + ($readable, $writable, $timer, $recurring) = (); + $reactor->timer(0.025 => sub { shift->stop }); + $reactor->start; + ok $readable, 'handle is readable again'; + ok $writable, 'handle is writable again'; + ok !$timer, 'timer was not triggered'; + ok !$recurring, 'recurring was not triggered again'; + ($readable, $writable, $timer, $recurring) = (); + my $next_tick; + is $reactor->next_tick(sub { $next_tick++ }), undef, 'returned undef'; + $id = $reactor->recurring(0 => sub { $recurring++ }); + $reactor->timer(0.025 => sub { shift->stop }); + $reactor->start; + ok $readable, 'handle is readable again'; + ok $writable, 'handle is writable again'; + ok !$timer, 'timer was not triggered'; + ok $recurring, 'recurring was triggered again'; + ok $next_tick, 'next tick was triggered'; +}; -# Reset while watchers are active -$writable = undef; -$reactor->io($_ => sub { ++$writable and shift->reset })->watch($_, 0, 1) for $client, $server; -$reactor->start; -is $writable, 1, 'only one handle was writable'; +subtest 'Reset' => sub { + $reactor->next_tick(sub { die 'Reset failed' }); + $reactor->reset; + ($readable, $writable, $recurring) = (); + $reactor->next_tick(sub { shift->stop }); + $reactor->start; + ok !$readable, 'io event was not triggered again'; + ok !$writable, 'io event was not triggered again'; + ok !$recurring, 'recurring was not triggered again'; + $reactor2 = Mojo::Reactor::EV->new; + is ref $reactor2, 'Mojo::Reactor::Poll', 'right object'; +}; -# Concurrent reactors -$timer = 0; -$reactor->recurring(0 => sub { $timer++ }); -my $timer2; -$reactor2->recurring(0 => sub { $timer2++ }); -$reactor->timer(0.025 => sub { shift->stop }); -$reactor->start; -ok $timer, 'timer was triggered'; -ok !$timer2, 'timer was not triggered'; -$timer = $timer2 = 0; -$reactor2->timer(0.025 => sub { shift->stop }); -$reactor2->start; -ok !$timer, 'timer was not triggered'; -ok $timer2, 'timer was triggered'; -$timer = $timer2 = 0; -$reactor->timer(0.025 => sub { shift->stop }); -$reactor->start; -ok $timer, 'timer was triggered'; -ok !$timer2, 'timer was not triggered'; -$timer = $timer2 = 0; -$reactor2->timer(0.025 => sub { shift->stop }); -$reactor2->start; -ok !$timer, 'timer was not triggered'; -ok $timer2, 'timer was triggered'; -$reactor->reset; - -# Restart timer -my ($single, $pair, $one, $two, $last); -$reactor->timer(0.025 => sub { $single++ }); -$one = $reactor->timer( - 0.025 => sub { - my $reactor = shift; - $last++ if $single && $pair; - $pair++ ? $reactor->stop : $reactor->again($two); - } -); -$two = $reactor->timer( - 0.025 => sub { - my $reactor = shift; - $last++ if $single && $pair; - $pair++ ? $reactor->stop : $reactor->again($one); +subtest 'Ordered next_tick' => sub { + my $result = []; + for my $i (1 .. 10) { + $reactor->next_tick(sub { push @$result, $i }); } -); -$reactor->start; -is $pair, 2, 'timer pair was triggered'; -ok $single, 'single timer was triggered'; -ok $last, 'timers were triggered in the right order'; + $reactor->start; + is_deeply $result, [1 .. 10], 'right result'; +}; -# Reset timer -my $before = steady_time; -my ($after, $again); -$one = $reactor->timer(300 => sub { $after = steady_time }); -$two = $reactor->recurring( - 300 => sub { - my $reactor = shift; - $reactor->remove($two) if ++$again > 3; - } -); -$reactor->timer( - 0.025 => sub { - my $reactor = shift; - $reactor->again($one, 0.025); - $reactor->again($two, 0.025); - } -); -$reactor->start; -ok $after, 'timer was triggered'; -ok(($after - $before) < 200, 'less than 200 seconds'); -is $again, 4, 'recurring timer triggered four times'; +subtest 'Reset while watchers are active' => sub { + $writable = undef; + $reactor->io($_ => sub { ++$writable and shift->reset })->watch($_, 0, 1) for $client, $server; + $reactor->start; + is $writable, 1, 'only one handle was writable'; +}; -# Restart inactive timer -$id = $reactor->timer(0 => sub { }); -ok $reactor->remove($id), 'removed'; -eval { $reactor->again($id) }; -like $@, qr/Timer not active/, 'right error'; +subtest 'Concurrent reactors' => sub { + my $timer = 0; + $reactor->recurring(0 => sub { $timer++ }); + my $timer2; + $reactor2->recurring(0 => sub { $timer2++ }); + $reactor->timer(0.025 => sub { shift->stop }); + $reactor->start; + ok $timer, 'timer was triggered'; + ok !$timer2, 'timer was not triggered'; + $timer = $timer2 = 0; + $reactor2->timer(0.025 => sub { shift->stop }); + $reactor2->start; + ok !$timer, 'timer was not triggered'; + ok $timer2, 'timer was triggered'; + $timer = $timer2 = 0; + $reactor->timer(0.025 => sub { shift->stop }); + $reactor->start; + ok $timer, 'timer was triggered'; + ok !$timer2, 'timer was not triggered'; + $timer = $timer2 = 0; + $reactor2->timer(0.025 => sub { shift->stop }); + $reactor2->start; + ok !$timer, 'timer was not triggered'; + ok $timer2, 'timer was triggered'; + $reactor->reset; +}; -# Change inactive I/O watcher -ok !$reactor->remove($listen), 'not removed again'; -eval { $reactor->watch($listen, 1, 1) }; -like $@, qr!I/O watcher not active!, 'right error'; +subtest 'Restart timer' => sub { + my ($single, $pair, $last, $one, $two); + $reactor->timer(0.025 => sub { $single++ }); + $one = $reactor->timer( + 0.025 => sub { + my $reactor = shift; + $last++ if $single && $pair; + $pair++ ? $reactor->stop : $reactor->again($two); + } + ); + $two = $reactor->timer( + 0.025 => sub { + my $reactor = shift; + $last++ if $single && $pair; + $pair++ ? $reactor->stop : $reactor->again($one); + } + ); + $reactor->start; + is $pair, 2, 'timer pair was triggered'; + ok $single, 'single timer was triggered'; + ok $last, 'timers were triggered in the right order'; +}; -# Error -my $err; -$reactor->unsubscribe('error')->on( - error => sub { - shift->stop; - $err = pop; - } -); -$reactor->timer(0 => sub { die "works!\n" }); -$reactor->start; -like $err, qr/works!/, 'right error'; +subtest 'Reset timer' => sub { + my $before = steady_time; + my ($after, $again, $one, $two); + $one = $reactor->timer(300 => sub { $after = steady_time }); + $two = $reactor->recurring( + 300 => sub { + my $reactor = shift; + $reactor->remove($two) if ++$again > 3; + } + ); + $reactor->timer( + 0.025 => sub { + my $reactor = shift; + $reactor->again($one, 0.025); + $reactor->again($two, 0.025); + } + ); + $reactor->start; + ok $after, 'timer was triggered'; + ok(($after - $before) < 200, 'less than 200 seconds'); + is $again, 4, 'recurring timer triggered four times'; +}; -# Reset events -$reactor->on(error => sub { }); -ok $reactor->has_subscribers('error'), 'has subscribers'; -$reactor->reset; -ok !$reactor->has_subscribers('error'), 'no subscribers'; +subtest 'Restart inactive timer' => sub { + my $id = $reactor->timer(0 => sub { }); + ok $reactor->remove($id), 'removed'; + eval { $reactor->again($id) }; + like $@, qr/Timer not active/, 'right error'; +}; -# Recursion -$timer = undef; -$reactor = $reactor->new; -$reactor->timer(0 => sub { ++$timer and shift->one_tick }); -$reactor->one_tick; -is $timer, 1, 'timer was triggered once'; +subtest 'Change inactive I/O watcher' => sub { + ok !$reactor->remove($listen), 'not removed again'; + eval { $reactor->watch($listen, 1, 1) }; + like $@, qr!I/O watcher not active!, 'right error'; +}; -# Detection -is(Mojo::Reactor->detect, 'Mojo::Reactor::EV', 'right class'); +subtest 'Error' => sub { + my $err; + $reactor->unsubscribe('error')->on( + error => sub { + shift->stop; + $err = pop; + } + ); + $reactor->timer(0 => sub { die "works!\n" }); + $reactor->start; + like $err, qr/works!/, 'right error'; +}; -# Reactor in control -is ref Mojo::IOLoop->singleton->reactor, 'Mojo::Reactor::EV', 'right object'; -ok !Mojo::IOLoop->is_running, 'loop is not running'; -my ($buffer, $server_err, $server_running, $client_err, $client_running); -$id = Mojo::IOLoop->server( - {address => '127.0.0.1'} => sub { - my ($loop, $stream) = @_; - $stream->write('test' => sub { shift->write('321') }); - $server_running = Mojo::IOLoop->is_running; - eval { Mojo::IOLoop->start }; - $server_err = $@; - } -); -$port = Mojo::IOLoop->acceptor($id)->port; -Mojo::IOLoop->client( - {port => $port} => sub { - my ($loop, $err, $stream) = @_; - $stream->on( - read => sub { - my ($stream, $chunk) = @_; - $buffer .= $chunk; - return unless $buffer eq 'test321'; - Mojo::IOLoop->singleton->reactor->stop; - } - ); - $client_running = Mojo::IOLoop->is_running; - eval { Mojo::IOLoop->start }; - $client_err = $@; - } -); -Mojo::IOLoop->singleton->reactor->start; -ok !Mojo::IOLoop->is_running, 'loop is not running'; -like $server_err, qr/^Mojo::IOLoop already running/, 'right error'; -like $client_err, qr/^Mojo::IOLoop already running/, 'right error'; -ok $server_running, 'loop is running'; -ok $client_running, 'loop is running'; +subtest 'Reset events' => sub { + $reactor->on(error => sub { }); + ok $reactor->has_subscribers('error'), 'has subscribers'; + $reactor->reset; + ok !$reactor->has_subscribers('error'), 'no subscribers'; +}; + +subtest 'Recursion' => sub { + my $timer = undef; + $reactor = $reactor->new; + $reactor->timer(0 => sub { ++$timer and shift->one_tick }); + $reactor->one_tick; + is $timer, 1, 'timer was triggered once'; +}; + +subtest 'Detection' => sub { + is(Mojo::Reactor->detect, 'Mojo::Reactor::EV', 'right class'); +}; + +subtest 'Reactor in control' => sub { + is ref Mojo::IOLoop->singleton->reactor, 'Mojo::Reactor::EV', 'right object'; + ok !Mojo::IOLoop->is_running, 'loop is not running'; + my ($buffer, $server_err, $server_running, $client_err, $client_running); + my $id = Mojo::IOLoop->server( + {address => '127.0.0.1'} => sub { + my ($loop, $stream) = @_; + $stream->write('test' => sub { shift->write('321') }); + $server_running = Mojo::IOLoop->is_running; + eval { Mojo::IOLoop->start }; + $server_err = $@; + } + ); + $port = Mojo::IOLoop->acceptor($id)->port; + Mojo::IOLoop->client( + {port => $port} => sub { + my ($loop, $err, $stream) = @_; + $stream->on( + read => sub { + my ($stream, $chunk) = @_; + $buffer .= $chunk; + return unless $buffer eq 'test321'; + Mojo::IOLoop->singleton->reactor->stop; + } + ); + $client_running = Mojo::IOLoop->is_running; + eval { Mojo::IOLoop->start }; + $client_err = $@; + } + ); + Mojo::IOLoop->singleton->reactor->start; + ok !Mojo::IOLoop->is_running, 'loop is not running'; + like $server_err, qr/^Mojo::IOLoop already running/, 'right error'; + like $client_err, qr/^Mojo::IOLoop already running/, 'right error'; + ok $server_running, 'loop is running'; + ok $client_running, 'loop is running'; +}; done_testing();