commit 165c75ba21184b4fe865e7a30ce2d69012836a26 Author: Damian Johnson atagar@torproject.org Date: Wed Oct 24 12:40:38 2018 -0700
Integration test race when multiple tor processes are running
Our flakiest integration tests on Jenkins tend to be our system tests...
====================================================================== FAIL: test_pid_by_name_ps_linux ---------------------------------------------------------------------- Traceback (most recent call last): File "/srv/jenkins-workspace/workspace/stem-tor-ci/test/require.py", line 58, in wrapped return func(self, *args, **kwargs) File "/srv/jenkins-workspace/workspace/stem-tor-ci/test/require.py", line 58, in wrapped return func(self, *args, **kwargs) File "/srv/jenkins-workspace/workspace/stem-tor-ci/test/require.py", line 58, in wrapped return func(self, *args, **kwargs) File "/srv/jenkins-workspace/workspace/stem-tor-ci/test/integ/util/system.py", line 211, in test_pid_by_name_ps_linux self.assertEqual(tor_pid, stem.util.system.pid_by_name(tor_cmd)) AssertionError: 31963 != None
----------------------------------------------------------------------
These tests skip themselves if multiple tor processes are running, *but* they fail in this fashion if a tor process spawns *during* the test.
To reduce the chances of this the tests now check for additional tor processes both before *and* after the test. In theory an error could still occure if a tor process both starts *and* stops in the middle of a test but I'm unsure if this will really happen in practice. Lets see. If these assertion errors continue to show up I might simply move them under a special target. --- test/integ/util/system.py | 21 ++++++++++++++++++++- test/require.py | 2 +- 2 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/test/integ/util/system.py b/test/integ/util/system.py index cc6f9eda..06202bfa 100644 --- a/test/integ/util/system.py +++ b/test/integ/util/system.py @@ -65,13 +65,32 @@ def _has_port(): return test.runner.Torrc.PORT in test.runner.get_runner().get_options()
-require_single_tor_instance = test.require.needs(_is_single_tor_running, 'multiple tor instances') require_control_port = test.require.needs(_has_port, 'test instance has no port') require_linux = test.require.needs(_is_linux, 'linux only') require_bsd = test.require.needs(stem.util.system.is_bsd, 'bsd only') require_path = test.require.needs(lambda: 'PATH' in os.environ, 'requires PATH')
+def require_single_tor_instance(func): + # Checking both before and after the test to see if we're running only a + # single tor instance. We do both to narrow the possability of the test + # failing due to a race. + + def wrapped(self, *args, **kwargs): + if _is_single_tor_running(): + try: + return func(self, *args, **kwargs) + except: + if _is_single_tor_running(): + raise + else: + self.skipTest('(multiple tor instances)') + else: + self.skipTest('(multiple tor instances)') + + return wrapped + + class TestSystem(unittest.TestCase): def test_daemon_task_when_successful(self): """ diff --git a/test/require.py b/test/require.py index 598576bf..25a7ae12 100644 --- a/test/require.py +++ b/test/require.py @@ -49,7 +49,7 @@ def only_run_once(func):
def needs(condition, message): """ - Skips teh test unless the conditional evaluates to 'true'. + Skips the test unless the conditional evaluates to 'true'. """
def decorator(func):