changeset 1678:d0025a0dead7

Tests: better timeout handling in mail tests. The eval + alarm model used previously does not work on Windows (see perlport(1) for alarm), so it was replaced with non-blocking I/O.
author Maxim Dounin <mdounin@mdounin.ru>
date Wed, 19 May 2021 04:32:57 +0300
parents f13ead27f89c
children 74986ebee2fd
files lib/Test/Nginx/IMAP.pm lib/Test/Nginx/POP3.pm lib/Test/Nginx/SMTP.pm
diffstat 3 files changed, 91 insertions(+), 44 deletions(-) [+]
line wrap: on
line diff
--- a/lib/Test/Nginx/IMAP.pm
+++ b/lib/Test/Nginx/IMAP.pm
@@ -34,6 +34,7 @@ sub new {
 	}
 
 	$self->{_socket}->autoflush(1);
+	$self->{_read_buffer} = '';
 
 	return $self;
 }
@@ -55,25 +56,39 @@ sub send {
 	$self->{_socket}->print($cmd . CRLF);
 }
 
+sub getline {
+	my ($self) = @_;
+	my $socket = $self->{_socket};
+
+	if ($self->{_read_buffer} =~ /^(.*?\x0a)(.*)/ms) {
+		$self->{_read_buffer} = $2;
+		return $1;
+	}
+
+	while (IO::Select->new($socket)->can_read(8)) {
+	        $socket->blocking(0);
+		my $n = $socket->sysread(my $buf, 1024);
+	        $socket->blocking(1);
+		last unless $n;
+
+		$self->{_read_buffer} .= $buf;
+
+		if ($self->{_read_buffer} =~ /^(.*?\x0a)(.*)/ms) {
+			$self->{_read_buffer} = $2;
+			return $1;
+		}
+	};
+}
+
 sub read {
 	my ($self) = @_;
 	my $socket = $self->{_socket};
-	eval {
-		local $SIG{ALRM} = sub { die "timeout\n" };
-		alarm(8);
-		while (<$socket>) {
-			log_in($_);
-			# XXX
-			next if m/^\d\d\d-/;
-			last;
-		}
-		alarm(0);
-	};
-	alarm(0);
-	if ($@) {
-		log_in("died: $@");
-		return undef;
+
+	while (defined($_ = $self->getline())) {
+		log_in($_);
+		last;
 	}
+
 	return $_;
 }
 
--- a/lib/Test/Nginx/POP3.pm
+++ b/lib/Test/Nginx/POP3.pm
@@ -34,6 +34,7 @@ sub new {
 	}
 
 	$self->{_socket}->autoflush(1);
+	$self->{_read_buffer} = '';
 
 	return $self;
 }
@@ -55,25 +56,39 @@ sub send {
 	$self->{_socket}->print($cmd . CRLF);
 }
 
+sub getline {
+	my ($self) = @_;
+	my $socket = $self->{_socket};
+
+	if ($self->{_read_buffer} =~ /^(.*?\x0a)(.*)/ms) {
+		$self->{_read_buffer} = $2;
+		return $1;
+	}
+
+	while (IO::Select->new($socket)->can_read(8)) {
+		$socket->blocking(0);
+		my $n = $socket->sysread(my $buf, 1024);
+		$socket->blocking(1);
+		last unless $n;
+
+		$self->{_read_buffer} .= $buf;
+
+		if ($self->{_read_buffer} =~ /^(.*?\x0a)(.*)/ms) {
+			$self->{_read_buffer} = $2;
+			return $1;
+		}
+	};
+}
+
 sub read {
 	my ($self) = @_;
 	my $socket = $self->{_socket};
-	eval {
-		local $SIG{ALRM} = sub { die "timeout\n" };
-		alarm(8);
-		while (<$socket>) {
-			log_in($_);
-			# XXX
-			next if m/^\d\d\d-/;
-			last;
-		}
-		alarm(0);
-	};
-	alarm(0);
-	if ($@) {
-		log_in("died: $@");
-		return undef;
+
+	while (defined($_ = $self->getline())) {
+		log_in($_);
+		last;
 	}
+
 	return $_;
 }
 
--- a/lib/Test/Nginx/SMTP.pm
+++ b/lib/Test/Nginx/SMTP.pm
@@ -34,6 +34,7 @@ sub new {
 	}
 
 	$self->{_socket}->autoflush(1);
+	$self->{_read_buffer} = '';
 
 	return $self;
 }
@@ -55,24 +56,40 @@ sub send {
 	$self->{_socket}->print($cmd . CRLF);
 }
 
+sub getline {
+	my ($self) = @_;
+	my $socket = $self->{_socket};
+
+	if ($self->{_read_buffer} =~ /^(.*?\x0a)(.*)/ms) {
+		$self->{_read_buffer} = $2;
+		return $1;
+	}
+
+	while (IO::Select->new($socket)->can_read(8)) {
+		$socket->blocking(0);
+		my $n = $socket->sysread(my $buf, 1024);
+		$socket->blocking(1);
+		last unless $n;
+
+		$self->{_read_buffer} .= $buf;
+
+		if ($self->{_read_buffer} =~ /^(.*?\x0a)(.*)/ms) {
+			$self->{_read_buffer} = $2;
+			return $1;
+		}
+	};
+}
+
 sub read {
 	my ($self) = @_;
 	my $socket = $self->{_socket};
-	eval {
-		local $SIG{ALRM} = sub { die "timeout\n" };
-		alarm(8);
-		while (<$socket>) {
-			log_in($_);
-			next if m/^\d\d\d-/;
-			last;
-		}
-		alarm(0);
-	};
-	alarm(0);
-	if ($@) {
-		log_in("died: $@");
-		return undef;
+
+	while (defined($_ = $self->getline())) {
+		log_in($_);
+		next if m/^\d\d\d-/;
+		last;
 	}
+
 	return $_;
 }