Merge pull request #92 from vishnubob/containertests

Containertests
This commit is contained in:
Douglas Gibbons
2020-02-04 18:32:06 -08:00
committed by GitHub
4 changed files with 87 additions and 28 deletions

18
test/README.md Normal file
View File

@ -0,0 +1,18 @@
# Tests for wait-for-it
* wait-for-it.py - pytests for wait-for-it.sh
* container-runners.py - Runs wait-for-it.py tests in multiple containers
* requirements.txt - pip requirements for container-runners.py
To run the basic tests:
```
python wait-for-it.py
```
Many of the issues encountered have been related to differences between operating system versions. The container-runners.py script provides an easy way to run the python wait-for-it.py tests against multiple system configurations:
```
pip install -r requirements.txt
python container-runners.py
```

36
test/container-runners.py Executable file
View File

@ -0,0 +1,36 @@
#!/usr/bin/env python
# Unit tests to run wait-for-it.py unit tests in several different docker images
import unittest
from ddt import ddt, data
import os
import docker
client = docker.from_env()
app_path = os.path.abspath(os.path.join(os.path.dirname( __file__ ), '..'))
volumes = {app_path: {'bind': '/app', 'mode': 'ro'}}
@ddt
class TestContainers(unittest.TestCase):
"""
Test multiple container types with the test cases in wait-for-it.py
"""
@data(
"python:3.5-buster",
"python:3.5-stretch",
"dougg/alpine-busybox:alpine-3.11.3_busybox-1.30.1",
"dougg/alpine-busybox:alpine-3.11.3_busybox-1.31.1",
)
def test_image(self, image):
print(image)
command="/app/test/wait-for-it.py"
container = client.containers.run(image, command=command, volumes=volumes, detach=True)
result = container.wait()
logs = container.logs()
container.remove()
self.assertEqual(result, 0, logs)
if __name__ == '__main__':
unittest.main()

2
test/requirements.txt Normal file
View File

@ -0,0 +1,2 @@
docker>=2.0.0
dtt>=1.2.0

59
test/wait-for-it.py Normal file → Executable file
View File

