Nginx::Test - testing framework for nginx-perl and nginx
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; ...
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.
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
Finds executable binary for nginx-perl. Returns executable path or undef if not found.
undef
my $nginx = find_nginx_perl or die "Cannot find nginx-perl\n"; # $nginx = './objs/nginx-perl'
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";
"$host:$port", $timeout
Tries to connect to $host:$port within $timeout seconds. Returns 1 on success and undef on error.
$host:$port
$timeout
1
wait_for_peer "127.0.0.1:1234", 2 or die "Failed to connect to 127.0.0.1:1234 within 2 seconds";
$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 package One::Two; sub handler { ... } 1; ENDONETWO
$dir
Returns all logs from $dir.'/logs' as a single scalar. Useful for diagnostics.
$dir.'/logs'
diag cat_nginx_logs $dir;
$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"
$nginx
"$nginx -p $dir"
my $child = fork_nginx_die $nginx, $dir; ... undef $child;
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;
Runs nginx-perl -V, parses its output and returns a set of keys out of the list of configure arguments.
nginx-perl -V
my %CONFARGS = get_nginx_conf_args_dir; # %CONFARGS = ( '--with-http_ssl_module' => 1, # '--with-...' => 1 )
$peer, $uri, $timeout
Connects to $peer, sends GET request and return its $body and parsed $headers.
$peer
$body
$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], ... }
Returns proper @INC to use in nginx-perl.conf during tests.
@INC
my @incs = get_nginx_incs $nginx, $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.
$conf
$code
sub handler { ... }
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.
$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.
eval
$sub
my $rv = eval_wait_sub "test1", 5, sub { ... pass "test1"; }; fail "test1" unless $rv;
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 ...;
$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.
$buf
$sock
print
send_data $sock, $buf, 5 or ...;
$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.
$r
0
"\n\n"
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 }
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.
$r = { 'connection' => ['close'], 'content-type' => ['text/html'], ... '_status' => '404', '_message' => 'Not Found', '_version' => 'HTTP/1.0', '_keepalive' => 0 };
$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 }
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;
$sock, $h, $timeout
Reads and parses HTTP response header from $sock into $h within $timeout seconds. Returns true on success or undef on error.
$h
read_http_response $sock, $h, 5 or ...;
$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";
Scans directory $dir for logs, concatenates them and returns.
diag cat_logs $dir;
Alexandr Gomoliako <zzz@zzz.org.ua>
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.
To install Nginx::Perl, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Nginx::Perl
CPAN shell
perl -MCPAN -e shell install Nginx::Perl
For more information on module installation, please visit the detailed CPAN module installation guide.