From 7f645ced94cb99eb7d4bbfe6f079361d2dd49829 Mon Sep 17 00:00:00 2001 From: Douglas Gibbons Date: Wed, 22 Mar 2017 17:31:47 -0700 Subject: [PATCH 1/6] Start of test framework --- .gitignore | 3 +++ .travis.yml | 5 +++++ test/wait-for-it.py | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+) create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 test/wait-for-it.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3e7e969 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +**/*.pyc +.pydevproject + diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..dfd38c8 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,5 @@ +language: python +python: + - "2.7" + +script: python test/wait-for-it.py diff --git a/test/wait-for-it.py b/test/wait-for-it.py new file mode 100644 index 0000000..88b478c --- /dev/null +++ b/test/wait-for-it.py @@ -0,0 +1,40 @@ +import unittest +import subprocess +import shlex +from subprocess import Popen, PIPE +import os +import sys + + +class TestWaitForIt(unittest.TestCase): + + + def execute(self,cmd): + """Executes a command and returns exit code, STDOUT, STDERR""" + args = shlex.split(cmd) + proc = Popen(args, stdout=PIPE, stderr=PIPE) + out, err = proc.communicate() + exitcode = proc.returncode + return exitcode, out, err + + def setUp(self): + script_path = os.path.dirname(sys.argv[0]) + parent_path = os.path.abspath(os.path.join(script_path, os.pardir)) + self.wait_script = os.path.join(parent_path,"wait-for-it.sh") + + def test_no_args_return_code(self): + # Return code should be 1 when called with no args + exitcode, out, err = self.execute(self.wait_script) + self.assertEqual(exitcode,1) + + def test_help(self): + exitcode, out, err = self.execute(self.wait_script+" --help") + # STDERR should begin with "Usage:" + self.assertTrue(err.startswith("Usage:")) + # exit code should be 1 + self.assertEqual(exitcode,1) + + + +if __name__ == '__main__': + unittest.main() From 13c00e35ea19c8fb49bbbc9d97c8ce0950b4e238 Mon Sep 17 00:00:00 2001 From: Douglas Gibbons Date: Wed, 22 Mar 2017 17:33:24 -0700 Subject: [PATCH 2/6] Start of test framework --- test/wait-for-it.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/wait-for-it.py b/test/wait-for-it.py index 88b478c..a004b26 100644 --- a/test/wait-for-it.py +++ b/test/wait-for-it.py @@ -28,6 +28,7 @@ class TestWaitForIt(unittest.TestCase): self.assertEqual(exitcode,1) def test_help(self): + # Execute with "--help" option and check output exitcode, out, err = self.execute(self.wait_script+" --help") # STDERR should begin with "Usage:" self.assertTrue(err.startswith("Usage:")) From 4fd1b45cff18b37630ebabe0bc0b2f4ea763954b Mon Sep 17 00:00:00 2001 From: Douglas Gibbons Date: Sun, 26 Mar 2017 22:50:25 -0700 Subject: [PATCH 3/6] Added some real tests --- test/wait-for-it.py | 160 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 151 insertions(+), 9 deletions(-) diff --git a/test/wait-for-it.py b/test/wait-for-it.py index a004b26..f4a6194 100644 --- a/test/wait-for-it.py +++ b/test/wait-for-it.py @@ -4,8 +4,18 @@ import shlex from subprocess import Popen, PIPE import os import sys +import socket +import re - +missing_args_text = "Error: you need to provide a host and port to test." +help_text = "Usage:" +dividing_line = '-'*71 # Output line of dashes +""" + TestWaitForIt tests the wait-for-it.sh shell script. + + The wait-for-it.sh script is assumed to be in the parent directory to the + test script. +""" class TestWaitForIt(unittest.TestCase): @@ -16,26 +26,158 @@ class TestWaitForIt(unittest.TestCase): out, err = proc.communicate() exitcode = proc.returncode return exitcode, out, err + + def open_local_port(self,host="localhost", port=8929, timeout=5): + s = socket.socket() + s.bind((host,port)) + s.listen(timeout) + return s + def check_args(self,args,stdout_regex,stderr_regex,exitcode): + command = self.wait_script+" "+args + actual_exitcode, out, err = self.execute(command) + + # Check stderr + msg = ("Failed check that STDERR:\n"+ + dividing_line + "\n"+err+"\n"+dividing_line+ + "\nmatches:\n"+ + dividing_line + "\n"+stderr_regex+"\n"+dividing_line) + self.assertIsNotNone(re.match(stderr_regex,err,re.DOTALL),msg) + + # Check STDOUT + msg = ("Failed check that STDOUT:\n"+ + dividing_line + "\n"+out+"\n"+dividing_line+ + "\nmatches:\n"+ + dividing_line + "\n"+stdout_regex+"\n"+dividing_line) + self.assertIsNotNone(re.match(stdout_regex,out,re.DOTALL),msg) + + # Check exit code + self.assertEqual(actual_exitcode,exitcode) + def setUp(self): script_path = os.path.dirname(sys.argv[0]) parent_path = os.path.abspath(os.path.join(script_path, os.pardir)) self.wait_script = os.path.join(parent_path,"wait-for-it.sh") - - def test_no_args_return_code(self): + + def test_no_args(self): + """ + Check that no aruments returns the missing args text and the correct + return code + """ + self.check_args( + "", + "^$", + missing_args_text, + 1 + ) # Return code should be 1 when called with no args exitcode, out, err = self.execute(self.wait_script) self.assertEqual(exitcode,1) def test_help(self): - # Execute with "--help" option and check output - exitcode, out, err = self.execute(self.wait_script+" --help") - # STDERR should begin with "Usage:" - self.assertTrue(err.startswith("Usage:")) - # exit code should be 1 - self.assertEqual(exitcode,1) + """ Check that help text is printed with --help argument """ + self.check_args( + "--help", + "", + help_text, + 1 + ) + + def test_no_port(self): + """ Check with missing port argument """ + self.check_args( + "--host=localhost", + "", + missing_args_text, + 1 + ) + def test_no_host(self): + """ Check with missing hostname argument """ + self.check_args( + "--port=80", + "", + missing_args_text, + 1 + ) + def test_host_port(self): + """ Check that --host and --port args work correctly """ + soc = self.open_local_port(port=8929) + self.check_args( + "--host=localhost --port=8929 --timeout=1", + "", + "wait-for-it.sh: waiting 1 seconds for localhost:8929", + 0 + ) + soc.close() + + 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) + self.check_args( + "localhost:8929 --timeout=1", + "", + "wait-for-it.sh: waiting 1 seconds for localhost:8929", + 0 + ) + soc.close() + + def test_port_failure_with_timeout(self): + """ + Note exit status of 124 is exected, passed from the timeout command + """ + self.check_args( + "localhost:8929 --timeout=1", + "", + ".*wait-for-it.sh: timeout occurred after waiting 1 seconds for localhost:8929", + 124 + ) + + def test_command_execution(self): + """ + Checks that a command executes correctly after a port test passes + """ + soc = self.open_local_port(port=8929) + self.check_args( + "localhost:8929 -- echo \"CMD OUTPUT\"", + "CMD OUTPUT", + ".*wait-for-it.sh: localhost:8929 is available after 0 seconds", + 0 + ) + soc.close() + + + 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) + self.check_args( + "localhost:8929 -- ls not_real_file", + "", + ".*ls: cannot access 'not_real_file': No such file or directory\n", + 2 + ) + soc.close() + + def test_command_after_connection_failure(self): + """ + Test that a command still runs even if a connection times out + and that the return code is correct for the comand being run + """ + self.check_args( + "localhost:8929 --timeout=1 -- echo \"CMD OUTPUT\"", + "CMD OUTPUT", + ".*wait-for-it.sh: timeout occurred after waiting 1 seconds for localhost:8929", + 0 + ) + + if __name__ == '__main__': unittest.main() From 13745289ba677fea19e3e8839356bed94a0988e0 Mon Sep 17 00:00:00 2001 From: Douglas Gibbons Date: Sun, 26 Mar 2017 22:52:51 -0700 Subject: [PATCH 4/6] Modified error output for 'ls' command to cope with different test environments --- test/wait-for-it.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/wait-for-it.py b/test/wait-for-it.py index f4a6194..fd07f9b 100644 --- a/test/wait-for-it.py +++ b/test/wait-for-it.py @@ -160,7 +160,7 @@ class TestWaitForIt(unittest.TestCase): self.check_args( "localhost:8929 -- ls not_real_file", "", - ".*ls: cannot access 'not_real_file': No such file or directory\n", + ".*No such file or directory\n", 2 ) soc.close() From f9b79b2e51f7a0925ad15cb4bd1cc1007acfd4a4 Mon Sep 17 00:00:00 2001 From: Douglas Gibbons Date: Sun, 26 Mar 2017 23:10:11 -0700 Subject: [PATCH 5/6] Tidy up of vars in tests --- test/wait-for-it.py | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/test/wait-for-it.py b/test/wait-for-it.py index fd07f9b..7d7b0f8 100644 --- a/test/wait-for-it.py +++ b/test/wait-for-it.py @@ -7,9 +7,10 @@ import sys import socket import re -missing_args_text = "Error: you need to provide a host and port to test." -help_text = "Usage:" -dividing_line = '-'*71 # Output line of dashes +MISSING_ARGS_TEXT = "Error: you need to provide a host and port to test." +HELP_TEXT = "Usage:" # Start of help text +DIVIDE_LINE = '-'*71 # Output line of dashes + """ TestWaitForIt tests the wait-for-it.sh shell script. @@ -34,21 +35,21 @@ class TestWaitForIt(unittest.TestCase): return s def check_args(self,args,stdout_regex,stderr_regex,exitcode): - command = self.wait_script+" "+args + command = self.wait_script + " " + args actual_exitcode, out, err = self.execute(command) # Check stderr msg = ("Failed check that STDERR:\n"+ - dividing_line + "\n"+err+"\n"+dividing_line+ - "\nmatches:\n"+ - dividing_line + "\n"+stderr_regex+"\n"+dividing_line) + DIVIDE_LINE + "\n" + err + "\n" + DIVIDE_LINE + + "\nmatches:\n" + + DIVIDE_LINE + "\n" + stderr_regex + "\n" + DIVIDE_LINE) self.assertIsNotNone(re.match(stderr_regex,err,re.DOTALL),msg) # Check STDOUT msg = ("Failed check that STDOUT:\n"+ - dividing_line + "\n"+out+"\n"+dividing_line+ - "\nmatches:\n"+ - dividing_line + "\n"+stdout_regex+"\n"+dividing_line) + DIVIDE_LINE + "\n" + out + "\n" + DIVIDE_LINE + + "\nmatches:\n" + + DIVIDE_LINE + "\n" + stdout_regex + "\n" + DIVIDE_LINE) self.assertIsNotNone(re.match(stdout_regex,out,re.DOTALL),msg) # Check exit code @@ -67,7 +68,7 @@ class TestWaitForIt(unittest.TestCase): self.check_args( "", "^$", - missing_args_text, + MISSING_ARGS_TEXT, 1 ) # Return code should be 1 when called with no args @@ -79,7 +80,7 @@ class TestWaitForIt(unittest.TestCase): self.check_args( "--help", "", - help_text, + HELP_TEXT, 1 ) @@ -88,7 +89,7 @@ class TestWaitForIt(unittest.TestCase): self.check_args( "--host=localhost", "", - missing_args_text, + MISSING_ARGS_TEXT, 1 ) @@ -97,7 +98,7 @@ class TestWaitForIt(unittest.TestCase): self.check_args( "--port=80", "", - missing_args_text, + MISSING_ARGS_TEXT, 1 ) From 8ed81e380330f8ab72a8f8ea6bf7a657d744b8f0 Mon Sep 17 00:00:00 2001 From: Douglas Gibbons Date: Wed, 17 May 2017 10:18:55 -0700 Subject: [PATCH 6/6] Fixes to test script for flake8 --- .travis.yml | 4 +- test/wait-for-it.py | 93 +++++++++++++++++++++------------------------ 2 files changed, 47 insertions(+), 50 deletions(-) diff --git a/.travis.yml b/.travis.yml index dfd38c8..30a8138 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,4 +2,6 @@ language: python python: - "2.7" -script: python test/wait-for-it.py +script: + - python test/wait-for-it.py + diff --git a/test/wait-for-it.py b/test/wait-for-it.py index 7d7b0f8..e06fb8c 100644 --- a/test/wait-for-it.py +++ b/test/wait-for-it.py @@ -1,5 +1,4 @@ import unittest -import subprocess import shlex from subprocess import Popen, PIPE import os @@ -11,59 +10,58 @@ MISSING_ARGS_TEXT = "Error: you need to provide a host and port to test." HELP_TEXT = "Usage:" # Start of help text DIVIDE_LINE = '-'*71 # Output line of dashes -""" - TestWaitForIt tests the wait-for-it.sh shell script. - - The wait-for-it.sh script is assumed to be in the parent directory to the - test script. -""" + class TestWaitForIt(unittest.TestCase): + """ + TestWaitForIt tests the wait-for-it.sh shell script. + The wait-for-it.sh script is assumed to be in the parent directory to + the test script. + """ - - def execute(self,cmd): + def execute(self, cmd): """Executes a command and returns exit code, STDOUT, STDERR""" args = shlex.split(cmd) proc = Popen(args, stdout=PIPE, stderr=PIPE) out, err = proc.communicate() exitcode = proc.returncode return exitcode, out, err - - def open_local_port(self,host="localhost", port=8929, timeout=5): + + def open_local_port(self, host="localhost", port=8929, timeout=5): s = socket.socket() - s.bind((host,port)) + s.bind((host, port)) s.listen(timeout) return s - - def check_args(self,args,stdout_regex,stderr_regex,exitcode): + + def check_args(self, args, stdout_regex, stderr_regex, exitcode): command = self.wait_script + " " + args actual_exitcode, out, err = self.execute(command) - + # Check stderr - msg = ("Failed check that STDERR:\n"+ - DIVIDE_LINE + "\n" + err + "\n" + DIVIDE_LINE + - "\nmatches:\n" + - DIVIDE_LINE + "\n" + stderr_regex + "\n" + DIVIDE_LINE) - self.assertIsNotNone(re.match(stderr_regex,err,re.DOTALL),msg) - - # Check STDOUT - msg = ("Failed check that STDOUT:\n"+ + msg = ("Failed check that STDERR:\n" + + DIVIDE_LINE + "\n" + err + "\n" + DIVIDE_LINE + + "\nmatches:\n" + + DIVIDE_LINE + "\n" + stderr_regex + "\n" + DIVIDE_LINE) + self.assertIsNotNone(re.match(stderr_regex, err, re.DOTALL), msg) + + # Check STDOUT + msg = ("Failed check that STDOUT:\n" + DIVIDE_LINE + "\n" + out + "\n" + DIVIDE_LINE + "\nmatches:\n" + DIVIDE_LINE + "\n" + stdout_regex + "\n" + DIVIDE_LINE) - self.assertIsNotNone(re.match(stdout_regex,out,re.DOTALL),msg) + self.assertIsNotNone(re.match(stdout_regex, out, re.DOTALL), msg) # Check exit code - self.assertEqual(actual_exitcode,exitcode) - + self.assertEqual(actual_exitcode, exitcode) + def setUp(self): script_path = os.path.dirname(sys.argv[0]) parent_path = os.path.abspath(os.path.join(script_path, os.pardir)) - self.wait_script = os.path.join(parent_path,"wait-for-it.sh") - + self.wait_script = os.path.join(parent_path, "wait-for-it.sh") + def test_no_args(self): """ - Check that no aruments returns the missing args text and the correct - return code + Check that no aruments returns the missing args text and the + correct return code """ self.check_args( "", @@ -73,15 +71,15 @@ class TestWaitForIt(unittest.TestCase): ) # Return code should be 1 when called with no args exitcode, out, err = self.execute(self.wait_script) - self.assertEqual(exitcode,1) - + self.assertEqual(exitcode, 1) + def test_help(self): - """ Check that help text is printed with --help argument """ - self.check_args( - "--help", - "", - HELP_TEXT, - 1 + """ Check that help text is printed with --help argument """ + self.check_args( + "--help", + "", + HELP_TEXT, + 1 ) def test_no_port(self): @@ -112,7 +110,7 @@ class TestWaitForIt(unittest.TestCase): 0 ) soc.close() - + def test_combined_host_port(self): """ Tests that wait-for-it.sh returns correctly after establishing a @@ -126,7 +124,7 @@ class TestWaitForIt(unittest.TestCase): 0 ) soc.close() - + def test_port_failure_with_timeout(self): """ Note exit status of 124 is exected, passed from the timeout command @@ -134,7 +132,7 @@ class TestWaitForIt(unittest.TestCase): self.check_args( "localhost:8929 --timeout=1", "", - ".*wait-for-it.sh: timeout occurred after waiting 1 seconds for localhost:8929", + ".*timeout occurred after waiting 1 seconds for localhost:8929", 124 ) @@ -151,21 +149,19 @@ class TestWaitForIt(unittest.TestCase): ) soc.close() - def test_failed_command_execution(self): """ - Check command failure. The command in question outputs STDERR and an - exit code of 2 + Check command failure. The command in question outputs STDERR and + an exit code of 2 """ soc = self.open_local_port(port=8929) self.check_args( "localhost:8929 -- ls not_real_file", "", - ".*No such file or directory\n", + ".*No such file or directory\n", 2 ) soc.close() - def test_command_after_connection_failure(self): """ @@ -175,10 +171,9 @@ class TestWaitForIt(unittest.TestCase): self.check_args( "localhost:8929 --timeout=1 -- echo \"CMD OUTPUT\"", "CMD OUTPUT", - ".*wait-for-it.sh: timeout occurred after waiting 1 seconds for localhost:8929", + ".*timeout occurred after waiting 1 seconds for localhost:8929", 0 ) - - + if __name__ == '__main__': unittest.main()