NAME
Nginx::Test - testing framework for nginx-perl and nginx
SYNOPSIS
use
Nginx::Test;
my
$nginx
= find_nginx_perl;
my
$dir
= make_path
'tmp/test'
;
my
(
$child
,
$peer
) =
fork_nginx_handler_die
$nginx
,
$dir
,
''
,
<<'END';
sub handler {
my $r = shift;
...
return OK;
}
END
wait_for_peer
$peer
, 2
or
die
"peer never started\n"
;
my
(
$body
,
$headers
) = http_get
$peer
,
"/"
, 2;
...
DESCRIPTION
Making sure testing isn't a nightmare.
This module provides some basic functions to find nginx-perl, prepare configuration, generate handler, start in a child process, query it and get something back. And it comes with Nginx::Perl. You can simply add it as a dependency for you module and use.
EXPORT
find_nginx_perl
get_nginx_conf_args_die
get_unused_port
wait_for_peer
prepare_nginx_dir_die
cat_nginx_logs
fork_nginx_die
fork_child_die
http_get
get_nginx_incs
fork_nginx_handler_die
eval_wait_sub
connect_peer
send_data
parse_http_request
parse_http_response
inject_content_length
read_http_response
make_path
cat_logs
FUNCTIONS
find_nginx_perl
Finds executable binary for nginx-perl. Returns executable path or undef
if not found.
my
$nginx
= find_nginx_perl
or
die
"Cannot find nginx-perl\n"
;
# $nginx = './objs/nginx-perl'
get_unused_port
Returns available port number to bind to. Tries to use it first and returns undef
if fails.
$port
= get_unused_port
or
die
"No unused ports\n"
;
wait_for_peer "$host:$port", $timeout
Tries to connect to $host:$port
within $timeout
seconds. Returns 1
on success and undef
on error.
wait_for_peer
"127.0.0.1:1234"
, 2
or
die
"Failed to connect to 127.0.0.1:1234 within 2 seconds"
;
prepare_nginx_dir_die $dir, $conf, @pkgs
Creates directory tree suitable to run nginx-perl from. Puts there config and packages specified as string scalars. Dies on errors.
prepare_nginx_dir_die
"tmp/foo"
,
<<'ENDCONF', <<'ENDONETWO';
worker_processes 1;
events {
worker_connections 1024;
}
http {
server {
location / {
...
}
}
}
ENDCONF
sub
handler {
...
}
1;
ENDONETWO
cat_nginx_logs $dir
Returns all logs from $dir.'/logs'
as a single scalar. Useful for diagnostics.
diag cat_nginx_logs
$dir
;
fork_nginx_die $nginx, $dir
Forks nginx-perl using executable binary from $nginx
and prepared directory path from $dir
and returns guard object. Dies on errors. Internally does something like this: "$nginx -p $dir"
my
$child
= fork_nginx_die
$nginx
,
$dir
;
...
undef
$child
;
fork_child_die sub {}
Forks sub in a child process and returns its guard object. Dies on errors.
my
$child
= fork_child_die
sub
{
...
sleep
5;
};
undef
$child
;
get_nginx_conf_args_dir $nginx
Runs nginx-perl -V
, parses its output and returns a set of keys out of the list of configure arguments.
my
%CONFARGS
= get_nginx_conf_args_dir;
# %CONFARGS = ( '--with-http_ssl_module' => 1,
# '--with-...' => 1 )
http_get $peer, $uri, $timeout
Connects to $peer
, sends GET request and return its $body
and parsed $headers
.
my
(
$body
,
$headers
) = http_get
'127.0.0.1:1234'
,
'/'
, 2;
$headers
= {
_status
=> 200,
_message
=>
'OK'
,
_version
=>
'HTTP/1.0'
,
'content-type'
=> [
'text/html'
],
'content-length'
=> [1234],
... }
get_nginx_incs $nginx, $dir
Returns proper @INC
to use in nginx-perl.conf during tests.
my
@incs
= get_nginx_incs
$nginx
,
$dir
;
fork_nginx_handler_dir $nginx, $dir, $conf, $code
Gets unused port, prepares directory for nginx with predefined package name, forks nginx and gives you a child object and generated peer back. Allows to inject $conf
into nginx-perl.conf and $code
into the package. Expects to found sub handler { ... }
in $code
. Dies on errors.
my
(
$child
,
$peer
) =
fork_nginx_handler_die
$nginx
,
$dir
,
<<'ENDCONF', <<'ENDCODE';
resolver 8.8.8.8;
ENDCONF
sub
handler {
my
(
$r
) =
@_
;
...
return
OK;
}
ENDCODE
...
undef
$child
;
Be aware that this function is not suited for every module. It expects $dir
to be relative to the current directory or any of its subdirectories, i.e. foo, foo/bar. And also expects blib/lib and blib/arch to contain your libraries, which is where ExtUtils::MakeMaker puts them.
eval_wait_sub $name, $timeout, $sub
Wraps eval
block around subroutine $sub
, sets alarm to $timeout
and waits for sub to finish. Returns undef on alarm and if $sub
dies.
my
$rv
= eval_wait_sub
"test1"
, 5,
sub
{
...
pass
"test1"
;
};
fail
"test1"
unless
$rv
;
connect_peer "$host:$port", $timeout
Tries to connect to $host:$port
within $timeout
seconds. Returns socket handle on success or undef
otherwise.
$sock
= connect_peer
"127.0.0.1:55555"
, 5
or ...;
send_data $sock, $buf, $timeout
Sends an entire $buf
to the socket $sock
in $timeout
seconds. Returns amount of data sent on success or undef otherwise. This amount is guessed since print
is used to send data.
send_data
$sock
,
$buf
, 5
or ...;
parse_http_request $buf, $r
Parses HTTP request from $buf
and puts parsed data structure into $r
. Returns length of the header in bytes on success or undef
on error. Returns 0
if cannot find header separator "\n\n"
in $buf
.
Data returned in the following form:
$r
= {
'connection'
=> [
'close'
],
'content-type'
=> [
'text/html'
],
...
'_method'
=>
'GET'
,
'_request_uri'
=>
'/?foo=bar'
,
'_version'
=>
'HTTP/1.0'
,
'_uri'
=>
'/'
,
'_query_string'
=>
'foo=bar'
,
'_keepalive'
=> 0 };
Example:
$len
= parse_http_request
$buf
,
$r
;
if
(
$len
) {
# ok
substr
$buf
, 0,
$len
,
''
;
warn
Dumper
$r
;
}
elsif
(
defined
$len
) {
# read more data
# and try again
}
else
{
# bad request
}
parse_http_response $buf, $r
Parses HTTP response from $buf
and puts parsed data structure into $r
. Returns length of the header in bytes on success or undef
on error. Returns 0
if cannot find header separator "\n\n"
in $buf
.
Data returned in the following form:
$r
= {
'connection'
=> [
'close'
],
'content-type'
=> [
'text/html'
],
...
'_status'
=>
'404'
,
'_message'
=>
'Not Found'
,
'_version'
=>
'HTTP/1.0'
,
'_keepalive'
=> 0 };
Example:
$len
= parse_http_response
$buf
,
$r
;
if
(
$len
) {
# ok
substr
$buf
, 0,
$len
,
''
;
warn
Dumper
$r
;
}
elsif
(
defined
$len
) {
# read more data
# and try again
}
else
{
# bad response
}
inject_content_length $buf
Parses HTTP header and inserts Content-Length if needed, assuming that $buf
contains entire request or response.
$buf
=
"PUT /"
.
"\x0d\x0a"
.
"Host: foo.bar"
.
"\x0d\x0a"
.
""
.
"\x0d\x0a"
.
"hello"
;
inject_content_length
$buf
;
read_http_response $sock, $h, $timeout
Reads and parses HTTP response header from $sock
into $h
within $timeout
seconds. Returns true on success or undef
on error.
read_http_response
$sock
,
$h
, 5
or ...;
make_path $path
Creates directory tree specified by $path
and returns this path or undef on error.
$path
= make_path
'tmp/foo'
or
die
"Can't create tmp/foo: $!\n"
;
cat_logs $dir
Scans directory $dir
for logs, concatenates them and returns.
diag cat_logs
$dir
;
AUTHOR
Alexandr Gomoliako <zzz@zzz.org.ua>
LICENSE
Copyright 2011-2012 Alexandr Gomoliako. All rights reserved.
This module is free software. It may be used, redistributed and/or modified under the same terms as nginx itself.