Mercurial > hg > nginx-tests
comparison http_resolver.t @ 352:145c37f27c5a
Tests: added resolver tests.
author | Sergey Kandaurov <pluknet@nginx.com> |
---|---|
date | Thu, 14 Nov 2013 16:17:03 +0400 |
parents | |
children | 7a472e46772c |
comparison
equal
deleted
inserted
replaced
351:3d3c8b5ea8ee | 352:145c37f27c5a |
---|---|
1 #!/usr/bin/perl | |
2 | |
3 # (C) Sergey Kandaurov | |
4 # (C) Nginx, Inc. | |
5 | |
6 # Tests for http resolver. | |
7 | |
8 ############################################################################### | |
9 | |
10 use warnings; | |
11 use strict; | |
12 | |
13 use Test::More; | |
14 | |
15 BEGIN { use FindBin; chdir($FindBin::Bin); } | |
16 | |
17 use lib 'lib'; | |
18 use Test::Nginx; | |
19 | |
20 ############################################################################### | |
21 | |
22 select STDERR; $| = 1; | |
23 select STDOUT; $| = 1; | |
24 | |
25 eval { require Net::DNS::Nameserver; }; | |
26 plan(skip_all => "Net::DNS::Nameserver not installed") if $@; | |
27 | |
28 my $t = Test::Nginx->new()->has(qw/http proxy rewrite ipv6/); | |
29 | |
30 $t->write_file_expand('nginx.conf', <<'EOF'); | |
31 | |
32 %%TEST_GLOBALS%% | |
33 | |
34 daemon off; | |
35 | |
36 events { | |
37 } | |
38 | |
39 http { | |
40 %%TEST_GLOBALS_HTTP%% | |
41 | |
42 server { | |
43 listen 127.0.0.1:8080; | |
44 listen [::1]:8080; | |
45 server_name localhost; | |
46 | |
47 location / { | |
48 resolver 127.0.0.1:8081; | |
49 # to lower resolving delay for unsupported AAAA | |
50 resolver_timeout 1s; | |
51 proxy_pass http://$host:8080/backend; | |
52 } | |
53 location /cached { | |
54 resolver 127.0.0.1:8081 127.0.0.1:8082; | |
55 proxy_pass http://$host:8080/backend; | |
56 } | |
57 location /two { | |
58 resolver 127.0.0.1:8081 127.0.0.1:8082; | |
59 resolver_timeout 2s; | |
60 proxy_pass http://$host:8080/backend; | |
61 } | |
62 location /valid { | |
63 resolver 127.0.0.1:8081 127.0.0.1:8082 valid=3s; | |
64 resolver_timeout 2s; | |
65 proxy_pass http://$host:8080/backend; | |
66 } | |
67 location /invalid { | |
68 proxy_pass http://$host:8080/backend; | |
69 } | |
70 location /many { | |
71 resolver 127.0.0.1:8081 127.0.0.1:8082; | |
72 resolver_timeout 2s; | |
73 proxy_pass http://$host:8080/backend; | |
74 proxy_next_upstream http_504 timeout error; | |
75 proxy_intercept_errors on; | |
76 proxy_connect_timeout 2s; | |
77 error_page 504 502 /50x; | |
78 } | |
79 | |
80 location /backend { | |
81 return 200; | |
82 } | |
83 location /50x { | |
84 return 200 $upstream_addr; | |
85 } | |
86 } | |
87 } | |
88 | |
89 EOF | |
90 | |
91 $t->run_daemon(\&dns_daemon, 8081); | |
92 $t->run_daemon(\&dns_daemon, 8082); | |
93 | |
94 eval { | |
95 open OLDERR, ">&", \*STDERR; close STDERR; | |
96 $t->run(); | |
97 open STDERR, ">&", \*OLDERR; | |
98 }; | |
99 plan(skip_all => 'no inet6 support') if $@; | |
100 | |
101 $t->waitforsocket('127.0.0.1:8081'); | |
102 $t->waitforsocket('127.0.0.1:8082'); | |
103 | |
104 $t->plan(27); | |
105 | |
106 ############################################################################### | |
107 | |
108 like(http_host_header('a.example.net', '/'), qr/200 OK/, 'A'); | |
109 like(http_host_header('short.example.net', '/'), qr/502 Bad/, | |
110 'A short dns response'); | |
111 | |
112 TODO: { | |
113 local $TODO = 'support for AAAA'; | |
114 | |
115 like(http_host_header('aaaa.example.net', '/'), qr/200 OK/, 'AAAA'); | |
116 | |
117 } | |
118 | |
119 like(http_host_header('nx.example.net', '/'), qr/502 Bad/, 'NXDOMAIN'); | |
120 like(http_host_header('cname.example.net', '/cached'), qr/200 OK/, 'CNAME'); | |
121 like(http_host_header('cname.example.net', '/cached'), qr/200 OK/, | |
122 'CNAME cached'); | |
123 | |
124 # CNAME refers to non-existing A | |
125 | |
126 like(http_host_header('cname2.example.net', '/'), qr/502 Bad/, 'CNAME bad'); | |
127 like(http_host_header('long.example.net', '/'), qr/200 OK/, 'long label'); | |
128 like(http_host_header('long2.example.net', '/'), qr/200 OK/, 'long name'); | |
129 | |
130 # take into account DNAME | |
131 | |
132 like(http_host_header('alias.example.com', '/'), qr/200 OK/, 'DNAME'); | |
133 | |
134 # many A records in round robin | |
135 # nonexisting IPs enumerated with proxy_next_upstream | |
136 | |
137 like(http_host_header('many.example.net', '/many'), | |
138 qr/^127.0.0.20(1:8080, 127.0.0.202:8080|2:8080, 127.0.0.201:8080)$/m, | |
139 'A many'); | |
140 | |
141 like(http_host_header('many.example.net', '/many'), | |
142 qr/^127.0.0.20(1:8080, 127.0.0.202:8080|2:8080, 127.0.0.201:8080)$/m, | |
143 'A many cached'); | |
144 | |
145 # several resolver addresses with 1st ns bad | |
146 # query bad ns, negative responses are not cached | |
147 | |
148 like(http_host_header('2.example.net', '/two'), qr/502 Bad/, 'two ns bad'); | |
149 | |
150 # query alive ns | |
151 | |
152 like(http_host_header('2.example.net', '/two'), qr/200 OK/, 'two ns good'); | |
153 | |
154 # cached response prevents querying the next (bad) ns again | |
155 | |
156 like(http_host_header('2.example.net', '/two'), qr/200 OK/, 'two ns cached'); | |
157 | |
158 # ttl tested with 1st ns good and 2nd ns bad | |
159 # query good ns and cache response | |
160 | |
161 like(http_host_header('ttl.example.net', '/two'), qr/200 OK/, 'ttl'); | |
162 | |
163 # cached response prevents querying the next (bad) ns | |
164 | |
165 like(http_host_header('ttl.example.net', '/two'), qr/200 OK/, 'ttl cached 1'); | |
166 like(http_host_header('ttl.example.net', '/two'), qr/200 OK/, 'ttl cached 2'); | |
167 | |
168 sleep 2; | |
169 | |
170 # expired ttl causes nginx to query the next (bad) ns | |
171 | |
172 skip: | |
173 like(http_host_header('ttl.example.net', '/two'), qr/502 Bad/, 'ttl expired'); | |
174 | |
175 # zero ttl prohibits response caching | |
176 | |
177 like(http_host_header('ttl0.example.net', '/two'), qr/200 OK/, 'zero ttl'); | |
178 | |
179 TODO: { | |
180 local $TODO = 'support for zero ttl'; | |
181 | |
182 like(http_host_header('ttl0.example.net', '/two'), qr/502 Bad/, | |
183 'zero ttl not cached'); | |
184 | |
185 } | |
186 | |
187 # "valid" parameter tested with 1st alive ns and 2nd bad ns | |
188 # query alive ns, and cache response | |
189 | |
190 like(http_host_header('ttl.example.net', '/valid'), qr/200 OK/, 'valid'); | |
191 | |
192 # cached response prevents querying the next (bad) ns | |
193 | |
194 like(http_host_header('ttl.example.net', '/valid'), qr/200 OK/, | |
195 'valid cached 1'); | |
196 like(http_host_header('ttl.example.net', '/valid'), qr/200 OK/, | |
197 'valid cached 2'); | |
198 | |
199 sleep 2; | |
200 | |
201 # expired ttl is overridden with "valid" parameter | |
202 # response is taken from cache | |
203 | |
204 like(http_host_header('ttl.example.net', '/valid'), qr/200 OK/, | |
205 'valid overrides ttl'); | |
206 | |
207 sleep 2; | |
208 | |
209 # expired "valid" value causes nginx to query the next (bad) ns | |
210 | |
211 like(http_host_header('ttl.example.net', '/valid'), qr/502 Bad/, | |
212 'valid expired'); | |
213 | |
214 like(http_host_header('example.net', '/invalid'), qr/502 Bad/, 'no resolver'); | |
215 | |
216 ############################################################################### | |
217 | |
218 sub http_host_header { | |
219 my ($host, $uri) = @_; | |
220 return http(<<EOF); | |
221 GET $uri HTTP/1.0 | |
222 Host: $host | |
223 | |
224 EOF | |
225 } | |
226 | |
227 ############################################################################### | |
228 | |
229 sub reply_handler { | |
230 my ($name, $class, $type, $peerhost, $query, $conn) = @_; | |
231 my ($rcode, @ans, $ttl, $rdata); | |
232 | |
233 $rcode = 'NOERROR'; | |
234 $ttl = 3600; | |
235 | |
236 if (($name eq 'a.example.net') || ($name eq 'alias.example.net')) { | |
237 ($rdata) = ('127.0.0.1'); | |
238 push @ans, Net::DNS::RR->new("$name $ttl $class $type $rdata"); | |
239 | |
240 } elsif (($name eq 'many.example.net')) { | |
241 if ($conn->{sockport} == 8082) { | |
242 return 'SERVFAIL'; | |
243 } | |
244 ($rdata) = ('127.0.0.201'); | |
245 push @ans, Net::DNS::RR->new("$name $ttl $class $type $rdata"); | |
246 ($rdata) = ('127.0.0.202'); | |
247 push @ans, Net::DNS::RR->new("$name $ttl $class $type $rdata"); | |
248 | |
249 } elsif (($name eq 'aaaa.example.net')) { | |
250 ($type, $rdata) = ('AAAA', '::1'); | |
251 push @ans, Net::DNS::RR->new("$name $ttl $class $type $rdata"); | |
252 | |
253 } elsif (($name eq 'short.example.net')) { | |
254 # zero length RDATA in DNS response | |
255 ($name, $rdata) = ($name, ''); | |
256 push @ans, Net::DNS::RR->new("$name $ttl $class $type $rdata"); | |
257 | |
258 } elsif (($name eq 'alias.example.com')) { | |
259 my $dname = 'example.com'; | |
260 ($type, $rdata) = ('DNAME', 'example.net'); | |
261 push @ans, Net::DNS::RR->new("$dname $ttl $class $type $rdata"); | |
262 ($type, $rdata) = ('CNAME', 'alias.example.net'); | |
263 push @ans, Net::DNS::RR->new("$name $ttl $class $type $rdata"); | |
264 | |
265 } elsif ($name eq 'cname.example.net') { | |
266 if ($conn->{sockport} == 8082) { | |
267 return 'SERVFAIL'; | |
268 } | |
269 ($type, $rdata) = ('CNAME', 'alias.example.net'); | |
270 push @ans, Net::DNS::RR->new("$name $ttl $class $type $rdata"); | |
271 | |
272 } elsif ($name eq 'cname2.example.net') { | |
273 # points to non-existing A | |
274 ($type, $rdata) = ('CNAME', 'nx.example.net'); | |
275 push @ans, Net::DNS::RR->new("$name $ttl $class $type $rdata"); | |
276 | |
277 } elsif ($name eq 'long.example.net') { | |
278 ($type, $rdata) = ('CNAME', 'a' x 63); | |
279 push @ans, Net::DNS::RR->new("$name $ttl $class $type $rdata"); | |
280 | |
281 } elsif (($name eq 'a' x 63)) { | |
282 ($rdata) = ('127.0.0.1'); | |
283 push @ans, Net::DNS::RR->new("$name $ttl $class $type $rdata"); | |
284 | |
285 } elsif ($name eq 'long2.example.net') { | |
286 ($type, $rdata) = ('CNAME', 'a' x 63 . '.' . 'a' x 63 . '.' | |
287 . 'a' x 63 . '.' . 'a' x 63); | |
288 push @ans, Net::DNS::RR->new("$name $ttl $class $type $rdata"); | |
289 | |
290 } elsif (($name eq 'a' x 63 . '.' . 'a' x 63 . '.' . 'a' x 63 . '.' | |
291 . 'a' x 63)) | |
292 { | |
293 ($rdata) = ('127.0.0.1'); | |
294 push @ans, Net::DNS::RR->new("$name $ttl $class $type $rdata"); | |
295 | |
296 } elsif ($name eq 'ttl.example.net') { | |
297 if ($conn->{sockport} == 8082) { | |
298 return 'SERVFAIL'; | |
299 } | |
300 ($ttl, $rdata) = (1, '127.0.0.1'); | |
301 push @ans, Net::DNS::RR->new("$name $ttl $class $type $rdata"); | |
302 | |
303 } elsif ($name eq 'ttl0.example.net') { | |
304 if ($conn->{sockport} == 8082) { | |
305 return 'SERVFAIL'; | |
306 } | |
307 ($ttl, $rdata) = (0, '127.0.0.1'); | |
308 push @ans, Net::DNS::RR->new("$name $ttl $class $type $rdata"); | |
309 | |
310 } elsif ($name eq '2.example.net') { | |
311 if ($conn->{sockport} == 8081) { | |
312 return 'SERVFAIL'; | |
313 } | |
314 ($rdata) = ('127.0.0.1'); | |
315 push @ans, Net::DNS::RR->new("$name $ttl $class $type $rdata"); | |
316 | |
317 } else { | |
318 $rcode = 'NXDOMAIN'; | |
319 } | |
320 | |
321 return ($rcode, \@ans); | |
322 } | |
323 | |
324 sub dns_daemon { | |
325 my ($port) = @_; | |
326 | |
327 my $ns = Net::DNS::Nameserver->new( | |
328 LocalAddr => '127.0.0.1', | |
329 LocalPort => $port, | |
330 Proto => 'udp', | |
331 ReplyHandler => \&reply_handler, | |
332 ) | |
333 or die "Can't create nameserver object: $!\n"; | |
334 | |
335 $ns->main_loop; | |
336 } | |
337 | |
338 ############################################################################### |