Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Containertests #92

Merged
merged 2 commits into from
Feb 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions test/README.md
Original file line number Diff line number Diff line change
@@ -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 changes: 36 additions & 0 deletions test/container-runners.py
Original file line number Diff line number Diff line change
@@ -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 changes: 2 additions & 0 deletions test/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
docker>=2.0.0
dtt>=1.2.0
59 changes: 31 additions & 28 deletions test/wait-for-it.py
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#!/usr/bin/env python

import unittest
import shlex
from subprocess import Popen, PIPE
Expand All @@ -24,17 +26,17 @@ def execute(self, cmd):
proc = Popen(args, stdout=PIPE, stderr=PIPE)
out, err = proc.communicate()
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.bind((host, port))
s.bind(('', 0))
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
actual_exitcode, out, err = self.execute(command)
exitcode, out, err = self.execute(command)

# Check stderr
msg = ("Failed check that STDERR:\n" +
Expand All @@ -51,7 +53,7 @@ def check_args(self, args, stdout_regex, stderr_regex, exitcode):
self.assertIsNotNone(re.match(stdout_regex, out, re.DOTALL), msg)

# Check exit code
self.assertEqual(actual_exitcode, exitcode)
self.assertEqual(should_succeed, exitcode == 0)

def setUp(self):
script_path = os.path.dirname(sys.argv[0])
Expand All @@ -67,7 +69,7 @@ def test_no_args(self):
"",
"^$",
MISSING_ARGS_TEXT,
1
False
)
# Return code should be 1 when called with no args
exitcode, out, err = self.execute(self.wait_script)
Expand All @@ -79,7 +81,7 @@ def test_help(self):
"--help",
"",
HELP_TEXT,
1
False
)

def test_no_port(self):
Expand All @@ -88,7 +90,7 @@ def test_no_port(self):
"--host=localhost",
"",
MISSING_ARGS_TEXT,
1
False
)

def test_no_host(self):
Expand All @@ -97,17 +99,17 @@ def test_no_host(self):
"--port=80",
"",
MISSING_ARGS_TEXT,
1
False
)

def test_host_port(self):
""" Check that --host and --port args work correctly """
soc = self.open_local_port(port=8929)
soc, port = self.open_local_port()
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",
0
"wait-for-it.sh: waiting 1 seconds for localhost:{0}".format(port),
True
)
soc.close()

Expand All @@ -116,15 +118,16 @@ def test_combined_host_port(self):
Tests that wait-for-it.sh returns correctly after establishing a
connectionm using combined host and ports
"""
soc = self.open_local_port(port=8929)
soc, port = self.open_local_port()
self.check_args(
"localhost:8929 --timeout=1",
"localhost:{0} --timeout=1".format(port),
"",
"wait-for-it.sh: waiting 1 seconds for localhost:8929",
0
"wait-for-it.sh: waiting 1 seconds for localhost:{0}".format(port),
True
)
soc.close()


def test_port_failure_with_timeout(self):
"""
Note exit status of 124 is exected, passed from the timeout command
Expand All @@ -133,19 +136,19 @@ def test_port_failure_with_timeout(self):
"localhost:8929 --timeout=1",
"",
".*timeout occurred after waiting 1 seconds for localhost:8929",
124
False
)

def test_command_execution(self):
"""
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(
"localhost:8929 -- echo \"CMD OUTPUT\"",
"localhost:{0} -- echo \"CMD OUTPUT\"".format(port),
"CMD OUTPUT",
".*wait-for-it.sh: localhost:8929 is available after 0 seconds",
0
".*wait-for-it.sh: localhost:{0} is available after 0 seconds".format(port),
True
)
soc.close()

Expand All @@ -154,12 +157,12 @@ def test_failed_command_execution(self):
Check command failure. The command in question outputs STDERR and
an exit code of 2
"""
soc = self.open_local_port(port=8929)
soc, port = self.open_local_port()
self.check_args(
"localhost:8929 -- ls not_real_file",
"localhost:{0} -- ls not_real_file".format(port),
"",
".*No such file or directory\n",
2
False
)
soc.close()

Expand All @@ -172,7 +175,7 @@ def test_command_after_connection_failure(self):
"localhost:8929 --timeout=1 -- echo \"CMD OUTPUT\"",
"CMD OUTPUT",
".*timeout occurred after waiting 1 seconds for localhost:8929",
0
True
)

if __name__ == '__main__':
Expand Down