comparison lib/Test/Nginx.pm @ 1236:93f749c1d5c5

Tests: fixed parallel tests execution with UDP. Previously, when checking ports availability, a UDP socket was always created first, then a TCP socket was created. On success, one of UDP and TCP sockets was closed (depending on the "udp" option) and the second one was used to busy this port in other scripts. This lead to the following problem: in an attempt to reopen a UDP socket used in a given testing script it could be stolen by another script as part of checking ports availability. To solve this problem, UDP and TCP ports were split into two non-overlapping ranges: TCP ports are only used in the range 8000-8499, and UDP ports - in the range 8500-8999. In addition, the order of creating sockets in UDP tests has been reversed: now a TCP socket used as a lock precedes a UDP socket.
author Andrey Zelenkov <zelenkov@nginx.com>
date Thu, 26 Oct 2017 18:00:21 +0300
parents 852856f8e7dc
children e35cc79ed4a1
comparison
equal deleted inserted replaced
1235:3fc6817cd84a 1236:93f749c1d5c5
337 return $self; 337 return $self;
338 } 338 }
339 339
340 sub port { 340 sub port {
341 my ($num, %opts) = @_; 341 my ($num, %opts) = @_;
342 my ($s_tcp, $s_udp, $port); 342 my ($sock, $lock, $port);
343 343
344 goto done if defined $ports{$num}; 344 goto done if defined $ports{$num};
345 345
346 my $socket = sub {
347 IO::Socket::INET->new(
348 Proto => 'tcp',
349 LocalAddr => '127.0.0.1:' . shift,
350 Listen => 1,
351 Reuse => ($^O ne 'MSWin32'),
352 );
353 };
354
355 my $socketl = sub {
356 IO::Socket::INET->new(
357 Proto => 'udp',
358 LocalAddr => '127.0.0.1:' . shift,
359 );
360 };
361
362 ($socket, $socketl) = ($socketl, $socket) if $opts{udp};
363
346 $port = $num; 364 $port = $num;
347 365
348 for (1 .. 10) { 366 for (1 .. 10) {
349 $port = 8000 + int(rand(1000)) unless $_ == 1; 367 $port = int($port / 500) * 500 + int(rand(500)) unless $_ == 1;
350 368
351 $s_udp = IO::Socket::INET->new( 369 $lock = $socketl->($port) or next;
352 Proto => 'udp', 370 $sock = $socket->($port) and last;
353 LocalAddr => '127.0.0.1:' . $port, 371 }
354 ) or next; 372
355 373 die "Port limit exceeded" unless defined $lock and defined $sock;
356 $s_tcp = IO::Socket::INET->new(
357 Proto => 'tcp',
358 LocalAddr => '127.0.0.1:' . $port,
359 Listen => 1,
360 Reuse => ($^O ne 'MSWin32')
361 ) and last;
362 }
363
364 die "Port limit exceeded" unless defined $s_tcp and defined $s_udp;
365 374
366 $ports{$num} = { 375 $ports{$num} = {
367 port => $port, 376 port => $port,
368 socket => $opts{udp} ? $s_tcp : $s_udp 377 socket => $lock
369 }; 378 };
370 379
371 done: 380 done:
372 return $ports{$num}{socket} if $opts{socket}; 381 return $ports{$num}{socket} if $opts{socket};
373 return $ports{$num}{port}; 382 return $ports{$num}{port};