From 841c2b13a14662e6b5c05983ef385c82d6addb24 Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Sun, 1 Apr 2018 01:17:29 +0100 Subject: [PATCH 01/10] fakessh_test: Apply timeout decorators to rsync tests timeoutcontext.timeout uses SIGALRM, hence it will only work on Unix like operating systems. --- dev_requirements.txt | 1 + tests/fakessh_test.py | 3 +++ 2 files changed, 4 insertions(+) diff --git a/dev_requirements.txt b/dev_requirements.txt index 7761ff4a..3d1b0624 100644 --- a/dev_requirements.txt +++ b/dev_requirements.txt @@ -9,6 +9,7 @@ pytest-catchlog==1.2.2 pytest==3.1.2 PyYAML==3.11; python_version < '2.7' PyYAML==3.12; python_version >= '2.7' +timeoutcontext==1.2.0 unittest2==1.1.0 # Fix InsecurePlatformWarning while creating py26 tox environment # https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings diff --git a/tests/fakessh_test.py b/tests/fakessh_test.py index 6e28be1d..8711b46b 100644 --- a/tests/fakessh_test.py +++ b/tests/fakessh_test.py @@ -2,6 +2,7 @@ import os import shutil +import timeoutcontext import unittest2 import mitogen.fakessh @@ -10,6 +11,7 @@ import testlib class RsyncTest(testlib.DockerMixin, unittest2.TestCase): + @timeoutcontext.timeout(5) def test_rsync_from_master(self): context = self.docker_ssh_any() @@ -25,6 +27,7 @@ class RsyncTest(testlib.DockerMixin, unittest2.TestCase): self.assertTrue(context.call(os.path.exists, '/tmp/data')) self.assertTrue(context.call(os.path.exists, '/tmp/data/simple_pkg/a.py')) + @timeoutcontext.timeout(5) def test_rsync_between_direct_children(self): # master -> SSH -> has-sudo-pubkey -> rsync(.ssh) -> master -> # has-sudo -> rsync From 0dcaeb21a2185ac23303d1902d0877d94f19c091 Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Sun, 1 Apr 2018 01:21:42 +0100 Subject: [PATCH 02/10] master_test: Don't assume __file__ points to source code When run under a test runner the unit tests are imported as modules. This triggers .pyc generation, after which __file__ resolves to the .pyc file. --- tests/master_test.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/master_test.py b/tests/master_test.py index 796c7084..cf16d6c5 100644 --- a/tests/master_test.py +++ b/tests/master_test.py @@ -1,3 +1,4 @@ +import inspect import unittest2 @@ -9,8 +10,10 @@ class ScanCodeImportsTest(unittest2.TestCase): func = staticmethod(mitogen.master.scan_code_imports) def test_simple(self): - co = compile(open(__file__).read(), __file__, 'exec') + source_path = inspect.getsourcefile(ScanCodeImportsTest) + co = compile(open(source_path).read(), source_path, 'exec') self.assertEquals(list(self.func(co)), [ + (-1, 'inspect', ()), (-1, 'unittest2', ()), (-1, 'testlib', ()), (-1, 'mitogen.master', ()), From a22294dda9e6241ea9005395845628b8bdb12b48 Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Sun, 1 Apr 2018 01:23:13 +0100 Subject: [PATCH 03/10] call_function_test: Fix assumption that we run as a script --- tests/call_function_test.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/call_function_test.py b/tests/call_function_test.py index d66864b4..de3f1f46 100644 --- a/tests/call_function_test.py +++ b/tests/call_function_test.py @@ -64,7 +64,10 @@ class CallFunctionTest(testlib.RouterMixin, testlib.TestCase): def test_bad_return_value(self): exc = self.assertRaises(mitogen.core.StreamError, lambda: self.local.call(func_with_bad_return_value)) - self.assertEquals(exc[0], "cannot unpickle '__main__'/'CrazyType'") + self.assertEquals( + exc[0], + "cannot unpickle '%s'/'CrazyType'" % (__name__,), + ) def test_returns_dead(self): self.assertEqual(mitogen.core._DEAD, self.local.call(func_returns_dead)) From 7b8fef5284c4d7c44c295cf18f83e9d7372a9d66 Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Sun, 1 Apr 2018 01:32:13 +0100 Subject: [PATCH 04/10] tests: Make the tests directory an importable package Required for test discovery by e.g. unit2, pytest --- tests/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/__init__.py diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 00000000..e69de29b From dc60f05a4057c870ab88ceb362e8e1c0d73048e2 Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Sun, 1 Apr 2018 01:42:31 +0100 Subject: [PATCH 05/10] tests: Switch to unit2 test runner, with coverage This means test files are imported as modules, not run as scripts. THey can still be run individually if so desired. Test coverage is measured, and an html report generated in htmlcov/. Test cases are automativally discovered, so they need not be listed twice. An overall passed/failed/skipped summary is printed, rather than for each file. Arguments passed to ./test are passed on to unit2. For instance ./test -v will print each test name as it is run. --- .gitignore | 2 ++ .travis.yml | 2 +- setup.cfg | 7 ++++++ test | 11 +++++++++ test.sh | 63 ------------------------------------------------- tests/README.md | 2 +- tox.ini | 2 +- 7 files changed, 23 insertions(+), 66 deletions(-) create mode 100755 test delete mode 100755 test.sh diff --git a/.gitignore b/.gitignore index 9a539564..9ec8ce9b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,9 @@ +.coverage .venv **/.DS_Store MANIFEST build/ dist/ docs/_build +htmlcov/ *.egg-info diff --git a/.travis.yml b/.travis.yml index a7f2f637..8deda0c0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,7 @@ install: - pip install -r dev_requirements.txt script: -- MITOGEN_LOG_LEVEL=debug PYTHONPATH=. ${TRAVIS_BUILD_DIR}/test.sh +- MITOGEN_LOG_LEVEL=debug PYTHONPATH=. ${TRAVIS_BUILD_DIR}/test services: - docker diff --git a/setup.cfg b/setup.cfg index 44668df3..92051682 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,3 +1,10 @@ +[coverage:run] +branch = true +source = + mitogen +omit = + mitogen/compat/* + [flake8] ignore = E402,E128,W503 exclude = mitogen/compat diff --git a/test b/test new file mode 100755 index 00000000..aeb9c51c --- /dev/null +++ b/test @@ -0,0 +1,11 @@ +#/bin/sh + +UNIT2="$(which unit2)" + +coverage erase +coverage run "${UNIT2}" discover \ + --start-directory "tests" \ + --pattern '*_test.py' \ + "$@" +coverage html +echo coverage report is at "file://$(pwd)/htmlcov/index.html" diff --git a/test.sh b/test.sh deleted file mode 100755 index ab545104..00000000 --- a/test.sh +++ /dev/null @@ -1,63 +0,0 @@ -#!/bin/bash - -timeout() -{ - python -c ' -import subprocess -import sys -import time - -deadline = time.time() + float(sys.argv[1]) -proc = subprocess.Popen(sys.argv[2:]) -while time.time() < deadline and proc.poll() is None: - time.sleep(1.0) - -if proc.poll() is not None: - sys.exit(proc.returncode) -proc.terminate() -print -print >> sys.stderr, "Timeout! Command was:", sys.argv[2:] -print -sys.exit(1) - ' "$@" -} - -trap 'sigint' INT -sigint() -{ - echo "SIGINT received, stopping.." - exit 1 -} - -run_test() -{ - echo "Running $1.." - timeout 10 python $1 || fail=$? -} - -run_test tests/ansible_helpers_test.py -run_test tests/call_error_test.py -run_test tests/call_function_test.py -run_test tests/channel_test.py -run_test tests/fakessh_test.py -run_test tests/first_stage_test.py -run_test tests/fork_test.py -run_test tests/id_allocation_test.py -run_test tests/importer_test.py -run_test tests/latch_test.py -run_test tests/local_test.py -run_test tests/master_test.py -run_test tests/module_finder_test.py -run_test tests/nested_test.py -run_test tests/parent_test.py -run_test tests/receiver_test.py -run_test tests/responder_test.py -run_test tests/router_test.py -run_test tests/select_test.py -run_test tests/ssh_test.py -run_test tests/utils_test.py - -if [ "$fail" ]; then - echo "AT LEAST ONE TEST FAILED" >&2 - exit 1 -fi diff --git a/tests/README.md b/tests/README.md index 0ac4bcb1..41c024b5 100644 --- a/tests/README.md +++ b/tests/README.md @@ -27,4 +27,4 @@ and run the tests there. 1. Build the virtual environment ``virtualenv ../venv`` 1. Enable the virtual environment we just built ``source ../venv/bin/activate`` 1. Install Mitogen in pip editable mode ``pip install -e .`` -1. Run ``test.sh`` +1. Run ``test`` diff --git a/tox.ini b/tox.ini index f9eabeed..70de05df 100644 --- a/tox.ini +++ b/tox.ini @@ -8,7 +8,7 @@ deps = -r{toxinidir}/dev_requirements.txt commands = - {posargs:./test.sh} + {posargs:./test} [testenv:docs] basepython = python From 5e66f6c4fa52fe3bda0fceeb5d6ad6d7b86710c5 Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Sun, 1 Apr 2018 01:44:29 +0100 Subject: [PATCH 06/10] Ignore hidden directory containing tox environments --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 9ec8ce9b..0a843e9b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .coverage +.tox .venv **/.DS_Store MANIFEST From b5848e71162581f85016382318671ad2dffff2e3 Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Sun, 1 Apr 2018 01:45:22 +0100 Subject: [PATCH 07/10] Ignore compiled Python files --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 0a843e9b..09a0cb67 100644 --- a/.gitignore +++ b/.gitignore @@ -2,9 +2,13 @@ .tox .venv **/.DS_Store +*.pyc +*.pyd +*.pyo MANIFEST build/ dist/ docs/_build htmlcov/ *.egg-info +__pycache__/ From 94a082177d3edad7d27be61db635d5b2e9690144 Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Sun, 1 Apr 2018 02:04:41 +0100 Subject: [PATCH 08/10] tests: Add coverage as a dev requirement --- dev_requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/dev_requirements.txt b/dev_requirements.txt index 3d1b0624..59bf43de 100644 --- a/dev_requirements.txt +++ b/dev_requirements.txt @@ -1,5 +1,6 @@ -r docs/docs-requirements.txt ansible==2.3.1.0 +coverage==4.5.1 Django==1.6.11; python_version < '2.7' Django==1.11.5; python_version >= '2.7' # for module_finder_test https://github.com/docker/docker-py/archive/1.10.6.tar.gz; python_version < '2.7' From f92d88c24182142396646c464ab820d8fae14418 Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Sun, 1 Apr 2018 02:05:36 +0100 Subject: [PATCH 09/10] travis: Cache wheels and other pip artifacts Should speedup builds --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 8deda0c0..815192a6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ notifications: email: false language: python +cache: pip python: - "2.7" From 0896e95e2c6e065b36a42c5b05fae5686e1b4b70 Mon Sep 17 00:00:00 2001 From: Alex Willmer Date: Sun, 1 Apr 2018 02:11:37 +0100 Subject: [PATCH 10/10] Set strict mode in test script Exits with an error if a command is not found, any undefined variable is used, or a command in a pipeline returns an error. Should make Travis detect failed tests. --- test | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test b/test index aeb9c51c..71ce18aa 100755 --- a/test +++ b/test @@ -1,4 +1,7 @@ #/bin/sh +set -o errexit +set -o nounset +set -o pipefail UNIT2="$(which unit2)"