@ -1,3 +1,5 @@
#!/usr/bin/env python
import unittest import unittest
import shlex import shlex
from subprocess import Popen, PIPE from subprocess import Popen, PIPE
@ -24,17 +26,17 @@ class TestWaitForIt(unittest.TestCase):
proc = Popen(args, stdout=PIPE, stderr=PIPE) proc = Popen(args, stdout=PIPE, stderr=PIPE)
out, err = proc.communicate() out, err = proc.communicate()
exitcode = proc.returncode exitcode = proc.returncode
return exitcode, out, err return exitcode, out.decode('utf-8'), err.decode('utf-8')
def open_local_port(self, host="localhost", port=8929, timeout=5): def open_local_port(self, timeout=5):
s = socket.socket() s = socket.socket()
s.bind((host, port)) s.bind(('', 0))
s.listen(timeout) s.listen(timeout)
return s return s, s.getsockname()[1]
def check_args(self, args, stdout_regex, stderr_regex, exitcode): def check_args(self, args, stdout_regex, stderr_regex, should_succeed):
command = self.wait_script + " " + args command = self.wait_script + " " + args
actual_exitcode, out, err = self.execute(command) exitcode, out, err = self.execute(command)
# Check stderr # Check stderr
msg = ("Failed check that STDERR:\n" + msg = ("Failed check that STDERR:\n" +
@ -51,7 +53,7 @@ class TestWaitForIt(unittest.TestCase):
self.assertIsNotNone(re.match(stdout_regex, out, re.DOTALL), msg) self.assertIsNotNone(re.match(stdout_regex, out, re.DOTALL), msg)
# Check exit code # Check exit code
self.assertEqual(actual_exitcode, exitcode) self.assertEqual(should_succeed, exitcode == 0)
def setUp(self): def setUp(self):
script_path = os.path.dirname(sys.argv[0]) script_path = os.path.dirname(sys.argv[0])
@ -67,7 +69,7 @@ class TestWaitForIt(unittest.TestCase):
"", "",
"^$", "^$",
MISSING_ARGS_TEXT, MISSING_ARGS_TEXT,
1 False
) )
# Return code should be 1 when called with no args # Return code should be 1 when called with no args
exitcode, out, err = self.execute(self.wait_script) exitcode, out, err = self.execute(self.wait_script)
@ -79,7 +81,7 @@ class TestWaitForIt(unittest.TestCase):
"--help", "--help",
"", "",
HELP_TEXT, HELP_TEXT,
1 False
) )
def test_no_port(self): def test_no_port(self):
@ -88,7 +90,7 @@ class TestWaitForIt(unittest.TestCase):
"--host=localhost", "--host=localhost",
"", "",
MISSING_ARGS_TEXT, MISSING_ARGS_TEXT,
1 False
) )
def test_no_host(self): def test_no_host(self):
@ -97,17 +99,17 @@ class TestWaitForIt(unittest.TestCase):
"--port=80", "--port=80",
"", "",
MISSING_ARGS_TEXT, MISSING_ARGS_TEXT,
1 False
) )
def test_host_port(self): def test_host_port(self):
""" Check that --host and --port args work correctly """ """ Check that --host and --port args work correctly """
soc = self.open_local_port(port=8929) soc, port = self.open_local_port()
self.check_args( self.check_args(
"--host=localhost --port=8929 --timeout=1", "--host=localhost --port={0} --timeout=1".format(port),
"", "",
"wait-for-it.sh: waiting 1 seconds for localhost:8929", "wait-for-it.sh: waiting 1 seconds for localhost:{0}".format(port),
0 True
) )
soc.close() soc.close()
@ -116,15 +118,16 @@ class TestWaitForIt(unittest.TestCase):
Tests that wait-for-it.sh returns correctly after establishing a Tests that wait-for-it.sh returns correctly after establishing a
connectionm using combined host and ports connectionm using combined host and ports
""" """
soc = self.open_local_port(port=8929) soc, port = self.open_local_port()
self.check_args( self.check_args(
"localhost:8929 --timeout=1", "localhost:{0} --timeout=1".format(port),
"", "",
"wait-for-it.sh: waiting 1 seconds for localhost:8929", "wait-for-it.sh: waiting 1 seconds for localhost:{0}".format(port),
0 True
) )
soc.close() soc.close()
def test_port_failure_with_timeout(self): def test_port_failure_with_timeout(self):
""" """
Note exit status of 124 is exected, passed from the timeout command Note exit status of 124 is exected, passed from the timeout command
@ -133,19 +136,19 @@ class TestWaitForIt(unittest.TestCase):
"localhost:8929 --timeout=1", "localhost:8929 --timeout=1",
"", "",
".*timeout occurred after waiting 1 seconds for localhost:8929", ".*timeout occurred after waiting 1 seconds for localhost:8929",
124 False
) )
def test_command_execution(self): def test_command_execution(self):
""" """
Checks that a command executes correctly after a port test passes Checks that a command executes correctly after a port test passes
""" """
soc = self.open_local_port(port=8929) soc, port = self.open_local_port()
self.check_args( self.check_args(
"localhost:8929 -- echo \"CMD OUTPUT\"", "localhost:{0} -- echo \"CMD OUTPUT\"".format(port),
"CMD OUTPUT", "CMD OUTPUT",
".*wait-for-it.sh: localhost:8929 is available after 0 seconds", ".*wait-for-it.sh: localhost:{0} is available after 0 seconds".format(port),
0 True
) )
soc.close() soc.close()
@ -154,12 +157,12 @@ class TestWaitForIt(unittest.TestCase):
Check command failure. The command in question outputs STDERR and Check command failure. The command in question outputs STDERR and
an exit code of 2 an exit code of 2
""" """
soc = self.open_local_port(port=8929) soc, port = self.open_local_port()
self.check_args( self.check_args(
"localhost:8929 -- ls not_real_file", "localhost:{0} -- ls not_real_file".format(port),
"", "",
".*No such file or directory\n", ".*No such file or directory\n",
2 False
) )
soc.close() soc.close()
@ -172,7 +175,7 @@ class TestWaitForIt(unittest.TestCase):
"localhost:8929 --timeout=1 -- echo \"CMD OUTPUT\"", "localhost:8929 --timeout=1 -- echo \"CMD OUTPUT\"",
"CMD OUTPUT", "CMD OUTPUT",
".*timeout occurred after waiting 1 seconds for localhost:8929", ".*timeout occurred after waiting 1 seconds for localhost:8929",
0 True
) )
if __name__ == '__main__': if __name__ == '__main__':