Set default signal handlers for SIGINT and SIGHUP.
authorJeff Quast <contact@jeffquast.com>
Mon, 24 Nov 2014 04:14:16 +0000 (20:14 -0800)
committerJeff Quast <contact@jeffquast.com>
Mon, 24 Nov 2014 04:14:16 +0000 (20:14 -0800)
According to test_misc.py comments, fedora's build
agent has the same problem as ours.  We use the setUp
and tearDown methods to set and restore these signals,
if ignored.

tests/PexpectTestCase.py
tests/test_misc.py

index 7a9574e43c4f6a5dc4286ed1ae13ecdc8845f327..32a3e75851efdbb2bce7ca7c698a52c677bfa70f 100644 (file)
@@ -22,26 +22,55 @@ from __future__ import print_function
 
 import contextlib
 import unittest
+import signal
 import sys
 import os
 
+
 class PexpectTestCase(unittest.TestCase):
     def setUp(self):
         self.PYTHONBIN = sys.executable
         self.original_path = os.getcwd()
         tests_dir = os.path.dirname(__file__)
         self.project_dir = project_dir = os.path.dirname(tests_dir)
+
+        # all tests are executed in this folder; there are many auxiliary
+        # programs in this folder executed by spawn().
         os.chdir(tests_dir)
-        os.environ['COVERAGE_PROCESS_START'] = os.path.join(project_dir, '.coveragerc')
+
+        coverage_rc = os.path.join(project_dir, '.coveragerc')
+        os.environ['COVERAGE_PROCESS_START'] = coverage_rc
         os.environ['COVERAGE_FILE'] = os.path.join(project_dir, '.coverage')
         print('\n', self.id(), end=' ')
         sys.stdout.flush()
+
+        # some build agents will ignore SIGHUP and SIGINT, which python
+        # inherits.  This causes some of the tests related to terminate()
+        # to fail.  We set them to the default handlers that they should
+        # be, and restore them back to their SIG_IGN value on tearDown.
+        #
+        # I'm not entirely convinced they need to be restored, only our
+        # test runner is affected.
+        self.restore_ignored_signals = [
+            value for value in (signal.SIGHUP, signal.SIGINT,)
+            if signal.getsignal(value) == signal.SIG_IGN]
+        if signal.SIGHUP in self.store_ignored_signals:
+            # sighup should be set to default handler
+            signal.signal(signal.SIGHUP, signal.SIG_DFL)
+        if signal.SIGINT in self.restore_ignored_signals:
+            # SIGINT should be set to signal.default_int_handler
+            signal.signal(signal.SIGINT, signal.default_int_handler)
         unittest.TestCase.setUp(self)
 
     def tearDown(self):
-        os.chdir (self.original_path)
+        # restore original working folder
+        os.chdir(self.original_path)
+
+        # restore signal handlers
+        for signal_name in self.restore_ignored_signals:
+            signal.signal(getattr(signal, signal_name), signal.SIG_IGN)
 
-    if sys.version_info < (2,7):
+    if sys.version_info < (2, 7):
         # We want to use these methods, which are new/improved in 2.7, but
         # we are still supporting 2.6 for the moment. This section can be
         # removed when we drop Python 2.6 support.
index 9e44bab70afd98b6ee8fa05a6d4bce3c708e78b9..28df570e6baedf31c84f3fe948882a3c8c3cd612 100755 (executable)
@@ -149,41 +149,24 @@ class TestCaseMisc(PexpectTestCase.PexpectTestCase):
 
     def test_sighup(self):
         " validate argument `ignore_sighup=True` and `ignore_sighup=False`. "
-        # If a parent process sets an Ignore handler for SIGHUP (as on Fedora's
-        # build machines), this test breaks. We temporarily restore the default
-        # handler, so the child process will quit. However, we can't simply
-        # replace any installed handler, because getsignal returns None for
-        # handlers not set in Python code, so we wouldn't be able to restore
-        # them.
-        if signal.getsignal(signal.SIGHUP) == signal.SIG_IGN:
-            signal.signal(signal.SIGHUP, signal.SIG_DFL)
-            restore_sig_ign = True
-        else:
-            restore_sig_ign = False
-
         getch = sys.executable + ' getch.py'
-        try:
-            child = pexpect.spawn(getch, ignore_sighup=True)
-            child.expect('READY')
-            child.kill(signal.SIGHUP)
-            for _ in range(10):
-                if not child.isalive():
-                    self.fail('Child process should not have exited.')
-                time.sleep(0.1)
-
-            child = pexpect.spawn(getch, ignore_sighup=False)
-            child.expect('READY')
-            child.kill(signal.SIGHUP)
-            for _ in range(10):
-                if not child.isalive():
-                    break
-                time.sleep(0.1)
-            else:
-                self.fail('Child process should have exited.')
-
-        finally:
-            if restore_sig_ign:
-                signal.signal(signal.SIGHUP, signal.SIG_IGN)
+        child = pexpect.spawn(getch, ignore_sighup=True)
+        child.expect('READY')
+        child.kill(signal.SIGHUP)
+        for _ in range(10):
+            if not child.isalive():
+                self.fail('Child process should not have exited.')
+            time.sleep(0.1)
+
+        child = pexpect.spawn(getch, ignore_sighup=False)
+        child.expect('READY')
+        child.kill(signal.SIGHUP)
+        for _ in range(10):
+            if not child.isalive():
+                break
+            time.sleep(0.1)
+        else:
+            self.fail('Child process should have exited.')
 
     def test_bad_child_pid(self):
         " assert bad condition error in isalive(). "