1# Copyright 2016 gRPC authors. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14"""Tests clean exit of server/client on Python Interpreter exit/sigint. 15 16The tests in this module spawn a subprocess for each test case, the 17test is considered successful if it doesn't hang/timeout. 18""" 19 20import atexit 21import os 22import signal 23import six 24import subprocess 25import sys 26import threading 27import time 28import unittest 29 30from tests.unit import _exit_scenarios 31 32SCENARIO_FILE = os.path.abspath( 33 os.path.join( 34 os.path.dirname(os.path.realpath(__file__)), '_exit_scenarios.py')) 35INTERPRETER = sys.executable 36BASE_COMMAND = [INTERPRETER, SCENARIO_FILE] 37BASE_SIGTERM_COMMAND = BASE_COMMAND + ['--wait_for_interrupt'] 38 39INIT_TIME = 1.0 40 41processes = [] 42process_lock = threading.Lock() 43 44 45# Make sure we attempt to clean up any 46# processes we may have left running 47def cleanup_processes(): 48 with process_lock: 49 for process in processes: 50 try: 51 process.kill() 52 except Exception: # pylint: disable=broad-except 53 pass 54 55 56atexit.register(cleanup_processes) 57 58 59def interrupt_and_wait(process): 60 with process_lock: 61 processes.append(process) 62 time.sleep(INIT_TIME) 63 os.kill(process.pid, signal.SIGINT) 64 process.wait() 65 66 67def wait(process): 68 with process_lock: 69 processes.append(process) 70 process.wait() 71 72 73@unittest.skip('https://github.com/grpc/grpc/issues/7311') 74class ExitTest(unittest.TestCase): 75 76 def test_unstarted_server(self): 77 process = subprocess.Popen( 78 BASE_COMMAND + [_exit_scenarios.UNSTARTED_SERVER], 79 stdout=sys.stdout, 80 stderr=sys.stderr) 81 wait(process) 82 83 def test_unstarted_server_terminate(self): 84 process = subprocess.Popen( 85 BASE_SIGTERM_COMMAND + [_exit_scenarios.UNSTARTED_SERVER], 86 stdout=sys.stdout) 87 interrupt_and_wait(process) 88 89 def test_running_server(self): 90 process = subprocess.Popen( 91 BASE_COMMAND + [_exit_scenarios.RUNNING_SERVER], 92 stdout=sys.stdout, 93 stderr=sys.stderr) 94 wait(process) 95 96 def test_running_server_terminate(self): 97 process = subprocess.Popen( 98 BASE_SIGTERM_COMMAND + [_exit_scenarios.RUNNING_SERVER], 99 stdout=sys.stdout, 100 stderr=sys.stderr) 101 interrupt_and_wait(process) 102 103 def test_poll_connectivity_no_server(self): 104 process = subprocess.Popen( 105 BASE_COMMAND + [_exit_scenarios.POLL_CONNECTIVITY_NO_SERVER], 106 stdout=sys.stdout, 107 stderr=sys.stderr) 108 wait(process) 109 110 def test_poll_connectivity_no_server_terminate(self): 111 process = subprocess.Popen( 112 BASE_SIGTERM_COMMAND + 113 [_exit_scenarios.POLL_CONNECTIVITY_NO_SERVER], 114 stdout=sys.stdout, 115 stderr=sys.stderr) 116 interrupt_and_wait(process) 117 118 def test_poll_connectivity(self): 119 process = subprocess.Popen( 120 BASE_COMMAND + [_exit_scenarios.POLL_CONNECTIVITY], 121 stdout=sys.stdout, 122 stderr=sys.stderr) 123 wait(process) 124 125 def test_poll_connectivity_terminate(self): 126 process = subprocess.Popen( 127 BASE_SIGTERM_COMMAND + [_exit_scenarios.POLL_CONNECTIVITY], 128 stdout=sys.stdout, 129 stderr=sys.stderr) 130 interrupt_and_wait(process) 131 132 def test_in_flight_unary_unary_call(self): 133 process = subprocess.Popen( 134 BASE_COMMAND + [_exit_scenarios.IN_FLIGHT_UNARY_UNARY_CALL], 135 stdout=sys.stdout, 136 stderr=sys.stderr) 137 interrupt_and_wait(process) 138 139 @unittest.skipIf(six.PY2, 'https://github.com/grpc/grpc/issues/6999') 140 def test_in_flight_unary_stream_call(self): 141 process = subprocess.Popen( 142 BASE_COMMAND + [_exit_scenarios.IN_FLIGHT_UNARY_STREAM_CALL], 143 stdout=sys.stdout, 144 stderr=sys.stderr) 145 interrupt_and_wait(process) 146 147 def test_in_flight_stream_unary_call(self): 148 process = subprocess.Popen( 149 BASE_COMMAND + [_exit_scenarios.IN_FLIGHT_STREAM_UNARY_CALL], 150 stdout=sys.stdout, 151 stderr=sys.stderr) 152 interrupt_and_wait(process) 153 154 @unittest.skipIf(six.PY2, 'https://github.com/grpc/grpc/issues/6999') 155 def test_in_flight_stream_stream_call(self): 156 process = subprocess.Popen( 157 BASE_COMMAND + [_exit_scenarios.IN_FLIGHT_STREAM_STREAM_CALL], 158 stdout=sys.stdout, 159 stderr=sys.stderr) 160 interrupt_and_wait(process) 161 162 @unittest.skipIf(six.PY2, 'https://github.com/grpc/grpc/issues/6999') 163 def test_in_flight_partial_unary_stream_call(self): 164 process = subprocess.Popen( 165 BASE_COMMAND + 166 [_exit_scenarios.IN_FLIGHT_PARTIAL_UNARY_STREAM_CALL], 167 stdout=sys.stdout, 168 stderr=sys.stderr) 169 interrupt_and_wait(process) 170 171 def test_in_flight_partial_stream_unary_call(self): 172 process = subprocess.Popen( 173 BASE_COMMAND + 174 [_exit_scenarios.IN_FLIGHT_PARTIAL_STREAM_UNARY_CALL], 175 stdout=sys.stdout, 176 stderr=sys.stderr) 177 interrupt_and_wait(process) 178 179 @unittest.skipIf(six.PY2, 'https://github.com/grpc/grpc/issues/6999') 180 def test_in_flight_partial_stream_stream_call(self): 181 process = subprocess.Popen( 182 BASE_COMMAND + 183 [_exit_scenarios.IN_FLIGHT_PARTIAL_STREAM_STREAM_CALL], 184 stdout=sys.stdout, 185 stderr=sys.stderr) 186 interrupt_and_wait(process) 187 188 189if __name__ == '__main__': 190 unittest.main(verbosity=2) 191