Skip to content

Commit 5497468

Browse files
committed
interop_test_runner: use Python 3, improve wait logic
'python2' does not exist on macOS, it is called 'python2.7'. Porting to Python 3 is however more future-proof so do that instead. Rename the file such that it can be run with pytest. Tests are run sequentially, do not wait three seconds for every server and instead speed it up by checking for listening services. Do not listen on a fixed host port and use a random port instead. Otherwise tests could fail if something is listening on those ports.
1 parent 7761398 commit 5497468

File tree

3 files changed

+41
-17
lines changed

3 files changed

+41
-17
lines changed

.travis.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
dist: xenial
12
language: go
23

34
matrix:
@@ -28,7 +29,10 @@ before_install:
2829
- make -f _dev/Makefile fmtcheck
2930

3031
install:
31-
- if [[ "$TRAVIS_OS_NAME" == "linux" ]] && [[ "$TEST_SUITE" != "test-unit" ]]; then sudo pip install docker; fi
32+
- |
33+
if [[ "$TRAVIS_OS_NAME" == "linux" ]] && [[ "$TEST_SUITE" != "test-unit" ]]; then
34+
sudo apt-get install -y python3-pip && sudo pip3 install docker
35+
fi
3236
3337
script:
3438
# Travis does not support Docker on macOS, disable it in the build-all target.

_dev/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ test-bogo:
135135
$(DOCKER) run --rm -v $(PRJ_DIR):$(BOGO_DOCKER_TRIS_LOCATION) tls-tris:bogo
136136

137137
test-interop:
138-
$(DEV_DIR)/interop_test_runner -v
138+
$(DEV_DIR)/interop_test_runner.py -v
139139

140140
###############
141141
#

_dev/interop_test_runner renamed to _dev/interop_test_runner.py

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#!/usr/bin/env python2
1+
#!/usr/bin/env python3
22

33
import docker
44
import unittest
@@ -8,13 +8,13 @@
88
# Regex patterns used for testing
99

1010
# Checks if TLS 1.3 was negotiated
11-
RE_PATTERN_HELLO_TLS_13_NORESUME = "^.*Hello TLS 1.3 \(draft .*\) _o/$|^.*Hello TLS 1.3 _o/$"
11+
RE_PATTERN_HELLO_TLS_13_NORESUME = r"^.*Hello TLS 1.3 \(draft .*\) _o/$|^.*Hello TLS 1.3 _o/$"
1212
# Checks if TLS 1.3 was resumed
13-
RE_PATTERN_HELLO_TLS_13_RESUME = "Hello TLS 1.3 \[resumed\] _o/"
13+
RE_PATTERN_HELLO_TLS_13_RESUME = r"Hello TLS 1.3 \[resumed\] _o/"
1414
# Checks if 0-RTT was used and NOT confirmed
15-
RE_PATTERN_HELLO_0RTT = "^.*Hello TLS 1.3 .*\[resumed\] \[0-RTT\] _o/$"
15+
RE_PATTERN_HELLO_0RTT = r"^.*Hello TLS 1.3 .*\[resumed\] \[0-RTT\] _o/$"
1616
# Checks if 0-RTT was used and confirmed
17-
RE_PATTERN_HELLO_0RTT_CONFIRMED = "^.*Hello TLS 1.3 .*\[resumed\] \[0-RTT confirmed\] _o/$"
17+
RE_PATTERN_HELLO_0RTT_CONFIRMED = r"^.*Hello TLS 1.3 .*\[resumed\] \[0-RTT confirmed\] _o/$"
1818
# ALPN
1919
RE_PATTERN_ALPN = "ALPN protocol: npn_proto$"
2020
# Successful TLS establishement from TRIS
@@ -27,27 +27,47 @@ class Docker(object):
2727
def __init__(self):
2828
self.d = docker.from_env()
2929

30+
def close(self):
31+
self.d.close()
32+
3033
def get_ip(self, server):
3134
tris_localserver_container = self.d.containers.get(server)
3235
return tris_localserver_container.attrs['NetworkSettings']['IPAddress']
3336

3437
def run_client(self, image_name, cmd):
3538
''' Runs client and returns tuple (status_code, logs) '''
36-
c = self.d.containers.create(image=image_name, command=cmd)
37-
c.start()
39+
c = self.d.containers.run(image=image_name, detach=True, command=cmd)
3840
res = c.wait()
39-
ret = c.logs()
41+
ret = c.logs().decode('utf8')
4042
c.remove()
4143
return (res['StatusCode'], ret)
4244

4345
def run_server(self, image_name, cmd=None, ports=None, entrypoint=None):
4446
''' Starts server and returns docker container '''
45-
c = self.d.containers.create(image=image_name, detach=True, command=cmd, ports=ports, entrypoint=entrypoint)
46-
c.start()
47-
# TODO: maybe can be done better?
48-
time.sleep(3)
47+
c = self.d.containers.run(image=image_name, auto_remove=True, detach=True, command=cmd, ports=ports, entrypoint=entrypoint)
48+
self.wait_for_ports(c)
4949
return c
5050

51+
def wait_for_ports(self, c):
52+
''' Waits until all services from the image are ready. '''
53+
check_ports = set(int(portproto.split('/')[0]) for portproto in c.attrs['NetworkSettings']['Ports'])
54+
for i in range(0, 100):
55+
# 'ss -Htln' is the modern form, but boringssl image only includes
56+
# netstat (via busybox).
57+
info = c.exec_run('sh -c "ss -Htln 2>/dev/null || netstat -tln"')
58+
if info.exit_code != 0:
59+
print('Unable to check for open ports, sleeping for a fixed time')
60+
time.sleep(3)
61+
return
62+
tcp_listen_info = [line for line in info.output.decode('utf8').splitlines() if 'LISTEN' in line]
63+
if tcp_listen_info:
64+
tcp_ports = set(int(line.split()[3].split(':')[-1]) for line in tcp_listen_info)
65+
check_ports -= tcp_ports
66+
if not check_ports:
67+
return
68+
time.sleep(.1)
69+
print('WARNING: services from %s are not ready, missing %s' % (c.image. check_ports))
70+
5171
class RegexSelfTest(unittest.TestCase):
5272
''' Ensures that those regexe's actually work '''
5373

@@ -100,7 +120,7 @@ def setUpClass(self):
100120
@classmethod
101121
def tearDownClass(self):
102122
self.server.kill()
103-
self.server.remove()
123+
self.d.close()
104124

105125
@property
106126
def server_ip(self):
@@ -195,13 +215,13 @@ def setUpClass(self):
195215
self.d = Docker()
196216
self.server = self.d.run_server(
197217
self.SERVER_NAME,
198-
ports={ '1443/tcp': 1443, '2443/tcp': 2443, '6443/tcp': 6443, '7443/tcp': 7443},
218+
ports={ '1443/tcp': None, '2443/tcp': None, '6443/tcp': None, '7443/tcp': None},
199219
entrypoint="/server.sh")
200220

201221
@classmethod
202222
def tearDownClass(self):
203223
self.server.kill()
204-
self.server.remove()
224+
self.d.close()
205225

206226
@property
207227
def server_ip(self):

0 commit comments

Comments
 (0)