Skip to content

Commit

Permalink
added tests for custom default controller class
Browse files Browse the repository at this point in the history
  • Loading branch information
kraih committed Sep 1, 2013
1 parent 876e7d3 commit 18791fd
Showing 1 changed file with 90 additions and 51 deletions.
141 changes: 90 additions & 51 deletions t/mojolicious/longpolling_lite_app.t
Expand Up @@ -10,37 +10,42 @@ use Mojo::IOLoop;
use Mojolicious::Lite;
use Test::Mojo;

my $shortpoll;
package MyTestApp::Controller;
use Mojo::Base 'Mojolicious::Controller';

sub DESTROY { shift->stash->{destroyed} = 1 }

package main;

app->controller_class('MyTestApp::Controller');

get '/shortpoll' => sub {
my $self = shift;
$self->res->headers->connection('close');
$self->on(finish => sub { $shortpoll++ });
$self->on(finish => sub { shift->stash->{finished}++ });
$self->res->code(200);
$self->res->headers->content_type('text/plain');
$self->finish('this was short.');
} => 'shortpoll';

my $shortpoll_plain;
get '/shortpoll/plain' => sub {
my $self = shift;
$self->on(finish => sub { $shortpoll_plain = 'finished!' });
$self->on(finish => sub { shift->stash->{finished}++ });
$self->res->code(200);
$self->res->headers->content_type('text/plain');
$self->res->headers->content_length(25);
$self->write('this was short and plain.');
};

my $shortpoll_nolength;
get '/shortpoll/nolength' => sub {
my $self = shift;
$self->on(finish => sub { $shortpoll_nolength = 'finished!' });
$self->on(finish => sub { shift->stash->{finished}++ });
$self->res->code(200);
$self->res->headers->content_type('text/plain');
$self->write('this was short and had no length.');
$self->write('');
};

my $longpoll;
get '/longpoll' => sub {
my $self = shift;
$self->res->code(200);
Expand All @@ -57,16 +62,15 @@ get '/longpoll' => sub {
);
$self->on(
finish => sub {
shift->stash->{finished}++;
Mojo::IOLoop->remove($id);
$longpoll = 'finished!';
}
);
};

my $longpoll_nolength;
get '/longpoll/nolength' => sub {
my $self = shift;
$self->on(finish => sub { $longpoll_nolength = 'finished!' });
$self->on(finish => sub { shift->stash->{finished}++ });
$self->res->code(200);
$self->res->headers->content_type('text/plain');
$self->write('hi ');
Expand All @@ -81,10 +85,9 @@ get '/longpoll/nolength' => sub {
);
};

my $longpoll_nested;
get '/longpoll/nested' => sub {
my $self = shift;
$self->on(finish => sub { $longpoll_nested = 'finished!' });
$self->on(finish => sub { shift->stash->{finished}++ });
$self->res->code(200);
$self->res->headers->content_type('text/plain');
$self->cookie(foo => 'bar');
Expand All @@ -95,7 +98,6 @@ get '/longpoll/nested' => sub {
);
};

