git » chasquid » commit c2ea8a8

test: Use our own netcat implementation :(

author Alberto Bertogli
2017-02-26 01:13:33 UTC
committer Alberto Bertogli
2017-02-26 01:21:35 UTC
parent 700539876bc816204a7a2eeb3c2fff6eba984452

test: Use our own netcat implementation :(

Netcat's behaviour after seeing EOF from stdin seems to not be very
portable or consistent, even under the same platform.

This has caused t-05-null_address to break recently under some
conditions, for example depending on the particular Debian version of
netcat-openbsd used, and the current situation is unclear.
See https://bugs.debian.org/854292 and https://bugs.debian.org/849192
for more details.

To stop depending on this brittle behaviour, this patch unfortunately
introduces a simple python3-based netcat for our tests to use.

test/README +0 -1
test/t-05-null_address/run.sh +1 -1
test/util/lib.sh +5 -1
test/util/nc.py +50 -0

diff --git a/test/README b/test/README
index f091f74..b66c76d 100644
--- a/test/README
+++ b/test/README
@@ -11,7 +11,6 @@ They also have some dependencies, listed below.
 The tests depend on the following things being installed on the system (listed
 as Debian package, for consistency):
 
- - netcat (nc)
  - msmtp
  - util-linux (for /usr/bin/setsid)
 
diff --git a/test/t-05-null_address/run.sh b/test/t-05-null_address/run.sh
index fa2c6f7..bcfeb2e 100755
--- a/test/t-05-null_address/run.sh
+++ b/test/t-05-null_address/run.sh
@@ -14,7 +14,7 @@ wait_until_ready 1025
 
 
 # Send mail with an empty address (directly, unauthenticated).
-nc localhost 1025 < sendmail > /dev/null
+nc.py localhost 1025 < sendmail > /dev/null
 wait_for_file .mail/user@testserver
 mail_diff content .mail/user@testserver
 rm -f .mail/user@testserver
diff --git a/test/util/lib.sh b/test/util/lib.sh
index 44c40fd..c61f126 100644
--- a/test/util/lib.sh
+++ b/test/util/lib.sh
@@ -61,6 +61,10 @@ function smtpc.py() {
 	${UTILDIR}/smtpc.py "$@"
 }
 
+function nc.py() {
+	${UTILDIR}/nc.py "$@"
+}
+
 function mail_diff() {
 	${UTILDIR}/mail_diff "$@"
 }
@@ -83,7 +87,7 @@ function fail() {
 function wait_until_ready() {
 	PORT=$1
 
-	while ! nc -z localhost $PORT; do
+	while ! nc.py -z localhost $PORT; do
 		sleep 0.1
 	done
 }
diff --git a/test/util/nc.py b/test/util/nc.py
new file mode 100755
index 0000000..dbc7864
--- /dev/null
+++ b/test/util/nc.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python3
+#
+# Simple "netcat" implementation.
+# Unfortunately netcat/nc is not that portable, so this contains a simple
+# implementation which fits our needs.
+
+import argparse
+import threading
+import smtplib
+import socket
+import sys
+
+ap = argparse.ArgumentParser()
+ap.add_argument("-z", action='store_true', help="scan for listening daemons")
+ap.add_argument("host", help="host to connect to")
+ap.add_argument("port", type=int, help="port to connect to")
+args = ap.parse_args()
+
+address = (args.host, args.port)
+
+try:
+	sock = socket.create_connection(address)
+	fd = sock.makefile('rw', buffering=1, encoding="utf-8")
+except OSError:
+	# Exit quietly, like nc does.
+	sys.exit(1)
+
+if args.z:
+	sys.exit(0)
+
+
+# stdin -> socket in the background. Do a partial shutdown when done.
+def stdin_to_sock():
+	for line in sys.stdin:
+		fd.write(line)
+		fd.flush()
+
+	try:
+		sock.shutdown(socket.SHUT_WR)
+	except OSError:
+		pass
+
+t1 = threading.Thread(target=stdin_to_sock, daemon=True)
+t1.start()
+
+# socket -> stdout in the foreground; if the socket closes, exit.
+for line in fd:
+	sys.stdout.write(line)
+	sys.stdout.flush()
+