comparison stream_upstream_max_conns.t @ 1391:62f06d8dfc63

Tests: ported upstream max_conns tests to stream, reduced diffs.
author Sergey Kandaurov <pluknet@nginx.com>
date Wed, 07 Nov 2018 14:49:34 +0300
parents upstream_max_conns.t@766bcbb632ee
children 3c101e516213
comparison
equal deleted inserted replaced
1390:2c0955286894 1391:62f06d8dfc63
1 #!/usr/bin/perl
2
3 # (C) Nginx, Inc.
4 # (C) Sergey Kandaurov
5
6 # Tests for stream upstream module with max_conns feature.
7
8 ###############################################################################
9
10 use warnings;
11 use strict;
12
13 use Test::More;
14
15 use IO::Select;
16
17 BEGIN { use FindBin; chdir($FindBin::Bin); }
18
19 use lib 'lib';
20 use Test::Nginx qw/ :DEFAULT http_end /;
21
22 ###############################################################################
23
24 select STDERR; $| = 1;
25 select STDOUT; $| = 1;
26
27 my $t = Test::Nginx->new()->has(qw/stream stream_upstream_least_conn/)
28 ->plan(12);
29
30 $t->write_file_expand('nginx.conf', <<'EOF');
31
32 %%TEST_GLOBALS%%
33
34 daemon off;
35
36 events {
37 }
38
39 stream {
40 upstream u_unlim {
41 server 127.0.0.1:8081 max_conns=0;
42 server 127.0.0.1:8082;
43 }
44 upstream u_lim {
45 server 127.0.0.1:8081 max_conns=3;
46 }
47
48 upstream u_backup {
49 server 127.0.0.1:8081 max_conns=2;
50 server 127.0.0.1:8082 backup;
51 }
52 upstream u_backup_lim {
53 server 127.0.0.1:8081 max_conns=2;
54 server 127.0.0.1:8082 backup max_conns=3;
55 }
56
57 upstream u_two {
58 server 127.0.0.1:8081 max_conns=1;
59 server 127.0.0.1:8082 max_conns=1;
60 }
61 upstream u_some {
62 server 127.0.0.1:8081 max_conns=1;
63 server 127.0.0.1:8082;
64 }
65 upstream u_many {
66 server 127.0.0.1:8081 max_conns=1;
67 server 127.0.0.1:8081 max_conns=1;
68 server 127.0.0.1:8082;
69 }
70
71 upstream u_weight {
72 server 127.0.0.1:8081 weight=2 max_conns=1;
73 server 127.0.0.1:8082;
74 }
75
76 upstream u_lc {
77 least_conn;
78 server 127.0.0.1:8081 max_conns=1;
79 server 127.0.0.1:8082;
80 }
81 upstream u_lc_backup {
82 least_conn;
83 server 127.0.0.1:8081 max_conns=2;
84 server 127.0.0.1:8082 backup;
85 }
86 upstream u_lc_backup_lim {
87 least_conn;
88 server 127.0.0.1:8081 max_conns=2;
89 server 127.0.0.1:8082 backup max_conns=3;
90 }
91
92 server {
93 listen 127.0.0.1:8086;
94 proxy_pass u_unlim;
95 }
96
97 server {
98 listen 127.0.0.1:8087;
99 proxy_pass u_lim;
100 }
101
102 server {
103 listen 127.0.0.1:8088;
104 proxy_pass u_backup;
105 }
106
107 server {
108 listen 127.0.0.1:8089;
109 proxy_pass u_backup_lim;
110 }
111
112 server {
113 listen 127.0.0.1:8090;
114 proxy_pass u_two;
115 }
116
117 server {
118 listen 127.0.0.1:8091;
119 proxy_pass u_some;
120 }
121
122 server {
123 listen 127.0.0.1:8092;
124 proxy_pass u_many;
125 }
126
127 server {
128 listen 127.0.0.1:8093;
129 proxy_pass u_weight;
130 }
131
132 server {
133 listen 127.0.0.1:8094;
134 proxy_pass u_lc;
135 }
136
137 server {
138 listen 127.0.0.1:8095;
139 proxy_pass u_lc_backup;
140 }
141
142 server {
143 listen 127.0.0.1:8096;
144 proxy_pass u_lc_backup_lim;
145 }
146 }
147
148 EOF
149
150 $t->run_daemon(\&http_daemon, port(8081), port(8082), port(8085));
151 $t->run();
152
153 $t->waitforsocket('127.0.0.1:' . port(8081));
154 $t->waitforsocket('127.0.0.1:' . port(8082));
155 $t->waitforsocket('127.0.0.1:' . port(8085));
156
157 ###############################################################################
158
159 my @ports = my ($p1, $p2) = (port(8081), port(8082));
160
161 # two peers without max_conns
162
163 is(parallel(8086, '/u_unlim?delay=0', 4), "$p1: 2, $p2: 2", 'unlimited');
164
165 # reopen connection to test connection subtraction
166
167 my @s = http_get_multi(8087, '/u_lim', 2, 1.1);
168 get(8087, '/close');
169 push @s, http_get_multi(8087, '/u_lim', 1, 1.1);
170 get(8085, '/closeall');
171
172 is(http_end_multi(\@s), "$p1: 3", 'conn subtraction');
173
174 # simple test with limited peer
175
176 is(parallel(8087, '/u_lim', 4), "$p1: 3", 'single');
177
178 # limited peer with backup peer
179
180 is(peers(8088, '/u_backup', 6), "$p1 $p1 $p2 $p2 $p2 $p2", 'backup');
181
182 # peer and backup peer, both limited
183
184 is(peers(8089, '/u_backup_lim', 6), "$p1 $p1 $p2 $p2 $p2 ", 'backup limited');
185
186 # all peers limited
187
188 is(parallel(8090, '/u_two', 4), "$p1: 1, $p2: 1", 'all peers');
189
190 # subset of peers limited
191
192 is(parallel(8091, '/u_some', 4), "$p1: 1, $p2: 3", 'some peers');
193
194 # ensure that peer "weight" does not affect its max_conns limit
195
196 is(parallel(8093, '/u_weight', 4), "$p1: 1, $p2: 3", 'weight');
197
198 # peers with equal server value aggregate max_conns limit
199
200 is(parallel(8092, '/u_many', 6), "$p1: 2, $p2: 4", 'equal peer');
201
202 # least_conn balancer tests
203
204 is(parallel(8094, '/u_lc', 4), "$p1: 1, $p2: 3", 'least_conn');
205 is(peers(8095, '/u_lc_backup', 6), "$p1 $p1 $p2 $p2 $p2 $p2",
206 'least_conn backup');
207 is(peers(8096, '/u_lc_backup_lim', 6), "$p1 $p1 $p2 $p2 $p2 ",
208 'least_conn backup limited');
209
210 ###############################################################################
211
212 sub peers {
213 my ($port, $uri, $count) = @_;
214
215 my @sockets = http_get_multi($port, $uri, $count, 1.1);
216 get(8085, '/closeall');
217
218 join ' ', map { defined $_ && /X-Port: (\d+)/ && $1 }
219 map { http_end $_ } (@sockets);
220 }
221
222 sub parallel {
223 my ($port, $uri, $count) = @_;
224
225 my @sockets = http_get_multi($port, $uri, $count);
226 for (1 .. 20) {
227 last if IO::Select->new(@sockets)->can_read(3) == $count;
228 select undef, undef, undef, 0.01;
229 }
230 get(8085, '/closeall');
231 return http_end_multi(\@sockets);
232 }
233
234 sub get {
235 my ($port, $uri, %opts) = @_;
236 my $s = IO::Socket::INET->new(
237 Proto => 'tcp',
238 PeerAddr => '127.0.0.1',
239 PeerPort => port($port),
240 )
241 or die "Can't connect to nginx: $!\n";
242
243 http_get($uri, socket => $s, %opts);
244 }
245
246 sub http_get_multi {
247 my ($port, $uri, $count, $wait) = @_;
248 my @sockets;
249
250 for (0 .. $count - 1) {
251 $sockets[$_] = get($port, $uri, start => 1);
252 IO::Select->new($sockets[$_])->can_read($wait) if $wait;
253 }
254
255 return @sockets;
256 }
257
258 sub http_end_multi {
259 my ($sockets) = @_;
260 my %ports;
261
262 for my $sock (@$sockets) {
263 my $r = http_end($sock);
264 if ($r && $r =~ /X-Port: (\d+)/) {
265 $ports{$1} = 0 unless defined $ports{$1};
266 $ports{$1}++;
267 }
268 close $sock;
269 }
270
271 my @keys = map { my $p = $_; grep { $p == $_ } keys %ports } @ports;
272 return join ', ', map { $_ . ": " . $ports{$_} } @keys;
273 }
274
275 ###############################################################################
276
277 sub http_daemon {
278 my (@ports) = @_;
279 my (@socks, @clients);
280
281 for my $port (@ports) {
282 my $server = IO::Socket::INET->new(
283 Proto => 'tcp',
284 LocalHost => "127.0.0.1:$port",
285 Listen => 42,
286 Reuse => 1
287 )
288 or die "Can't create listening socket: $!\n";
289 push @socks, $server;
290 }
291
292 my $sel = IO::Select->new(@socks);
293 my $skip = 4;
294 my $count = 0;
295
296 local $SIG{PIPE} = 'IGNORE';
297
298 OUTER:
299 while (my @ready = $sel->can_read) {
300 foreach my $fh (@ready) {
301 if (grep $_ == $fh, @socks) {
302 my $new = $fh->accept;
303 $new->autoflush(1);
304 $sel->add($new);
305 $count++;
306
307 } else {
308 my @busy = grep { $_->sockport() } @ready;
309
310 # finish other handles
311 if ($fh->sockport() == port(8085) && @busy > 1
312 && grep $_->sockport() != port(8085),
313 @busy)
314 {
315 next;
316 }
317
318 # late events in other handles
319 if ($fh->sockport() == port(8085) && @busy == 1
320 && $count > 1 && $skip-- > 0)
321 {
322 select undef, undef, undef, 0.1;
323 next OUTER;
324 }
325
326 my $rv = process_socket($fh, \@clients);
327 if ($rv == 1) {
328 $sel->remove($fh);
329 $fh->close;
330 }
331 if ($rv == 2) {
332 for (@clients) {
333 $sel->remove($_);
334 $_->close;
335 }
336 $sel->remove($fh);
337 $fh->close;
338 $skip = 4;
339 }
340 $count--;
341 }
342 }
343 }
344 }
345
346 # Returns true to close connection
347
348 sub process_socket {
349 my ($client, $saved) = @_;
350 my $port = $client->sockport();
351
352 my $headers = '';
353 my $uri = '';
354
355 while (<$client>) {
356 $headers .= $_;
357 last if (/^\x0d?\x0a?$/);
358 }
359 return 1 if $headers eq '';
360
361 $uri = $1 if $headers =~ /^\S+\s+([^ ]+)\s+HTTP/i;
362 return 1 if $uri eq '';
363
364 Test::Nginx::log_core('||', "$port: response, 200");
365 print $client <<EOF;
366 HTTP/1.1 200 OK
367 X-Port: $port
368
369 OK
370 EOF
371
372 return 2 if $uri =~ /closeall/;
373 return 1 if $uri =~ /close/;
374
375 push @$saved, $client;
376 return 0;
377 }
378
379 ###############################################################################