Skip to content

Commit

Permalink
a lot of new tests
Browse files Browse the repository at this point in the history
  • Loading branch information
kraih committed Feb 22, 2015
1 parent ec5c5cb commit c5c359a
Show file tree
Hide file tree
Showing 12 changed files with 127 additions and 81 deletions.
2 changes: 2 additions & 0 deletions Changes
Expand Up @@ -2,6 +2,8 @@
5.82 2015-02-22
- Deprecated keep_alive_requests setting in Hypnotoad in favor of requests.
- Improved Morbo to restart slightly faster.
- Fixed bug in daemon and prefork commands where --inactivity-timeout option
was called --inactivity.

5.81 2015-02-20
- Deprecated object-oriented Mojo::Loader API.
Expand Down
3 changes: 2 additions & 1 deletion lib/Mojo/Server/Daemon.pm
Expand Up @@ -415,7 +415,8 @@ TLS verification mode, defaults to C<0x03>.
my $max = $daemon->max_clients;
$daemon = $daemon->max_clients(1000);
Maximum number of concurrent client connections, passed along to
Maximum number of concurrent connections this server is allowed to handle
before stopping to accept new incoming connections, passed along to
L<Mojo::IOLoop/"max_connections">.
=head2 max_requests
Expand Down
13 changes: 7 additions & 6 deletions lib/Mojo/Server/Hypnotoad.pm
Expand Up @@ -261,9 +261,10 @@ L<Mojo::Server::Daemon/"backlog">.
clients => 100
Maximum number of concurrent client connections per worker process, defaults
to the value of L<Mojo::IOLoop/"max_connections">. Note that high concurrency
works best with applications that perform mostly non-blocking operations, to
Maximum number of concurrent connections each worker process is allowed to
handle before stopping to accept new incoming connections, defaults to the
value of L<Mojo::IOLoop/"max_connections">. Note that high concurrency works
best with applications that perform mostly non-blocking operations, to
optimize for blocking operations you can decrease this value and increase
L</"workers"> instead for better performance.
Expand Down Expand Up @@ -364,9 +365,9 @@ Number of worker processes, defaults to the value of
L<Mojo::Server::Prefork/"workers">. A good rule of thumb is two worker
processes per CPU core for applications that perform mostly non-blocking
operations, blocking operations often require more and benefit from decreasing
the number of concurrent L</"clients"> (often as low as C<1>). Note that
during zero downtime software upgrades there will be twice as many workers
active for a short amount of time.
concurrency with L</"clients"> (often as low as C<1>). Note that during zero
downtime software upgrades there will be twice as many workers active for a
short amount of time.
=head1 ATTRIBUTES
Expand Down
4 changes: 2 additions & 2 deletions lib/Mojo/Server/Prefork.pm
Expand Up @@ -448,8 +448,8 @@ Full path of process id file, defaults to a random temporary path.
Number of worker processes, defaults to C<4>. A good rule of thumb is two
worker processes per CPU core for applications that perform mostly
non-blocking operations, blocking operations often require more and benefit
from decreasing the number of concurrent L<Mojo::Server::Daemon/"clients">
(often as low as C<1>).
from decreasing concurrency with L<Mojo::Server::Daemon/"clients"> (often as
low as C<1>).
=head1 METHODS
Expand Down
47 changes: 25 additions & 22 deletions lib/Mojolicious/Command/daemon.pm
Expand Up @@ -12,14 +12,14 @@ sub run {

my $daemon = Mojo::Server::Daemon->new(app => $self->app);
GetOptionsFromArray \@args,
'b|backlog=i' => sub { $daemon->backlog($_[1]) },
'c|clients=i' => sub { $daemon->max_clients($_[1]) },
'g|group=s' => sub { $daemon->group($_[1]) },
'i|inactivity=i' => sub { $daemon->inactivity_timeout($_[1]) },
'l|listen=s' => \my @listen,
'p|proxy' => sub { $daemon->reverse_proxy(1) },
'r|requests=i' => sub { $daemon->max_requests($_[1]) },
'u|user=s' => sub { $daemon->user($_[1]) };
'b|backlog=i' => sub { $daemon->backlog($_[1]) },
'c|clients=i' => sub { $daemon->max_clients($_[1]) },
'g|group=s' => sub { $daemon->group($_[1]) },
'i|inactivity-timeout=i' => sub { $daemon->inactivity_timeout($_[1]) },
'l|listen=s' => \my @listen,
'p|proxy' => sub { $daemon->reverse_proxy(1) },
'r|requests=i' => sub { $daemon->max_requests($_[1]) },
'u|user=s' => sub { $daemon->user($_[1]) };

$daemon->listen(\@listen) if @listen;
$daemon->run;
Expand All @@ -43,20 +43,23 @@ Mojolicious::Command::daemon - Daemon command
./myapp.pl daemon -l 'https://*:443?cert=./server.crt&key=./server.key'
Options:
-b, --backlog <size> Listen backlog size, defaults to SOMAXCONN
-c, --clients <number> Maximum number of concurrent clients,
defaults to 1000
-g, --group <name> Group name for process
-i, --inactivity <seconds> Inactivity timeout, defaults to the value of
MOJO_INACTIVITY_TIMEOUT or 15
-l, --listen <location> One or more locations you want to listen on,
defaults to the value of MOJO_LISTEN or
"http://*:3000"
-p, --proxy Activate reverse proxy support, defaults to
the value of MOJO_REVERSE_PROXY
-r, --requests <number> Maximum number of requests per keep-alive
connection, defaults to 25
-u, --user <name> Username for process
-b, --backlog <size> Listen backlog size, defaults to
SOMAXCONN
-c, --clients <number> Maximum number of concurrent
connections, defaults to 1000
-g, --group <name> Group name for process
-i, --inactivity-timeout <seconds> Inactivity timeout, defaults to the
value of MOJO_INACTIVITY_TIMEOUT or
15
-l, --listen <location> One or more locations you want to
listen on, defaults to the value of
MOJO_LISTEN or "http://*:3000"
-p, --proxy Activate reverse proxy support,
defaults to the value of
MOJO_REVERSE_PROXY
-r, --requests <number> Maximum number of requests per
keep-alive connection, defaults to 25
-u, --user <name> Username for process
=head1 DESCRIPTION
Expand Down
24 changes: 12 additions & 12 deletions lib/Mojolicious/Command/prefork.pm
Expand Up @@ -13,14 +13,14 @@ sub run {

my $prefork = Mojo::Server::Prefork->new(app => $self->app);
GetOptionsFromArray \@args,
'A|accepts=i' => sub { $prefork->accepts($_[1]) },
'b|backlog=i' => sub { $prefork->backlog($_[1]) },
'c|clients=i' => sub { $prefork->max_clients($_[1]) },
'G|graceful-timeout=i' => sub { $prefork->graceful_timeout($_[1]) },
'g|group=s' => sub { $prefork->group($_[1]) },
'heartbeat-interval=i' => sub { $prefork->heartbeat_interval($_[1]) },
'H|heartbeat-timeout=i' => sub { $prefork->heartbeat_timeout($_[1]) },
'i|inactivity=i' => sub { $prefork->inactivity_timeout($_[1]) },
'A|accepts=i' => sub { $prefork->accepts($_[1]) },
'b|backlog=i' => sub { $prefork->backlog($_[1]) },
'c|clients=i' => sub { $prefork->max_clients($_[1]) },
'G|graceful-timeout=i' => sub { $prefork->graceful_timeout($_[1]) },
'g|group=s' => sub { $prefork->group($_[1]) },
'heartbeat-interval=i' => sub { $prefork->heartbeat_interval($_[1]) },
'H|heartbeat-timeout=i' => sub { $prefork->heartbeat_timeout($_[1]) },
'i|inactivity-timeout=i' => sub { $prefork->inactivity_timeout($_[1]) },
'l|listen=s' => \my @listen,
'multi-accept=i' => sub { $prefork->multi_accept($_[1]) },
'P|pid-file=s' => sub { $prefork->pid_file($_[1]) },
Expand Down Expand Up @@ -55,19 +55,19 @@ Mojolicious::Command::prefork - Prefork command
accept, defaults to 1000
-b, --backlog <size> Listen backlog size, defaults to
SOMAXCONN
-c, --clients <number> Maximum number of concurrent clients,
defaults to 1000
-c, --clients <number> Maximum number of concurrent
connections, defaults to 1000
-G, --graceful-timeout <seconds> Graceful timeout, defaults to 20.
-g, --group <name> Group name for process
--heartbeat-interval <seconds> Heartbeat interval, defaults to 5
-H, --heartbeat-timeout <seconds> Heartbeat timeout, defaults to 20
-i, --inactivity <seconds> Inactivity timeout, defaults to the
-i, --inactivity-timeout <seconds> Inactivity timeout, defaults to the
value of MOJO_INACTIVITY_TIMEOUT or
15
-l, --listen <location> One or more locations you want to
listen on, defaults to the value of
MOJO_LISTEN or "http://*:3000"
--multi-accept <number> Number of connection to accept at
--multi-accept <number> Number of connections to accept at
once, defaults to 50
-P, --pid-file <path> Path to process id file, defaults to
a random file
Expand Down
3 changes: 1 addition & 2 deletions lib/Mojolicious/Command/version.pm
Expand Up @@ -2,7 +2,6 @@ package Mojolicious::Command::version;
use Mojo::Base 'Mojolicious::Command';

use Mojo::IOLoop::Client;
use Mojo::UserAgent;
use Mojolicious;

has description => 'Show versions of available modules';
Expand Down Expand Up @@ -32,7 +31,7 @@ EOF

# Check latest version on CPAN
my $latest = eval {
Mojo::UserAgent->new(max_redirects => 10)->tap(sub { $_->proxy->detect })
$self->app->ua->max_redirects(10)->tap(sub { $_->proxy->detect })
->get('api.metacpan.org/v0/release/Mojolicious')->res->json->{version};
} or return;

Expand Down
43 changes: 33 additions & 10 deletions t/mojolicious/app.t
Expand Up @@ -178,15 +178,38 @@ like $log,
'right message';
$t->app->log->unsubscribe(message => $cb);

# Foo::fun
# Foo::fun (with a lot of different tests)
my $url = $t->ua->server->url;
$url->path('/fun/time');
$t->get_ok($url => {'X-Test' => 'Hi there!'})->status_isnt(404)
->status_is(200)->header_isnt('X-Bender' => 'Bite my shiny metal ass!')
->header_unlike('X-Bender' => qr/shiny metal/)
->header_is('X-Bender' => undef)->header_is(Server => 'Mojolicious (Perl)')
->header_unlike(Server => qr/Bender/)->content_isnt('Have')
->content_is('Have fun!');
->status_is(200)->status_is(200, 'with description')->status_isnt(500)
->status_isnt(500, 'with description')->header_is('X-Bender' => undef)
->header_is(Server => 'Mojolicious (Perl)')
->header_is(Server => 'Mojolicious (Perl)', 'with description')
->header_isnt(Server => 'Whatever')
->header_isnt(Server => 'Whatever', 'with description')
->header_like(Server => qr/Mojolicious/)
->header_like(Server => qr/Mojolicious/, 'with description')
->header_unlike(Server => qr/Bender/)
->header_unlike(Server => qr/Bender/, 'with description')
->content_type_is('text/html;charset=UTF-8')
->content_type_is('text/html;charset=UTF-8', 'with description')
->content_type_isnt('text/plain')
->content_type_isnt('text/plain', 'with description')
->content_type_like(qr/html/)
->content_type_like(qr/html/, 'with description')
->content_type_unlike(qr/plain/)
->content_type_unlike(qr/plain/, 'with description')->content_isnt('Have')
->content_isnt('Have', 'with description')->content_is('<p>Have fun!</p>')
->content_is('<p>Have fun!</p>', 'with description')->content_like(qr/fun/)
->content_like(qr/fun/, 'with description')->content_unlike(qr/boring/)
->content_unlike(qr/boring/, 'with description')->element_exists('p')
->element_exists('p', 'with description')->element_exists_not('b')
->element_exists_not('b', 'with description')->text_is('p', 'Have fun!')
->text_is('p', 'Have fun!', 'with description')->text_isnt('p', 'Have')
->text_isnt('p', 'Have', 'with description')->text_like('p', qr/fun/)
->text_like('p', qr/fun/, 'with description')->text_unlike('p', qr/boring/)
->text_unlike('p', qr/boring/, 'with description');

# Foo::baz (missing action without template)
$log = '';
Expand Down Expand Up @@ -256,7 +279,7 @@ $t->get_ok('/exceptional_too/this_one_does_not_exist' => {'X-DoNotDie' => 1})
# Foo::fun
$t->get_ok('/fun/time' => {'X-Test' => 'Hi there!'})->status_is(200)
->header_is('X-Bender' => undef)->header_is(Server => 'Mojolicious (Perl)')
->content_is('Have fun!');
->content_is('<p>Have fun!</p>');

# Foo::fun
$url = $t->ua->server->url;
Expand All @@ -265,15 +288,15 @@ $cb = $t->app->log->on(message => sub { $log .= pop });
$url->path('/fun/time');
$t->get_ok($url => {'X-Test' => 'Hi there!'})->status_is(200)
->header_is('X-Bender' => undef)->header_is(Server => 'Mojolicious (Perl)')
->content_is('Have fun!');
->content_is('<p>Have fun!</p>');
like $log, qr!Rendering cached template "foo/fun\.html\.ep" from DATA section!,
'right message';
$t->app->log->unsubscribe(message => $cb);

# Foo::fun
$t->get_ok('/happy/fun/time' => {'X-Test' => 'Hi there!'})->status_is(200)
->header_is('X-Bender' => undef)->header_is(Server => 'Mojolicious (Perl)')
->content_is('Have fun!');
->content_is('<p>Have fun!</p>');

# Foo::test
$t->get_ok('/foo/test' => {'X-Test' => 'Hi there!'})->status_is(200)
Expand Down Expand Up @@ -542,7 +565,7 @@ $log = '';
$cb = $t->app->log->on(message => sub { $log .= pop });
$t->get_ok('/suspended')->status_is(200)
->header_is(Server => 'Mojolicious (Perl)')
->header_is('X-Suspended' => '0, 1, 1, 2')->content_is('Have fun!');
->header_is('X-Suspended' => '0, 1, 1, 2')->content_is('<p>Have fun!</p>');
like $log, qr!GET "/suspended"!, 'right message';
like $log,
qr/Routing to controller "MojoliciousTest::Foo" and action "suspended"/,
Expand Down
29 changes: 20 additions & 9 deletions t/mojolicious/commands.t
Expand Up @@ -270,22 +270,17 @@ $buffer = '';
$get->run('/');
}
like $buffer, qr/Your Mojo is working!/, 'right output';
$get->app->hook(
before_dispatch => sub {
my $c = shift;
return $c->render(text => '<p>works</p>')
if $c->req->url->path->contains('/html');
$c->render(json => {works => 'too'})
if $c->req->url->path->contains('/json');
}
);
$get->app->plugins->once(
before_dispatch => sub { shift->render(text => '<p>works</p>') });
$buffer = '';
{
open my $handle, '>', \$buffer;
local *STDOUT = $handle;
$get->run('/html', 'p', 'text');
}
like $buffer, qr/works/, 'right output';
$get->app->plugins->once(
before_dispatch => sub { shift->render(json => {works => 'too'}) });
$buffer = '';
{
open my $handle, '>', \$buffer;
Expand Down Expand Up @@ -345,5 +340,21 @@ require Mojolicious::Command::version;
my $version = Mojolicious::Command::version->new;
ok $version->description, 'has a description';
like $version->usage, qr/version/, 'has usage information';
$version->app->ua->unsubscribe('start')->once(
start => sub {
my ($ua, $tx) = @_;
$tx->req->proxy(0)->url($ua->server->url->path('/'));
}
);
$version->app->plugins->once(
before_dispatch => sub { shift->render(json => {version => 1000}) });
$buffer = '';
{
open my $handle, '>', \$buffer;
local *STDOUT = $handle;
$version->run;
}
like $buffer, qr/You might want to update your Mojolicious to 1000!/,
'right output';

done_testing();
2 changes: 1 addition & 1 deletion t/mojolicious/lib/MojoliciousTest/Foo.pm
Expand Up @@ -100,7 +100,7 @@ sub withlayout { shift->stash(template => 'WithGreenLayout') }
__DATA__
@@ foo/fun.html.ep
Have fun!\
<p>Have fun!</p>\
@@ just/some/template.html.epl
Development template with high precedence.
Expand Down
11 changes: 6 additions & 5 deletions t/mojolicious/lite_app.t
Expand Up @@ -894,15 +894,16 @@ $t->post_ok('/malformed_utf8' =>
->status_is(200)->header_is(Server => 'Mojolicious (Perl)')
->content_is('%E1');

# JSON
# JSON (with a lot of different tests)
$t->get_ok('/json')->status_is(200)->header_is(Server => 'Mojolicious (Perl)')
->content_type_is('application/json')->json_is({foo => [1, -2, 3, 'b☃r']})
->json_is('/foo' => [1, -2, 3, 'b☃r'])
->json_is('/foo/3', 'b☃r', 'right value')->json_has('/foo')
->json_hasnt('/bar')->json_like('/foo/3' => qr/r$/)
->json_is('/foo/3', 'b☃r', 'with description')->json_has('/foo')
->json_has('/foo', 'with description')->json_hasnt('/bar')
->json_hasnt('/bar', 'with description')->json_like('/foo/3' => qr/r$/)
->json_like('/foo/3' => qr/r$/, 'with description')
->json_unlike('/foo/3' => qr/b$/)
->json_like('/foo/3' => qr/^b/, 'right value')
->json_unlike('/foo/3' => qr/^r/, 'different value');
->json_unlike('/foo/3' => qr/^r/, 'with description');

# JSON ("null")
$t->get_ok('/json' => json => undef)->status_is(200)
Expand Down
27 changes: 16 additions & 11 deletions t/mojolicious/websocket_lite_app.t
Expand Up @@ -105,8 +105,8 @@ post {data => 'plain nested too!'};
my $t = Test::Mojo->new;

# Simple roundtrip
$t->websocket_ok('/echo')->send_ok('hello')->message_ok('got a message')
->message_is('echo: hello')->finish_ok;
$t->websocket_ok('/echo')->send_ok('hello')
->message_ok->message_is('echo: hello')->finish_ok;

# Multiple roundtrips
$t->websocket_ok('/echo')->send_ok('hello again')
Expand Down Expand Up @@ -203,23 +203,28 @@ $t->websocket_ok(
->send_ok({binary => $huge})->message_ok->message_is({binary => $huge})
->finish_ok;

# JSON roundtrips
# JSON roundtrips (with a lot of different tests)
$t->websocket_ok('/json')->send_ok({json => {test => 23, snowman => ''}})
->message_ok->json_message_is('' => {test => 24, snowman => ''})
->json_message_is('' => {test => 24, snowman => ''})
->json_message_has('/test')->json_message_hasnt('/test/2')
->send_ok({binary => encode_json([1, 2, 3])})
->message_ok->json_message_is([1, 2, 3, 4])->json_message_is([1, 2, 3, 4])
->send_ok({binary => encode_json([1, 2, 3])})
->message_ok->json_message_has('/2', 'has two elements')
->json_message_is('/2' => 3, 'right value')
->json_message_hasnt('/5', 'not five elements')
->send_ok({binary => encode_json([1, 2, 3])}, 'with description')
->message_ok('with description')->message_is('[1,2,3,4]')
->message_is('[1,2,3,4]', 'with description')->message_isnt('[1,2,3]')
->message_isnt('[1,2,3]', 'with description')->message_like(qr/3/)
->message_like(qr/3/, 'with description')->message_unlike(qr/5/)
->message_unlike(qr/5/, 'with description')->json_message_is([1, 2, 3, 4])
->json_message_is([1, 2, 3, 4])->send_ok({binary => encode_json([1, 2, 3])})
->message_ok->json_message_has('/2')
->json_message_has('/2', 'with description')->json_message_hasnt('/5')
->json_message_hasnt('/5', 'with description')->json_message_is('/2' => 3)
->json_message_is('/2' => 3, 'with description')
->send_ok({json => {'' => [1, 2, 3]}})
->message_ok->json_message_is('/☃', [1, 2, 3])
->json_message_like('/☃/1' => qr/\d/)
->json_message_like('/☃/2' => qr/3/, 'with description')
->json_message_unlike('/☃/1' => qr/[a-z]/)
->json_message_like('/☃/2' => qr/3/, 'right value')
->json_message_unlike('/☃/2' => qr/2/, 'different value')
->json_message_unlike('/☃/2' => qr/2/, 'with description')
->send_ok({json => 'works'})->message_ok->json_message_is('works')
->send_ok({json => undef})->message_ok->json_message_is(undef)->finish_ok;

Expand Down

0 comments on commit c5c359a

Please sign in to comment.