Patch by Zack W to make test_noinherit() more robust: spawn a Python
authorGuido van Rossum <guido@python.org>
Sat, 17 Aug 2002 11:41:01 +0000 (11:41 +0000)
committerGuido van Rossum <guido@python.org>
Sat, 17 Aug 2002 11:41:01 +0000 (11:41 +0000)
subprocess that does the right checks.  This now works on Windows as
well.

Lib/test/test_tempfile.py
Lib/test/tf_inherit_check.py [new file with mode: 0644]

index 0e1c8914d2cbc1e68ab3d0445038c1d2c892f4fc..575986f23d4882aec492e0954b97c81d04807fe2 100644 (file)
@@ -17,6 +17,7 @@ else:
     has_stat = 0
 
 has_textmode = (tempfile._text_openflags != tempfile._bin_openflags)
+has_spawnl = hasattr(os, 'spawnl')
 
 # TEST_FILES may need to be tweaked for systems depending on the maximum
 # number of files that can be opened at one time (see ulimit -n)
@@ -323,39 +324,33 @@ class test__mkstemp_inner(TC):
 
     def test_noinherit(self):
         """_mkstemp_inner file handles are not inherited by child processes"""
-        # FIXME: Find a way to test this on Windows.
-        if os.name != 'posix':
+        if not has_spawnl:
             return            # ugh, can't use TestSkipped.
 
+        if test_support.verbose:
+            v="v"
+        else:
+            v="q"
+
         file = self.do_create()
+        fd = "%d" % file.fd
 
-        # We have to exec something, so that FD_CLOEXEC will take
-        # effect.  The sanest thing to try is /bin/sh; we can easily
-        # instruct it to attempt to write to the fd and report success
-        # or failure.  Unfortunately, sh syntax does not permit use of
-        # fds numerically larger than 9; abandon this test if so.
-        if file.fd > 9:
-            raise test_support.TestSkipped, 'cannot test with fd %d' % file.fd
-
-        pid = os.fork()
-        if pid:
-            status = os.wait()[1]
-            self.failUnless(os.WIFEXITED(status),
-                            "child process did not exit (status %d)" % status)
-
-            # We want the child to have exited _un_successfully, indicating
-            # failure to write to the closed fd.
-            self.failUnless(os.WEXITSTATUS(status) != 0,
-                            "child process exited successfully")
+        try:
+            me = __file__
+        except NameError:
+            me = sys.argv[0]
 
-        else:
-            try:
-                # Throw away stderr.
-                nul = os.open('/dev/null', os.O_RDWR)
-                os.dup2(nul, 2)
-                os.execv('/bin/sh', ['sh', '-c', 'echo blat >&%d' % file.fd])
-            except:
-                os._exit(0)
+        # We have to exec something, so that FD_CLOEXEC will take
+        # effect.  The core of this test is therefore in
+        # tf_inherit_check.py, which see.
+        tester = os.path.join(os.path.dirname(os.path.abspath(me)),
+                              "tf_inherit_check.py")
+
+        retval = os.spawnl(os.P_WAIT, sys.executable,
+                           sys.executable, tester, v, fd)
+        self.failIf(retval < 0,
+                    "child process caught fatal signal %d" % -retval)
+        self.failIf(retval > 0, "child process reports failure")
 
     def test_textmode(self):
         """_mkstemp_inner can create files in text mode"""
diff --git a/Lib/test/tf_inherit_check.py b/Lib/test/tf_inherit_check.py
new file mode 100644 (file)
index 0000000..a8b80d2
--- /dev/null
@@ -0,0 +1,25 @@
+# Helper script for test_tempfile.py.  argv[2] is the number of a file
+# descriptor which should _not_ be open.  Check this by attempting to
+# write to it -- if we succeed, something is wrong.
+
+import sys
+import os
+
+verbose = (sys.argv[1] == 'v')
+try:
+    fd = int(sys.argv[2])
+
+    try:
+        os.write(fd, "blat")
+    except os.error:
+        # Success -- could not write to fd.
+        sys.exit(0)
+    else:
+        if verbose:
+            sys.stderr.write("fd %d is open in child" % fd)
+        sys.exit(1)
+
+except StandardError:
+    if verbose:
+        raise
+    sys.exit(1)