Hello community,

here is the log from the commit of package perl-Mojolicious for 
openSUSE:Factory checked in at 2020-09-29 19:01:58
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/perl-Mojolicious (Old)
 and      /work/SRC/openSUSE:Factory/.perl-Mojolicious.new.4249 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "perl-Mojolicious"

Tue Sep 29 19:01:58 2020 rev:142 rq:838283 version:8.60

Changes:
--------
--- /work/SRC/openSUSE:Factory/perl-Mojolicious/perl-Mojolicious.changes        
2020-09-15 16:34:47.798970545 +0200
+++ 
/work/SRC/openSUSE:Factory/.perl-Mojolicious.new.4249/perl-Mojolicious.changes  
    2020-09-29 19:02:16.693808096 +0200
@@ -1,0 +2,10 @@
+Mon Sep 28 03:14:25 UTC 2020 - Tina Müller <[email protected]>
+
+- updated to 8.60
+   see /usr/share/doc/packages/perl-Mojolicious/Changes
+
+  8.60  2020-09-27
+    - Improved reset method in Mojo::IOLoop to prevent close event to be 
emitted in affected streams. (kiwiroy)
+    - Improved cookbook with Envoy deployment recipe. (zakame)
+
+-------------------------------------------------------------------

Old:
----
  Mojolicious-8.59.tar.gz

New:
----
  Mojolicious-8.60.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ perl-Mojolicious.spec ++++++
--- /var/tmp/diff_new_pack.WD5PBR/_old  2020-09-29 19:02:17.393808946 +0200
+++ /var/tmp/diff_new_pack.WD5PBR/_new  2020-09-29 19:02:17.397808951 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           perl-Mojolicious
-Version:        8.59
+Version:        8.60
 Release:        0
 %define cpan_name Mojolicious
 Summary:        Real-time web framework

++++++ Mojolicious-8.59.tar.gz -> Mojolicious-8.60.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Mojolicious-8.59/Changes new/Mojolicious-8.60/Changes
--- old/Mojolicious-8.59/Changes        2020-09-05 14:16:59.000000000 +0200
+++ new/Mojolicious-8.60/Changes        2020-09-27 17:46:20.000000000 +0200
@@ -1,4 +1,8 @@
 
+8.60  2020-09-27
+  - Improved reset method in Mojo::IOLoop to prevent close event to be emitted 
in affected streams. (kiwiroy)
+  - Improved cookbook with Envoy deployment recipe. (zakame)
+
 8.59  2020-09-05
   - Added l function to ojo. (kiwiroy)
   - Added MOJO_PROMISE_DEBUG environment variable to Mojo::Promise.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Mojolicious-8.59/META.json 
new/Mojolicious-8.60/META.json
--- old/Mojolicious-8.59/META.json      2020-09-13 18:04:04.000000000 +0200
+++ new/Mojolicious-8.60/META.json      2020-09-27 17:49:37.000000000 +0200
@@ -63,6 +63,6 @@
          "web" : "https://webchat.freenode.net/#mojo";
       }
    },
-   "version" : "8.59",
+   "version" : "8.60",
    "x_serialization_backend" : "JSON::PP version 4.05"
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Mojolicious-8.59/META.yml 
new/Mojolicious-8.60/META.yml
--- old/Mojolicious-8.59/META.yml       2020-09-13 18:04:04.000000000 +0200
+++ new/Mojolicious-8.60/META.yml       2020-09-27 17:49:37.000000000 +0200
@@ -34,5 +34,5 @@
   homepage: https://mojolicious.org
   license: http://www.opensource.org/licenses/artistic-license-2.0
   repository: https://github.com/mojolicious/mojo.git
-version: '8.59'
+version: '8.60'
 x_serialization_backend: 'CPAN::Meta::YAML version 0.018'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Mojolicious-8.59/lib/Mojo/IOLoop.pm 
