77import unittest
88import warnings
99import sys
10+ import signal
11+ import subprocess
12+ import time
1013import shutil
1114from test import support
1215
16+
1317# Tests creating TESTFN
1418class FileTests (unittest .TestCase ):
1519 def setUp (self ):
@@ -739,7 +743,6 @@ def test_setreuid(self):
739743 def test_setreuid_neg1 (self ):
740744 # Needs to accept -1. We run this in a subprocess to avoid
741745 # altering the test runner's process state (issue8045).
742- import subprocess
743746 subprocess .check_call ([
744747 sys .executable , '-c' ,
745748 'import os,sys;os.setreuid(-1,-1);sys.exit(0)' ])
@@ -754,7 +757,6 @@ def test_setregid(self):
754757 def test_setregid_neg1 (self ):
755758 # Needs to accept -1. We run this in a subprocess to avoid
756759 # altering the test runner's process state (issue8045).
757- import subprocess
758760 subprocess .check_call ([
759761 sys .executable , '-c' ,
760762 'import os,sys;os.setregid(-1,-1);sys.exit(0)' ])
@@ -798,6 +800,63 @@ class PosixUidGidTests(unittest.TestCase):
798800 class Pep383Tests (unittest .TestCase ):
799801 pass
800802
803+ @unittest .skipUnless (sys .platform == "win32" , "Win32 specific tests" )
804+ class Win32KillTests (unittest .TestCase ):
805+ def _kill (self , sig , * args ):
806+ # Send a subprocess a signal (or in some cases, just an int to be
807+ # the return value)
808+ proc = subprocess .Popen (* args )
809+ os .kill (proc .pid , sig )
810+ self .assertEqual (proc .wait (), sig )
811+
812+ def test_kill_sigterm (self ):
813+ # SIGTERM doesn't mean anything special, but make sure it works
814+ self ._kill (signal .SIGTERM , [sys .executable ])
815+
816+ def test_kill_int (self ):
817+ # os.kill on Windows can take an int which gets set as the exit code
818+ self ._kill (100 , [sys .executable ])
819+
820+ def _kill_with_event (self , event , name ):
821+ # Run a script which has console control handling enabled.
822+ proc = subprocess .Popen ([sys .executable ,
823+ os .path .join (os .path .dirname (__file__ ),
824+ "win_console_handler.py" )],
825+ creationflags = subprocess .CREATE_NEW_PROCESS_GROUP )
826+ # Let the interpreter startup before we send signals. See #3137.
827+ time .sleep (0.5 )
828+ os .kill (proc .pid , event )
829+ # proc.send_signal(event) could also be done here.
830+ # Allow time for the signal to be passed and the process to exit.
831+ time .sleep (0.5 )
832+ if not proc .poll ():
833+ # Forcefully kill the process if we weren't able to signal it.
834+ os .kill (proc .pid , signal .SIGINT )
835+ self .fail ("subprocess did not stop on {}" .format (name ))
836+
837+ @unittest .skip ("subprocesses aren't inheriting CTRL+C property" )
838+ def test_CTRL_C_EVENT (self ):
839+ from ctypes import wintypes
840+ import ctypes
841+
842+ # Make a NULL value by creating a pointer with no argument.
843+ NULL = ctypes .POINTER (ctypes .c_int )()
844+ SetConsoleCtrlHandler = ctypes .windll .kernel32 .SetConsoleCtrlHandler
845+ SetConsoleCtrlHandler .argtypes = (ctypes .POINTER (ctypes .c_int ),
846+ wintypes .BOOL )
847+ SetConsoleCtrlHandler .restype = wintypes .BOOL
848+
849+ # Calling this with NULL and FALSE causes the calling process to
850+ # handle CTRL+C, rather than ignore it. This property is inherited
851+ # by subprocesses.
852+ SetConsoleCtrlHandler (NULL , 0 )
853+
854+ self ._kill_with_event (signal .CTRL_C_EVENT , "CTRL_C_EVENT" )
855+
856+ def test_CTRL_BREAK_EVENT (self ):
857+ self ._kill_with_event (signal .CTRL_BREAK_EVENT , "CTRL_BREAK_EVENT" )
858+
859+
801860def test_main ():
802861 support .run_unittest (
803862 ArgTests ,
@@ -812,7 +871,8 @@ def test_main():
812871 Win32ErrorTests ,
813872 TestInvalidFD ,
814873 PosixUidGidTests ,
815- Pep383Tests
874+ Pep383Tests ,
875+ Win32KillTests
816876 )
817877
818878if __name__ == "__main__" :
0 commit comments