my $longpoll_plain;
get '/longpoll/plain' => sub {
my $self = shift;
$self->res->code(200);
Expand All @@ -104,16 +106,15 @@ get '/longpoll/plain' => sub {
$self->write('hi ');
Mojo::IOLoop->timer(
0.25 => sub {
$self->on(finish => sub { $longpoll_plain = 'finished!' });
$self->on(finish => sub { shift->stash->{finished}++ });
$self->write('there plain,' => sub { shift->write(' whats up?') });
}
);
};

my $longpoll_delayed;
get '/longpoll/delayed' => sub {
my $self = shift;
$self->on(finish => sub { $longpoll_delayed = 'finished!' });
$self->on(finish => sub { shift->stash->{finished}++ });
$self->res->code(200);
$self->res->headers->content_type('text/plain');
$self->write_chunk;
Expand All @@ -130,10 +131,9 @@ get '/longpoll/delayed' => sub {
);
};

my $longpoll_plain_delayed;
get '/longpoll/plain/delayed' => sub {
my $self = shift;
$self->on(finish => sub { $longpoll_plain_delayed = 'finished!' });
$self->on(finish => sub { shift->stash->{finished}++ });
$self->res->code(200);
$self->res->headers->content_type('text/plain');
$self->res->headers->content_length(12);
Expand All @@ -151,10 +151,9 @@ get '/longpoll/plain/delayed' => sub {
);
} => 'delayed';

my $longpoll_nolength_delayed;
get '/longpoll/nolength/delayed' => sub {
my $self = shift;
$self->on(finish => sub { $longpoll_nolength_delayed = 'finished!' });
$self->on(finish => sub { shift->stash->{finished}++ });
$self->res->code(200);
$self->res->headers->content_type('text/plain');
$self->write;
Expand All @@ -171,27 +170,24 @@ get '/longpoll/nolength/delayed' => sub {
);
};

my $longpoll_static_delayed;
get '/longpoll/static/delayed' => sub {
my $self = shift;
$self->on(finish => sub { $longpoll_static_delayed = 'finished!' });
$self->on(finish => sub { shift->stash->{finished}++ });
Mojo::IOLoop->timer(0.25 => sub { $self->render_static('hello.txt') });
};

my $longpoll_static_delayed_too;
get '/longpoll/static/delayed_too' => sub {
my $self = shift;
$self->on(finish => sub { $longpoll_static_delayed_too = 'finished!' });
$self->on(finish => sub { shift->stash->{finished}++ });
$self->cookie(bar => 'baz');
$self->session(foo => 'bar');
$self->render_later;
Mojo::IOLoop->timer(0.25 => sub { $self->render_static('hello.txt') });
} => 'delayed_too';

my $longpoll_dynamic_delayed;
get '/longpoll/dynamic/delayed' => sub {
my $self = shift;
$self->on(finish => sub { $longpoll_dynamic_delayed = 'finished!' });
$self->on(finish => sub { shift->stash->{finished}++ });
Mojo::IOLoop->timer(
0.25 => sub {
$self->res->code(201);
Expand All @@ -202,7 +198,6 @@ get '/longpoll/dynamic/delayed' => sub {
);
} => 'dynamic';

my $stream;
get '/stream' => sub {
my $self = shift;
my $i = 0;
Expand All @@ -211,24 +206,21 @@ get '/stream' => sub {
my $self = shift;
return $self->finish if $i >= 10;
$self->write_chunk($i++, $drain);
$stream
$self->stash->{subscribers}
+= @{Mojo::IOLoop->stream($self->tx->connection)->subscribers('drain')};
};
$self->$drain;
};

my $finish;
get '/finish' => sub {
my $self = shift;
my $stream = Mojo::IOLoop->stream($self->tx->connection);
$self->on(finish => sub { $finish = $stream->is_writing });
$self->on(finish => sub { shift->stash->{writing} = $stream->is_writing });
$self->render(text => 'Finish!');
};

my $too_long;
get '/too_long' => sub {
my $self = shift;
$self->on(finish => sub { $too_long = 'finished!' });
$self->res->code(200);
$self->res->headers->content_type('text/plain');
$self->res->headers->content_length(12);
Expand All @@ -239,40 +231,53 @@ get '/too_long' => sub {
my $t = Test::Mojo->new;

# Stream without delay and finish
my $stash;
$t->app->plugins->once(before_dispatch => sub { $stash = shift->stash });
$t->get_ok('/shortpoll')->status_is(200)
->header_is(Server => 'Mojolicious (Perl)')->content_type_is('text/plain')
->content_is('this was short.');
ok !$t->tx->kept_alive, 'connection was not kept alive';
ok !$t->tx->keep_alive, 'connection will not be kept alive';
is $shortpoll, 1, 'finished';
is $stash->{finished}, 1, 'finish event has been emitted once';
ok $stash->{destroyed}, 'controller has been destroyed';

# Stream without delay and content length
$stash = undef;
$t->app->plugins->once(before_dispatch => sub { $stash = shift->stash });
$t->get_ok('/shortpoll/plain')->status_is(200)
->header_is(Server => 'Mojolicious (Perl)')->content_type_is('text/plain')
->content_is('this was short and plain.');
ok !$t->tx->kept_alive, 'connection was not kept alive';
ok $t->tx->keep_alive, 'connection will be kept alive';
is $shortpoll_plain, 'finished!', 'finished';
is $stash->{finished}, 1, 'finish event has been emitted once';
ok $stash->{destroyed}, 'controller has been destroyed';

# Stream without delay and empty write
$stash = undef;
$t->app->plugins->once(before_dispatch => sub { $stash = shift->stash });
$t->get_ok('/shortpoll/nolength')->status_is(200)
->header_is(Server => 'Mojolicious (Perl)')
->header_is('Content-Length' => undef)->content_type_is('text/plain')
->content_is('this was short and had no length.');
ok $t->tx->kept_alive, 'connection was kept alive';
ok !$t->tx->keep_alive, 'connection will not be kept alive';
is $shortpoll_nolength, 'finished!', 'finished';
is $stash->{finished}, 1, 'finish event has been emitted once';
ok $stash->{destroyed}, 'controller has been destroyed';

# Chunked response with delay
$stash = undef;
$t->app->plugins->once(before_dispatch => sub { $stash = shift->stash });
$t->get_ok('/longpoll')->status_is(200)
->header_is(Server => 'Mojolicious (Perl)')->content_type_is('text/plain')
->content_is('hi there, whats up?');
ok !$t->tx->kept_alive, 'connection was not kept alive';
ok $t->tx->keep_alive, 'connection will be kept alive';
is $longpoll, 'finished!', 'finished';
is $stash->{finished}, 1, 'finish event has been emitted once';
ok $stash->{destroyed}, 'controller has been destroyed';

# Interrupted by closing the connection
$longpoll = undef;
$stash = undef;
$t->app->plugins->once(before_dispatch => sub { $stash = shift->stash });
my $port = $t->ua->app_url->port;
Mojo::IOLoop->client(
{port => $port} => sub {
Expand All @@ -288,7 +293,8 @@ Mojo::IOLoop->client(
}
);
Mojo::IOLoop->start;
is $longpoll, 'finished!', 'finished';
is $stash->{finished}, 1, 'finish event has been emitted once';
ok $stash->{destroyed}, 'controller has been destroyed';

# Interrupted by raising an error
my $tx = $t->ua->build_tx(GET => '/longpoll');
Expand All @@ -306,85 +312,118 @@ is $tx->res->error, 'Interrupted', 'right error';
is $buffer, 'hi ', 'right content';

# Stream with delay and finish
$stash = undef;
$t->app->plugins->once(before_dispatch => sub { $stash = shift->stash });
$t->get_ok('/longpoll/nolength')->status_is(200)
->header_is(Server => 'Mojolicious (Perl)')
->header_is('Content-Length' => undef)->content_type_is('text/plain')
->content_is('hi there, what length?');
ok !$t->tx->keep_alive, 'connection will not be kept alive';
is $longpoll_nolength, 'finished!', 'finished';
is $stash->{finished}, 1, 'finish event has been emitted once';
ok $stash->{destroyed}, 'controller has been destroyed';

# Stream with delay and empty write
$stash = undef;
$t->app->plugins->once(before_dispatch => sub { $stash = shift->stash });
$t->get_ok('/longpoll/nested')->status_is(200)
->header_is(Server => 'Mojolicious (Perl)')
->header_like('Set-Cookie' => qr/foo=bar/)->content_type_is('text/plain')
->content_is('nested!');
is $longpoll_nested, 'finished!', 'finished';
is $stash->{finished}, 1, 'finish event has been emitted once';
ok $stash->{destroyed}, 'controller has been destroyed';

# Stream with delay and content length
$stash = undef;
$t->app->plugins->once(before_dispatch => sub { $stash = shift->stash });
$t->get_ok('/longpoll/plain')->status_is(200)
->header_is(Server => 'Mojolicious (Perl)')->content_type_is('text/plain')
->content_is('hi there plain, whats up?');
is $longpoll_plain, 'finished!', 'finished';
is $stash->{finished}, 1, 'finish event has been emitted once';
ok $stash->{destroyed}, 'controller has been destroyed';

# Chunked response delayed multiple times with finish
$stash = undef;
$t->app->plugins->once(before_dispatch => sub { $stash = shift->stash });
$t->get_ok('/longpoll/delayed')->status_is(200)
->header_is(Server => 'Mojolicious (Perl)')->content_type_is('text/plain')
->content_is('howdy!');
is $longpoll_delayed, 'finished!', 'finished';
is $stash->{finished}, 1, 'finish event has been emitted once';
ok $stash->{destroyed}, 'controller has been destroyed';

# Stream delayed multiple times with content length
$stash = undef;
$t->app->plugins->once(before_dispatch => sub { $stash = shift->stash });
$t->get_ok('/longpoll/plain/delayed')->status_is(200)
->header_is(Server => 'Mojolicious (Perl)')->content_type_is('text/plain')
->content_is('howdy plain!');
is $longpoll_plain_delayed, 'finished!', 'finished';
is $stash->{finished}, 1, 'finish event has been emitted once';
ok $stash->{destroyed}, 'controller has been destroyed';

# Stream delayed multiple times with finish
$stash = undef;
$t->app->plugins->once(before_dispatch => sub { $stash = shift->stash });
$t->get_ok('/longpoll/nolength/delayed')->status_is(200)
->header_is(Server => 'Mojolicious (Perl)')
->header_is('Content-Length' => undef)->content_type_is('text/plain')
->content_is('howdy nolength!');
is $longpoll_nolength_delayed, 'finished!', 'finished';
is $stash->{finished}, 1, 'finish event has been emitted once';
ok $stash->{destroyed}, 'controller has been destroyed';

# Delayed static file (with log message)
my $log = '';
my $cb = $t->app->log->on(message => sub { $log .= pop });
$stash = undef;
$t->app->plugins->once(before_dispatch => sub { $stash = shift->stash });
$t->get_ok('/longpoll/static/delayed')->status_is(200)
->header_is(Server => 'Mojolicious (Perl)')->content_type_is('text/plain')
->content_is("Hello Mojo from a static file!\n");
is $longpoll_static_delayed, 'finished!', 'finished';
is $stash->{finished}, 1, 'finish event has been emitted once';
ok $stash->{destroyed}, 'controller has been destroyed';
like $log, qr/Nothing has been rendered, expecting delayed response\./,
'right message';
$t->app->log->unsubscribe(message => $cb);

# Delayed static file with cookies and session (without log message)
$log = '';
$cb = $t->app->log->on(message => sub { $log .= pop });
$log = '';
$cb = $t->app->log->on(message => sub { $log .= pop });
$stash = undef;
$t->app->plugins->once(before_dispatch => sub { $stash = shift->stash });
$t->get_ok('/longpoll/static/delayed_too')->status_is(200)
->header_is(Server => 'Mojolicious (Perl)')
->header_like('Set-Cookie' => qr/bar=baz/)
->header_like('Set-Cookie' => qr/mojolicious=/)
->content_type_is('text/plain')
->content_is("Hello Mojo from a static file!\n");
is $longpoll_static_delayed_too, 'finished!', 'finished';
is $stash->{finished}, 1, 'finish event has been emitted once';
ok $stash->{destroyed}, 'controller has been destroyed';
unlike $log, qr/Nothing has been rendered, expecting delayed response\./,
'right message';
$t->app->log->unsubscribe(message => $cb);

# Delayed custom response
$stash = undef;
$t->app->plugins->once(before_dispatch => sub { $stash = shift->stash });
$t->get_ok('/longpoll/dynamic/delayed')->status_is(201)
->header_is(Server => 'Mojolicious (Perl)')
->header_like('Set-Cookie' => qr/baz=yada/)->content_is('Dynamic!');
is $longpoll_dynamic_delayed, 'finished!', 'finished';
is $stash->{finished}, 1, 'finish event has been emitted once';
ok $stash->{destroyed}, 'controller has been destroyed';

# Chunked response streaming with drain event
$stash = undef;
$t->app->plugins->once(before_dispatch => sub { $stash = shift->stash });
$t->get_ok('/stream')->status_is(200)
->header_is(Server => 'Mojolicious (Perl)')->content_is('0123456789');
is $stream, 0, 'no leaking subscribers';
is $stash->{subscribers}, 0, 'no leaking subscribers';
ok $stash->{destroyed}, 'controller has been destroyed';

# Finish event timing
$stash = undef;
$t->app->plugins->once(before_dispatch => sub { $stash = shift->stash });
$t->get_ok('/finish')->status_is(200)
->header_is(Server => 'Mojolicious (Perl)')->content_is('Finish!');
ok !$finish, 'finish event timing is right';
ok !$stash->{writing}, 'finish event timing is right';
ok $stash->{destroyed}, 'controller has been destroyed';

# Request timeout
$tx = $t->ua->request_timeout(0.5)->build_tx(GET => '/too_long');
Expand Down

0 comments on commit 18791fd

Please sign in to comment.