blob: 5986468da90a2b270ff66e9df4521fc244fcb90c [file] [log] [blame]
Maxim Dounind26e7c52008-09-12 20:50:35 +04001package Test::Nginx;
Maxim Dounin668f89e2008-09-07 05:00:28 +04002
3# (C) Maxim Dounin
4
5# Generict module for nginx tests.
6
7###############################################################################
8
9use warnings;
10use strict;
11
12use base qw/ Exporter /;
13
Maxim Douninf79ada02008-11-01 16:19:28 +030014our @EXPORT = qw/ log_in log_out http http_get http_head /;
Maxim Dounin668f89e2008-09-07 05:00:28 +040015
16###############################################################################
17
Maxim Dounin668f89e2008-09-07 05:00:28 +040018use File::Temp qw/ tempdir /;
19use IO::Socket;
Maxim Dounin9ad211a2008-09-08 06:08:38 +040020use Socket qw/ CRLF /;
Maxim Dounine0a4a1b2008-10-10 20:09:14 +040021use Test::More qw//;
Maxim Dounin668f89e2008-09-07 05:00:28 +040022
Maxim Dounin668f89e2008-09-07 05:00:28 +040023###############################################################################
24
Maxim Dounin63257d02008-11-18 20:43:47 +030025our $NGINX = defined $ENV{TEST_NGINX_BINARY} ? $ENV{TEST_NGINX_BINARY}
26 : '../nginx/objs/nginx';
Maxim Dounine0a4a1b2008-10-10 20:09:14 +040027
Maxim Dounind26e7c52008-09-12 20:50:35 +040028sub new {
29 my $self = {};
30 bless $self;
Maxim Dounin46bf6af2008-09-13 02:57:01 +040031
32 $self->{_testdir} = tempdir(
33 'nginx-test-XXXXXXXXXX',
34 TMPDIR => 1,
35 CLEANUP => not $ENV{LEAVE}
36 )
37 or die "Can't create temp directory: $!\n";
38
Maxim Dounind26e7c52008-09-12 20:50:35 +040039 return $self;
40}
41
42sub DESTROY {
43 my ($self) = @_;
44 $self->stop();
Maxim Dounind9a349d2008-11-24 13:06:21 +030045 if ($ENV{TEST_NGINX_CATLOG}) {
46 system("cat $self->{_testdir}/error.log");
47 }
Maxim Dounind26e7c52008-09-12 20:50:35 +040048}
49
Maxim Dounine0a4a1b2008-10-10 20:09:14 +040050sub has {
Maxim Dounin09263aa2008-10-10 20:23:39 +040051 my ($self, $feature) = @_;
52
53 my %regex = (
54 mail => '--with-mail',
Maxim Dounina01dff62008-10-14 02:18:03 +040055 flv => '--with-http_flv_module',
Maxim Dounin09263aa2008-10-10 20:23:39 +040056 rewrite => '(?s)^(?!.*--without-http_rewrite_module)',
Maxim Dounin09263aa2008-10-10 20:23:39 +040057 );
58
Maxim Dounine0a4a1b2008-10-10 20:09:14 +040059 Test::More::plan(skip_all => "$feature not compiled in")
Maxim Dounin09263aa2008-10-10 20:23:39 +040060 unless `$NGINX -V 2>&1` =~ $regex{$feature};
61
62 return $self;
63}
64
Maxim Dounin323cf242008-10-11 10:58:43 +040065sub has_daemon($) {
66 my ($self, $daemon) = @_;
67
68 Test::More::plan(skip_all => "$daemon not found")
69 unless `which $daemon`;
70
71 return $self;
72}
73
74sub plan($) {
Maxim Dounin09263aa2008-10-10 20:23:39 +040075 my ($self, $plan) = @_;
76
77 Test::More::plan(tests => $plan);
78
79 return $self;
Maxim Dounine0a4a1b2008-10-10 20:09:14 +040080}
81
Maxim Dounin323cf242008-10-11 10:58:43 +040082sub run(;$) {
Maxim Dounind26e7c52008-09-12 20:50:35 +040083 my ($self, $conf) = @_;
Maxim Dounin668f89e2008-09-07 05:00:28 +040084
Maxim Dounin46bf6af2008-09-13 02:57:01 +040085 my $testdir = $self->{_testdir};
Maxim Dounin668f89e2008-09-07 05:00:28 +040086
Maxim Dounin46bf6af2008-09-13 02:57:01 +040087 if (defined $conf) {
88 my $c = `cat $conf`;
89 $self->write_file_expand('nginx.conf', $c);
90 }
Maxim Dounin668f89e2008-09-07 05:00:28 +040091
92 my $pid = fork();
93 die "Unable to fork(): $!\n" unless defined $pid;
94
95 if ($pid == 0) {
Maxim Dounine0a4a1b2008-10-10 20:09:14 +040096 exec($NGINX, '-c', "$testdir/nginx.conf", '-g',
Maxim Dounin668f89e2008-09-07 05:00:28 +040097 "pid $testdir/nginx.pid; "
Maxim Dounin5cd63152008-09-30 21:39:23 +040098 . "error_log $testdir/error.log debug;")
Maxim Dounin668f89e2008-09-07 05:00:28 +040099 or die "Unable to exec(): $!\n";
100 }
101
102 # wait for nginx to start
103
Maxim Dounin89a56122008-11-19 17:31:03 +0300104 $self->waitforfile("$testdir/nginx.pid")
105 or die "Can't start nginx";
Maxim Dounin323cf242008-10-11 10:58:43 +0400106
Maxim Douninc0ef0162008-09-26 18:24:28 +0400107 $self->{_started} = 1;
Maxim Dounind26e7c52008-09-12 20:50:35 +0400108 return $self;
Maxim Dounin668f89e2008-09-07 05:00:28 +0400109}
110
Maxim Dounin89a56122008-11-19 17:31:03 +0300111sub waitforfile($) {
112 my ($self, $file) = @_;
113
114 # wait for file to appear
115
116 for (1 .. 30) {
117 return 1 if -e $file;
118 select undef, undef, undef, 0.1;
119 }
120
121 return undef;
122}
123
124sub waitforsocket($) {
125 my ($self, $peer) = @_;
126
127 # wait for socket to accept connections
128
129 for (1 .. 30) {
130 my $s = IO::Socket::INET->new(
131 Proto => 'tcp',
132 PeerAddr => $peer
133 );
134
135 return 1 if defined $s;
136
137 select undef, undef, undef, 0.1;
138 }
139
140 return undef;
141}
142
Maxim Dounin46bf6af2008-09-13 02:57:01 +0400143sub stop() {
Maxim Dounind26e7c52008-09-12 20:50:35 +0400144 my ($self) = @_;
145
Maxim Douninc0ef0162008-09-26 18:24:28 +0400146 while ($self->{_daemons} && scalar @{$self->{_daemons}}) {
147 my $p = shift @{$self->{_daemons}};
Maxim Dounin27a152e2009-03-28 01:17:25 +0300148 kill 'TERM', $p;
Maxim Douninc0ef0162008-09-26 18:24:28 +0400149 wait;
150 }
151
152 return $self unless $self->{_started};
153
154 kill 'TERM', `cat $self->{_testdir}/nginx.pid`;
Maxim Dounin668f89e2008-09-07 05:00:28 +0400155 wait;
Maxim Dounin668f89e2008-09-07 05:00:28 +0400156
Maxim Douninc0ef0162008-09-26 18:24:28 +0400157 $self->{_started} = 0;
158
Maxim Dounind26e7c52008-09-12 20:50:35 +0400159 return $self;
Maxim Dounin668f89e2008-09-07 05:00:28 +0400160}
161
Maxim Dounin46bf6af2008-09-13 02:57:01 +0400162sub write_file($$) {
Maxim Dounind26e7c52008-09-12 20:50:35 +0400163 my ($self, $name, $content) = @_;
Maxim Dounind4ea27b2008-09-11 19:55:04 +0400164
Maxim Dounind26e7c52008-09-12 20:50:35 +0400165 open F, '>' . $self->{_testdir} . '/' . $name
Maxim Dounind4ea27b2008-09-11 19:55:04 +0400166 or die "Can't create $name: $!";
167 print F $content;
168 close F;
Maxim Dounind26e7c52008-09-12 20:50:35 +0400169
170 return $self;
Maxim Dounind4ea27b2008-09-11 19:55:04 +0400171}
172
Maxim Dounin46bf6af2008-09-13 02:57:01 +0400173sub write_file_expand($$) {
174 my ($self, $name, $content) = @_;
175
176 $content =~ s/%%TESTDIR%%/$self->{_testdir}/gms;
177
178 return $self->write_file($name, $content);
179}
180
Maxim Dounin323cf242008-10-11 10:58:43 +0400181sub run_daemon($;@) {
182 my ($self, $code, @args) = @_;
Maxim Douninc0ef0162008-09-26 18:24:28 +0400183
184 my $pid = fork();
185 die "Can't fork daemon: $!\n" unless defined $pid;
186
187 if ($pid == 0) {
Maxim Dounin323cf242008-10-11 10:58:43 +0400188 if (ref($code) eq 'CODE') {
189 $code->(@args);
190 exit 0;
191 } else {
192 exec($code, @args);
193 }
Maxim Douninc0ef0162008-09-26 18:24:28 +0400194 }
195
196 $self->{_daemons} = [] unless defined $self->{_daemons};
197 push @{$self->{_daemons}}, $pid;
198
199 return $self;
200}
201
Maxim Dounin6fbc1352008-11-10 19:04:34 +0300202sub testdir() {
203 my ($self) = @_;
204 return $self->{_testdir};
205}
206
Maxim Dounin668f89e2008-09-07 05:00:28 +0400207###############################################################################
208
Maxim Dounin42c96f62009-02-03 09:27:08 +0300209sub log_core {
Maxim Dounin8cc32262009-01-27 01:32:47 +0300210 return unless $ENV{TEST_NGINX_VERBOSE};
Maxim Dounin42c96f62009-02-03 09:27:08 +0300211 my ($prefix, $msg) = @_;
212 ($prefix, $msg) = ('', $prefix) unless defined $msg;
213 $prefix .= ' ' if length($prefix) > 0;
214
215 $msg =~ s/^/# $prefix/gm;
216 $msg =~ s/([^\x20-\x7e])/sprintf('\\x%02x', ord($1)) . (($1 eq "\n") ? "\n" : '')/gmxe;
Maxim Dounin668f89e2008-09-07 05:00:28 +0400217 $msg .= "\n" unless $msg =~ /\n\Z/;
218 print $msg;
219}
220
Maxim Dounin42c96f62009-02-03 09:27:08 +0300221sub log_out {
222 log_core('>>', @_);
223}
224
Maxim Dounin668f89e2008-09-07 05:00:28 +0400225sub log_in {
Maxim Dounin42c96f62009-02-03 09:27:08 +0300226 log_core('<<', @_);
Maxim Dounin668f89e2008-09-07 05:00:28 +0400227}
228
229###############################################################################
230
Maxim Dounin85211c22009-03-28 16:13:07 +0300231sub http_get($;%) {
232 my ($url, %extra) = @_;
233 return http(<<EOF, %extra);
Maxim Dounin323cf242008-10-11 10:58:43 +0400234GET $url HTTP/1.0
235Host: localhost
236
237EOF
238}
239
Maxim Dounin85211c22009-03-28 16:13:07 +0300240sub http_head($;%) {
241 my ($url, %extra) = @_;
242 return http(<<EOF, %extra);
Maxim Douninf79ada02008-11-01 16:19:28 +0300243HEAD $url HTTP/1.0
244Host: localhost
245
246EOF
247}
248
Maxim Dounin85211c22009-03-28 16:13:07 +0300249sub http($;%) {
250 my ($request, %extra) = @_;
Maxim Dounin668f89e2008-09-07 05:00:28 +0400251 my $reply;
252 eval {
253 local $SIG{ALRM} = sub { die "alarm\n" };
254 alarm(2);
255 my $s = IO::Socket::INET->new(
256 Proto => 'tcp',
Maxim Dounin3c472202008-11-02 15:01:41 +0300257 PeerAddr => '127.0.0.1:8080'
Maxim Dounin668f89e2008-09-07 05:00:28 +0400258 );
259 log_out($request);
260 $s->print($request);
261 local $/;
Maxim Dounin85211c22009-03-28 16:13:07 +0300262 select undef, undef, undef, $extra{sleep} if $extra{sleep};
Maxim Dounin0272ba32009-04-26 03:54:40 +0400263 return '' if $extra{aborted};
Maxim Dounin668f89e2008-09-07 05:00:28 +0400264 $reply = $s->getline();
265 log_in($reply);
266 alarm(0);
267 };
268 alarm(0);
269 if ($@) {
270 log_in('(timeout)');
271 return undef;
272 }
273 return $reply;
274}
275
276###############################################################################
277
Maxim Dounin668f89e2008-09-07 05:00:28 +04002781;
279
280###############################################################################