18
test/README.md
Normal file
18
test/README.md
Normal 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
36
test/container-runners.py
Executable 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
2
test/requirements.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
docker>=2.0.0
|
||||||
|
dtt>=1.2.0
|
59
test/wait-for-it.py
Normal file → Executable file
59
test/wait-for-it.py
Normal file → Executable 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__':
|
||||||
|
Reference in New Issue
Block a user