new/Mojolicious-8.60/lib/Mojo/IOLoop.pm
--- old/Mojolicious-8.59/lib/Mojo/IOLoop.pm     2020-09-07 17:42:33.000000000 
+0200
+++ new/Mojolicious-8.60/lib/Mojo/IOLoop.pm     2020-09-27 02:33:25.000000000 
+0200
@@ -95,6 +95,7 @@
 
 sub reset {
   my $self = _instance(shift)->emit('reset');
+  $self->stream($_)->unsubscribe('close') for (keys %{$self->{in}}, keys 
%{$self->{out}});
   delete @$self{qw(accepting acceptors events in out stop)};
   $self->reactor->reset;
   $self->stop;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Mojolicious-8.59/lib/Mojolicious/Guides/Cookbook.pod 
new/Mojolicious-8.60/lib/Mojolicious/Guides/Cookbook.pod
--- old/Mojolicious-8.59/lib/Mojolicious/Guides/Cookbook.pod    2020-09-04 
00:57:31.000000000 +0200
+++ new/Mojolicious-8.60/lib/Mojolicious/Guides/Cookbook.pod    2020-09-27 
01:01:58.000000000 +0200
@@ -342,6 +342,56 @@
 
   ScriptAlias / /home/sri/my_app/script/my_app/
 
+=head2 Envoy
+
+L<Mojolicious> applications can be deployed on "cloud-native" environments 
that use L<Envoy|https://www.envoyproxy.io>,
+such as with this reverse proxy configuration similar to the Apache and Nginx 
ones above.
+
+  static_resources:
+    listeners:
+    - name: listener_0
+      address:
+        socket_address: { address: 0.0.0.0, port_value: 80 }
+      filter_chains:
+      - filters:
+        - name: envoy.filters.network.http_connection_manager
+          typed_config:
+            "@type": 
type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
+            codec_type: auto
+            stat_prefix: index_http
+            route_config:
+              name: local_route
+              virtual_hosts:
+              - name: service
+                domains: ["*"]
+                routes:
+                - match:
+                    prefix: "/"
+                  route:
+                    cluster: local_service
+            upgrade_configs:
+            - upgrade_type: websocket
+            http_filters:
+            - name: envoy.filters.http.router
+              typed_config:
+    clusters:
+    - name: local_service
+      connect_timeout: 0.25s
+      type: strict_dns
+      lb_policy: round_robin
+      load_assignment:
+        cluster_name: local_service
+        endpoints:
+        - lb_endpoints:
+          - endpoint:
+              address:
+                socket_address: { address: mojo, port_value: 8080 }
+                
+While this configuration works for simple applications, Envoy's typical use 
case is for implementing proxies of
+applications as a "service mesh" providing advanced filtering, load balancing, 
and observability features, such as
+seen in L<Istio|https://istio.io/latest/docs/ops/deployment/architecture/>. 
For more examples, visit the
+L<Envoy documentation|https://www.envoyproxy.io/docs/envoy/latest/start/start>.
+
 =head2 PSGI/Plack
 
 L<PSGI> is an interface between Perl web frameworks and web servers, and 
L<Plack> is a Perl module and toolkit that
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Mojolicious-8.59/lib/Mojolicious/Guides/Routing.pod 
new/Mojolicious-8.60/lib/Mojolicious/Guides/Routing.pod
--- old/Mojolicious-8.59/lib/Mojolicious/Guides/Routing.pod     2020-08-19 
22:42:00.000000000 +0200
+++ new/Mojolicious-8.60/lib/Mojolicious/Guides/Routing.pod     2020-09-27 
17:47:44.000000000 +0200
@@ -376,7 +376,7 @@
   # /foo/marcus -> {controller => 'foo', action => 'bar', user => 'marcus'}
   $r->get('/foo/:user')->to('foo#bar')->name('baz');
 
-  # Generate URL "/foo/marcus" for route "baz"
+  # Generate URL "/foo/marcus" for route "baz" (in previous request context)
   my $url = $c->url_for('baz');
 
   # Generate URL "/foo/jan" for route "baz"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Mojolicious-8.59/lib/Mojolicious.pm 
new/Mojolicious-8.60/lib/Mojolicious.pm
--- old/Mojolicious-8.59/lib/Mojolicious.pm     2020-09-07 17:42:23.000000000 
+0200
+++ new/Mojolicious-8.60/lib/Mojolicious.pm     2020-09-19 20:54:34.000000000 
+0200
@@ -58,7 +58,7 @@
 has validator => sub { Mojolicious::Validator->new };
 
 our $CODENAME = 'Supervillain';
-our $VERSION  = '8.59';
+our $VERSION  = '8.60';
 
 sub BUILD_DYNAMIC {
   my ($class, $method, $dyn_methods) = @_;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Mojolicious-8.59/t/mojo/ioloop.t 
new/Mojolicious-8.60/t/mojo/ioloop.t
--- old/Mojolicious-8.59/t/mojo/ioloop.t        2020-09-07 17:43:04.000000000 
+0200
+++ new/Mojolicious-8.60/t/mojo/ioloop.t        2020-09-27 02:33:17.000000000 
+0200
@@ -10,333 +10,354 @@
 use Mojo::IOLoop::Server;
 use Mojo::IOLoop::Stream;
 
-# Defaults
-my $loop = Mojo::IOLoop->new;
-is $loop->max_connections, 1000, 'right default';
-$loop = Mojo::IOLoop->new(max_connections => 10);
-is $loop->max_connections, 10, 'right value';
-
-# Double start
-my $err;
-Mojo::IOLoop->next_tick(sub {
-  my $loop = shift;
-  eval { $loop->start };
-  $err = $@;
-  $loop->stop;
-});
-Mojo::IOLoop->start;
-like $err, qr/^Mojo::IOLoop already running/, 'right error';
-
-# Double one_tick
-$err = undef;
-Mojo::IOLoop->next_tick(sub {
-  my $loop = shift;
-  eval { $loop->one_tick };
-  $err = $@;
-});
-Mojo::IOLoop->one_tick;
-like $err, qr/^Mojo::IOLoop already running/, 'right error';
-
-# Basic functionality
-my ($ticks, $timer, $hirestimer);
-my $id = $loop->recurring(0 => sub { $ticks++ });
-$loop->timer(
-  1 => sub {
-    shift->timer(0 => sub { shift->stop });
-    $timer++;
-  }
-);
-$loop->timer(0.25 => sub { $hirestimer++ });
-$loop->start;
-ok $timer,      'recursive timer works';
-ok $hirestimer, 'hires timer works';
-$loop->one_tick;
-ok $ticks > 2, 'more than two ticks';
-
-# Run again without first tick event handler
-my $before = $ticks;
-my $after;
-my $id2 = $loop->recurring(0 => sub { $after++ });
-$loop->remove($id);
-$loop->timer(0.5 => sub { shift->stop });
-$loop->start;
-$loop->one_tick;
-$loop->remove($id2);
-ok $after > 1, 'more than one tick';
-is $ticks, $before, 'no additional ticks';
-
-# Recurring timer
-my $count;
-$id = $loop->recurring(0.1 => sub { $count++ });
-$loop->timer(0.5 => sub { shift->stop });
-$loop->start;
-$loop->one_tick;
-$loop->remove($id);
-ok($count > 1,  'more than one recurring event');
-ok($count < 10, 'less than ten recurring events');
-
-# Handle and reset
-my ($handle, $handle2, $reset);
-Mojo::IOLoop->singleton->on(reset => sub { $reset++ });
-$id = Mojo::IOLoop->server(
-  (address => '127.0.0.1') => sub {
-    my ($loop, $stream) = @_;
-    $handle = $stream->handle;
-    Mojo::IOLoop->stop;
-  }
-);
-my $port = Mojo::IOLoop->acceptor($id)->port;
-Mojo::IOLoop->acceptor($id)->on(accept => sub { $handle2 = pop });
-$id2 = Mojo::IOLoop->client((address => '127.0.0.1', port => $port) => sub { 
});
-Mojo::IOLoop->start;
-$count = 0;
-Mojo::IOLoop->recurring(10 => sub { $timer++ });
-my $running;
-Mojo::IOLoop->next_tick(sub {
-  Mojo::IOLoop->reset;
-  $running = Mojo::IOLoop->is_running;
-});
-Mojo::IOLoop->start;
-ok !$running, 'not running';
-is $count, 0, 'no recurring events';
-ok !Mojo::IOLoop->acceptor($id), 'acceptor has been removed';
-ok !Mojo::IOLoop->stream($id2),  'stream has been removed';
-is $handle,     $handle2, 'handles are equal';
-isa_ok $handle, 'IO::Socket', 'right reference';
-is $reset,      1,            'reset event has been emitted once';
-
-# The poll reactor stops when there are no events being watched anymore
-my $time = time;
-Mojo::IOLoop->start;
-Mojo::IOLoop->one_tick;
-Mojo::IOLoop->reset;
-ok time < ($time + 10), 'stopped automatically';
-
-# Reset events
-Mojo::IOLoop->singleton->on(finish => sub { });
-ok !!Mojo::IOLoop->singleton->has_subscribers('finish'), 'has subscribers';
-Mojo::IOLoop->reset;
-ok !Mojo::IOLoop->singleton->has_subscribers('finish'), 'no subscribers';
-
-# Stream
-my $buffer = '';
-$id = Mojo::IOLoop->server(
-  (address => '127.0.0.1') => sub {
-    my ($loop, $stream) = @_;
-    $buffer .= 'accepted';
-    $stream->on(
-      read => sub {
-        my ($stream, $chunk) = @_;
-        $buffer .= $chunk;
-        return unless $buffer eq 'acceptedhello';
-        $stream->write('wo')->write('')->write('rld' => sub { shift->close });
-      }
-    );
-  }
-);
-$port = Mojo::IOLoop->acceptor($id)->port;
-my $delay = Mojo::IOLoop->delay;
-my $end   = $delay->begin;
-$handle = undef;
-Mojo::IOLoop->client(
-  {port => $port} => sub {
-    my ($loop, $err, $stream) = @_;
-    $handle = $stream->steal_handle;
-    $end->();
-    $stream->on(close => sub { $buffer .= 'should not happen' });
-    $stream->on(error => sub { $buffer .= 'should not happen either' });
-  }
-);
-$delay->wait;
-my $stream = Mojo::IOLoop::Stream->new($handle);
-is $stream->timeout, 15, 'right default';
-is $stream->timeout(16)->timeout, 16, 'right timeout';
-$id = Mojo::IOLoop->stream($stream);
-$stream->on(close => sub { Mojo::IOLoop->stop });
-$stream->on(read  => sub { $buffer .= pop });
-$stream->write('hello');
-ok !!Mojo::IOLoop->stream($id), 'stream exists';
-is $stream->timeout, 16, 'right timeout';
-Mojo::IOLoop->start;
-Mojo::IOLoop->timer(0.25 => sub { Mojo::IOLoop->stop });
-Mojo::IOLoop->start;
-ok !Mojo::IOLoop->stream($id), 'stream does not exist anymore';
-is $buffer, 'acceptedhelloworld', 'right result';
-
-# Removed listen socket
-$id   = $loop->server({address => '127.0.0.1'} => sub { });
-$port = $loop->acceptor($id)->port;
-my $connected;
-$loop->client(
-  {port => $port} => sub {
-    my ($loop, $err, $stream) = @_;
-    $loop->remove($id);
+subtest 'Defaults' => sub {
+  my $loop = Mojo::IOLoop->new;
+  is $loop->max_connections, 1000, 'right default';
+  $loop = Mojo::IOLoop->new(max_connections => 10);
+  is $loop->max_connections, 10, 'right value';
+};
+
+subtest 'Double start' => sub {
+  my $err;
+  Mojo::IOLoop->next_tick(sub {
+    my $loop = shift;
+    eval { $loop->start };
+    $err = $@;
     $loop->stop;
-    $connected = 1;
-  }
-);
-my $fd = fileno $loop->acceptor($id)->handle;
-like $ENV{MOJO_REUSE}, qr/(?:^|\,)127\.0\.0\.1:\Q$port\E:\Q$fd\E/, 'file 
descriptor can be reused';
-$loop->start;
-unlike $ENV{MOJO_REUSE}, qr/(?:^|\,)127\.0\.0\.1:\Q$port\E:\Q$fd\E/, 
'environment is clean';
-ok $connected, 'connected';
-ok !$loop->acceptor($id), 'acceptor has been removed';
-
-# Removed connection (with delay)
-my $removed;
-$delay = Mojo::IOLoop->delay(sub { $removed++ });
-$end   = $delay->begin;
-$id    = Mojo::IOLoop->server(
-  (address => '127.0.0.1') => sub {
-    my ($loop, $stream) = @_;
-    $stream->on(close => $end);
-  }
-);
-$port = Mojo::IOLoop->acceptor($id)->port;
-my $end2 = $delay->begin;
-$id = Mojo::IOLoop->client(
-  (port => $port) => sub {
-    my ($loop, $err, $stream) = @_;
-    $stream->on(close => $end2);
-    $loop->remove($id);
-  }
-);
-$delay->wait;
-is $removed, 1, 'connection has been removed';
-
-# Stream throttling
-my ($client, $server, $client_after, $server_before, $server_after, @waiting);
-$id = Mojo::IOLoop->server(
-  {address => '127.0.0.1'} => sub {
-    my ($loop, $stream) = @_;
-    $stream->timeout(0)->on(
-      read => sub {
-        my ($stream, $chunk) = @_;
-        Mojo::IOLoop->timer(
-          0.5 => sub {
-            $server_before = $server;
-            $stream->stop;
-            $stream->write('works!');
-            push @waiting, $stream->bytes_waiting;
-            Mojo::IOLoop->timer(
-              0.5 => sub {
-                $server_after = $server;
-                $client_after = $client;
-                push @waiting, $stream->bytes_waiting;
-                $stream->start;
-                Mojo::IOLoop->timer(0.5 => sub { Mojo::IOLoop->stop });
-              }
-            );
-          }
-        ) unless $server;
-        $server .= $chunk;
-      }
-    );
-  }
-);
-$port = Mojo::IOLoop->acceptor($id)->port;
-Mojo::IOLoop->client(
-  {port => $port} => sub {
-    my ($loop, $err, $stream) = @_;
-    my $drain;
-    $drain = sub { shift->write('1', $drain) };
-    $stream->$drain();
-    $stream->on(read => sub { $client .= pop });
-  }
-);
-Mojo::IOLoop->start;
-is $server_before, $server_after, 'stream has been paused';
-ok length($server) > length($server_after), 'stream has been resumed';
-is $client, $client_after, 'stream was writable while paused';
-is $client, 'works!', 'full message has been written';
-is_deeply \@waiting, [6, 0], 'right buffer sizes';
-
-# Watermarks
-my $fake = IO::Socket::IP->new(Listen => 5, LocalAddr => '127.0.0.1');
-$stream = Mojo::IOLoop::Stream->new($fake);
-$stream->start;
-$stream->high_water_mark(10);
-$stream->write('abcd');
-is $stream->bytes_waiting, 4, 'four bytes waiting';
-ok $stream->can_write, 'stream is still writable';
-$stream->write('efghijk');
-is $stream->bytes_waiting, 11, 'eleven bytes waiting';
-ok !$stream->can_write, 'stream is not writable anymore';
-$stream->high_water_mark(12);
-ok $stream->can_write, 'stream is writable again';
-$stream->close;
-ok !$stream->can_write, 'closed stream is not writable anymore';
-undef $stream;
-
-# Graceful shutdown
-$err  = '';
-$loop = Mojo::IOLoop->new;
-$port = $loop->acceptor($loop->server({address => '127.0.0.1'} => sub { 
}))->port;
-$id   = $loop->client({port => $port} => sub { shift->stop_gracefully });
-my $finish;
-$loop->on(finish => sub { ++$finish and shift->stream($id)->close });
-$loop->timer(30 => sub { shift->stop; $err = 'failed' });
-$loop->start;
-ok !$loop->stream($id), 'stopped gracefully';
-ok !$err, 'no error';
-is $finish, 1, 'finish event has been emitted once';
-
-# Graceful shutdown (without connection)
-$err  = $finish = '';
-$loop = Mojo::IOLoop->new;
-$loop->on(finish => sub { $finish++ });
-$loop->next_tick(sub { shift->stop_gracefully });
-$loop->timer(30 => sub { shift->stop; $err = 'failed' });
-$loop->start;
-ok !$err, 'no error';
-is $finish, 1, 'finish event has been emitted once';
-
-# Graceful shutdown (max_accepts)
-$err  = '';
-$loop = Mojo::IOLoop->new->max_accepts(1);
-$id   = $loop->server({address => '127.0.0.1'} => sub { });
-$port = $loop->acceptor($id)->port;
-$loop->client({port => $port} => sub { pop->close });
-$loop->timer(30 => sub { shift->stop; $err = 'failed' });
-$loop->start;
-ok !$err, 'no error';
-is $loop->max_accepts, 1, 'right value';
-
-# Connection limit
-$err  = '';
-$loop = Mojo::IOLoop->new->max_connections(2);
-my @accepting;
-$id = $loop->server(
-  {address => '127.0.0.1', single_accept => 1} => sub {
-    shift->next_tick(sub {
-      my $loop = shift;
-      push @accepting, $loop->acceptor($id)->is_accepting;
-      $loop->stop if @accepting == 2;
-    });
-  }
-);
-$port = $loop->acceptor($id)->port;
-$loop->client({port => $port} => sub { }) for 1 .. 2;
-$loop->timer(30 => sub { shift->stop; $err = 'failed' });
-$loop->start;
-ok !$err, 'no error';
-ok $accepting[0], 'accepting connections';
-ok !$accepting[1], 'connection limit reached';
+  });
+  Mojo::IOLoop->start;
+  like $err, qr/^Mojo::IOLoop already running/, 'right error';
+};
+
+subtest 'Double one_tick' => sub {
+  my $err;
+  Mojo::IOLoop->next_tick(sub {
+    my $loop = shift;
+    eval { $loop->one_tick };
+    $err = $@;
+  });
+  Mojo::IOLoop->one_tick;
+  like $err, qr/^Mojo::IOLoop already running/, 'right error';
+};
+
+subtest 'Basic functionality' => sub {
+  my ($ticks, $timer, $hirestimer);
+  my $loop = Mojo::IOLoop->new;
+  my $id   = $loop->recurring(0 => sub { $ticks++ });
+  $loop->timer(
+    1 => sub {
+      shift->timer(0 => sub { shift->stop });
+      $timer++;
+    }
+  );
+  $loop->timer(0.25 => sub { $hirestimer++ });
+  $loop->start;
+  ok $timer,      'recursive timer works';
+  ok $hirestimer, 'hires timer works';
+  $loop->one_tick;
+  ok $ticks > 2, 'more than two ticks';
+
+  # Run again without first tick event handler
+  my $before = $ticks;
+  my $after;
+  my $id2 = $loop->recurring(0 => sub { $after++ });
+  $loop->remove($id);
+  $loop->timer(0.5 => sub { shift->stop });
+  $loop->start;
+  $loop->one_tick;
+  $loop->remove($id2);
+  ok $after > 1, 'more than one tick';
+  is $ticks, $before, 'no additional ticks';
+};
+
+subtest 'Recurring timer' => sub {
+  my $count;
+  my $loop = Mojo::IOLoop->new;
+  my $id   = $loop->recurring(0.1 => sub { $count++ });
+  $loop->timer(0.5 => sub { shift->stop });
+  $loop->start;
+  $loop->one_tick;
+  $loop->remove($id);
+  ok($count > 1,  'more than one recurring event');
+  ok($count < 10, 'less than ten recurring events');
+};
+
+subtest 'Handle and reset' => sub {
+  my ($handle, $handle2, $reset, $close);
+  Mojo::IOLoop->singleton->on(reset => sub { $reset++ });
+  my $id = Mojo::IOLoop->server(
+    (address => '127.0.0.1') => sub {
+      my ($loop, $stream) = @_;
+      $stream->on(close => sub { $close++ });
+      $handle = $stream->handle;
+      Mojo::IOLoop->stop;
+    }
+  );
+  my $port = Mojo::IOLoop->acceptor($id)->port;
+  Mojo::IOLoop->acceptor($id)->on(accept => sub { $handle2 = pop });
+  my $id2 = Mojo::IOLoop->client((address => '127.0.0.1', port => $port) => 
sub { pop->on(close => sub { $close++ })});
+  Mojo::IOLoop->start;
+  my ($count, $running, $timer) = (0) x 3;
+  Mojo::IOLoop->recurring(10 => sub { $timer++ });
+  Mojo::IOLoop->next_tick(sub {
+    Mojo::IOLoop->reset;
+    $running = Mojo::IOLoop->is_running;
+  });
+  Mojo::IOLoop->start;
+  ok !$running, 'not running';
+  is $count, 0, 'no recurring events';
+  ok !Mojo::IOLoop->acceptor($id), 'acceptor has been removed';
+  ok !Mojo::IOLoop->stream($id2),  'stream has been removed';
+  is $handle,     $handle2, 'handles are equal';
+  isa_ok $handle, 'IO::Socket', 'right reference';
+  is $reset,      1,            'reset event has been emitted once';
+  is $close,      undef,        'reset unsubscribed close on streams';
+};
+
+subtest 'The poll reactor stops when there are no events being watched 
anymore' => sub {
+  my $time = time;
+  Mojo::IOLoop->start;
+  Mojo::IOLoop->one_tick;
+  Mojo::IOLoop->reset;
+  ok time < ($time + 10), 'stopped automatically';
+};
+
+subtest 'Reset events' => sub {
+  Mojo::IOLoop->singleton->on(finish => sub { });
+  ok !!Mojo::IOLoop->singleton->has_subscribers('finish'), 'has subscribers';
+  Mojo::IOLoop->reset;
+  ok !Mojo::IOLoop->singleton->has_subscribers('finish'), 'no subscribers';
+};
+
+subtest 'Stream' => sub {
+  my $buffer = '';
+  my $id     = Mojo::IOLoop->server(
+    (address => '127.0.0.1') => sub {
+      my ($loop, $stream) = @_;
+      $buffer .= 'accepted';
+      $stream->on(
+        read => sub {
+          my ($stream, $chunk) = @_;
+          $buffer .= $chunk;
+          return unless $buffer eq 'acceptedhello';
+          $stream->write('wo')->write('')->write('rld' => sub { shift->close 
});
+        }
+      );
+    }
+  );
+  my $port  = Mojo::IOLoop->acceptor($id)->port;
+  my $delay = Mojo::IOLoop->delay;
+  my $end   = $delay->begin;
+  my $handle;
+  Mojo::IOLoop->client(
+    {port => $port} => sub {
+      my ($loop, $err, $stream) = @_;
+      $handle = $stream->steal_handle;
+      $end->();
+      $stream->on(close => sub { $buffer .= 'should not happen' });
+      $stream->on(error => sub { $buffer .= 'should not happen either' });
+    }
+  );
+  $delay->wait;
+  my $stream = Mojo::IOLoop::Stream->new($handle);
+  is $stream->timeout, 15, 'right default';
+  is $stream->timeout(16)->timeout, 16, 'right timeout';
+  $id = Mojo::IOLoop->stream($stream);
+  $stream->on(close => sub { Mojo::IOLoop->stop });
+  $stream->on(read  => sub { $buffer .= pop });
+  $stream->write('hello');
+  ok !!Mojo::IOLoop->stream($id), 'stream exists';
+  is $stream->timeout, 16, 'right timeout';
+  Mojo::IOLoop->start;
+  Mojo::IOLoop->timer(0.25 => sub { Mojo::IOLoop->stop });
+  Mojo::IOLoop->start;
+  ok !Mojo::IOLoop->stream($id), 'stream does not exist anymore';
+  is $buffer, 'acceptedhelloworld', 'right result';
+};
+
+subtest 'Removed listen socket' => sub {
+  my $loop = Mojo::IOLoop->new;
+  my $id   = $loop->server({address => '127.0.0.1'} => sub { });
+  my $port = $loop->acceptor($id)->port;
+  my $connected;
+  $loop->client(
+    {port => $port} => sub {
+      my ($loop, $err, $stream) = @_;
+      $loop->remove($id);
+      $loop->stop;
+      $connected = 1;
+    }
+  );
+  my $fd = fileno $loop->acceptor($id)->handle;
+  like $ENV{MOJO_REUSE}, qr/(?:^|\,)127\.0\.0\.1:\Q$port\E:\Q$fd\E/, 'file 
descriptor can be reused';
+  $loop->start;
+  unlike $ENV{MOJO_REUSE}, qr/(?:^|\,)127\.0\.0\.1:\Q$port\E:\Q$fd\E/, 
'environment is clean';
+  ok $connected, 'connected';
+  ok !$loop->acceptor($id), 'acceptor has been removed';
+};
+
+subtest 'Removed connection (with delay)' => sub {
+  my $removed;
+  my $delay = Mojo::IOLoop->delay(sub { $removed++ });
+  my $end   = $delay->begin;
+  my $id    = Mojo::IOLoop->server(
+    (address => '127.0.0.1') => sub {
+      my ($loop, $stream) = @_;
+      $stream->on(close => $end);
+    }
+  );
+  my $port = Mojo::IOLoop->acceptor($id)->port;
+  my $end2 = $delay->begin;
+  $id = Mojo::IOLoop->client(
+    (port => $port) => sub {
+      my ($loop, $err, $stream) = @_;
+      $stream->on(close => $end2);
+      $loop->remove($id);
+    }
+  );
+  $delay->wait;
+  is $removed, 1, 'connection has been removed';
+};
+
+subtest 'Stream throttling' => sub {
+  my ($client, $server, $client_after, $server_before, $server_after, 
@waiting);
+  my $id = Mojo::IOLoop->server(
+    {address => '127.0.0.1'} => sub {
+      my ($loop, $stream) = @_;
+      $stream->timeout(0)->on(
+        read => sub {
+          my ($stream, $chunk) = @_;
+          Mojo::IOLoop->timer(
+            0.5 => sub {
+              $server_before = $server;
+              $stream->stop;
+              $stream->write('works!');
+              push @waiting, $stream->bytes_waiting;
+              Mojo::IOLoop->timer(
+                0.5 => sub {
+                  $server_after = $server;
+                  $client_after = $client;
+                  push @waiting, $stream->bytes_waiting;
+                  $stream->start;
+                  Mojo::IOLoop->timer(0.5 => sub { Mojo::IOLoop->stop });
+                }
+              );
+            }
+          ) unless $server;
+          $server .= $chunk;
+        }
+      );
+    }
+  );
+  my $port = Mojo::IOLoop->acceptor($id)->port;
+  Mojo::IOLoop->client(
+    {port => $port} => sub {
+      my ($loop, $err, $stream) = @_;
+      my $drain;
+      $drain = sub { shift->write('1', $drain) };
+      $stream->$drain();
+      $stream->on(read => sub { $client .= pop });
+    }
+  );
+  Mojo::IOLoop->start;
+  is $server_before, $server_after, 'stream has been paused';
+  ok length($server) > length($server_after), 'stream has been resumed';
+  is $client, $client_after, 'stream was writable while paused';
+  is $client, 'works!', 'full message has been written';
+  is_deeply \@waiting, [6, 0], 'right buffer sizes';
+};
+
+subtest 'Watermarks' => sub {
+  my $fake   = IO::Socket::IP->new(Listen => 5, LocalAddr => '127.0.0.1');
+  my $stream = Mojo::IOLoop::Stream->new($fake);
+  $stream->start;
+  $stream->high_water_mark(10);
+  $stream->write('abcd');
+  is $stream->bytes_waiting, 4, 'four bytes waiting';
+  ok $stream->can_write, 'stream is still writable';
+  $stream->write('efghijk');
+  is $stream->bytes_waiting, 11, 'eleven bytes waiting';
+  ok !$stream->can_write, 'stream is not writable anymore';
+  $stream->high_water_mark(12);
+  ok $stream->can_write, 'stream is writable again';
+  $stream->close;
+  ok !$stream->can_write, 'closed stream is not writable anymore';
+  undef $stream;
+};
+
+subtest 'Graceful shutdown' => sub {
+  my $err;
+  my $loop = Mojo::IOLoop->new;
+  my $port = $loop->acceptor($loop->server({address => '127.0.0.1'} => sub { 
}))->port;
+  my $id   = $loop->client({port => $port} => sub { shift->stop_gracefully });
+  my $finish;
+  $loop->on(finish => sub { ++$finish and shift->stream($id)->close });
+  $loop->timer(30 => sub { shift->stop; $err = 'failed' });
+  $loop->start;
+  ok !$loop->stream($id), 'stopped gracefully';
+  ok !$err, 'no error';
+  is $finish, 1, 'finish event has been emitted once';
+};
+
+subtest 'Graceful shutdown (without connection)' => sub {
+  my ($err, $finish);
+  my $loop = Mojo::IOLoop->new;
+  $loop->on(finish => sub { $finish++ });
+  $loop->next_tick(sub { shift->stop_gracefully });
+  $loop->timer(30 => sub { shift->stop; $err = 'failed' });
+  $loop->start;
+  ok !$err, 'no error';
+  is $finish, 1, 'finish event has been emitted once';
+};
+
+subtest 'Graceful shutdown (max_accepts)' => sub {
+  my $err;
+  my $loop = Mojo::IOLoop->new->max_accepts(1);
+  my $id   = $loop->server({address => '127.0.0.1'} => sub { });
+  my $port = $loop->acceptor($id)->port;
+  $loop->client({port => $port} => sub { pop->close });
+  $loop->timer(30 => sub { shift->stop; $err = 'failed' });
+  $loop->start;
+  ok !$err, 'no error';
+  is $loop->max_accepts, 1, 'right value';
+};
+
+subtest 'Connection limit' => sub {
+  my ($err, $id);
+  my $loop = Mojo::IOLoop->new->max_connections(2);
+  my @accepting;
+  $id = $loop->server(
+    {address => '127.0.0.1', single_accept => 1} => sub {
+      shift->next_tick(sub {
+        my $loop = shift;
+        push @accepting, $loop->acceptor($id)->is_accepting;
+        $loop->stop if @accepting == 2;
+      });
+    }
+  );
+  my $port = $loop->acceptor($id)->port;
+  $loop->client({port => $port} => sub { }) for 1 .. 2;
+  $loop->timer(30 => sub { shift->stop; $err = 'failed' });
+  $loop->start;
+  ok !$err, 'no error';
+  ok $accepting[0], 'accepting connections';
+  ok !$accepting[1], 'connection limit reached';
+};
 
-# Exception in timer
-{
+subtest 'Exception in timer' => sub {
   local *STDERR;
   open STDERR, '>', \my $err;
   my $loop = Mojo::IOLoop->new;
   $loop->timer(0 => sub { die 'Bye!' });
   $loop->start;
   like $err, qr/^Mojo::Reactor::Poll:.*Bye!/, 'right error';
-}
+};
 
-# Defaults
-is(Mojo::IOLoop::Client->new->reactor, Mojo::IOLoop->singleton->reactor, 
'right default');
-is(Mojo::IOLoop::Delay->new->ioloop,   Mojo::IOLoop->singleton,          
'right default');
-is(Mojo::IOLoop::Server->new->reactor, Mojo::IOLoop->singleton->reactor, 
'right default');
-is(Mojo::IOLoop::Stream->new->reactor, Mojo::IOLoop->singleton->reactor, 
'right default');
+subtest 'Defaults' => sub {
+  is(Mojo::IOLoop::Client->new->reactor, Mojo::IOLoop->singleton->reactor, 
'right default');
+  is(Mojo::IOLoop::Delay->new->ioloop,   Mojo::IOLoop->singleton,          
'right default');
+  is(Mojo::IOLoop::Server->new->reactor, Mojo::IOLoop->singleton->reactor, 
'right default');
+  is(Mojo::IOLoop::Stream->new->reactor, Mojo::IOLoop->singleton->reactor, 
'right default');
+};
 
 done_testing();


Reply via email to