_exit_test.py
Go to the documentation of this file.
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 
16 The tests in this module spawn a subprocess for each test case, the
17 test is considered successful if it doesn't freeze/timeout.
18 """
19 
20 import atexit
21 import datetime
22 import logging
23 import os
24 import signal
25 import subprocess
26 import sys
27 import threading
28 import time
29 import unittest
30 
31 import six
32 
33 from tests.unit import _exit_scenarios
34 
35 SCENARIO_FILE = os.path.abspath(
36  os.path.join(os.path.dirname(os.path.realpath(__file__)),
37  '_exit_scenarios.py'))
38 INTERPRETER = sys.executable
39 BASE_COMMAND = [INTERPRETER, SCENARIO_FILE]
40 BASE_SIGTERM_COMMAND = BASE_COMMAND + ['--wait_for_interrupt']
41 
42 INIT_TIME = datetime.timedelta(seconds=1)
43 WAIT_CHECK_INTERVAL = datetime.timedelta(milliseconds=100)
44 WAIT_CHECK_DEFAULT_TIMEOUT = datetime.timedelta(seconds=5)
45 
46 processes = []
47 process_lock = threading.Lock()
48 
49 
50 # Make sure we attempt to clean up any
51 # processes we may have left running
53  with process_lock:
54  for process in processes:
55  try:
56  process.kill()
57  except Exception: # pylint: disable=broad-except
58  pass
59 
60 
61 atexit.register(cleanup_processes)
62 
63 
64 def _process_wait_with_timeout(process, timeout=WAIT_CHECK_DEFAULT_TIMEOUT):
65  """A funciton to mimic 3.3+ only timeout argument in process.wait."""
66  deadline = datetime.datetime.now() + timeout
67  while (process.poll() is None) and (datetime.datetime.now() < deadline):
68  time.sleep(WAIT_CHECK_INTERVAL.total_seconds())
69  if process.returncode is None:
70  raise RuntimeError('Process failed to exit within %s' % timeout)
71 
72 
73 def interrupt_and_wait(process):
74  with process_lock:
75  processes.append(process)
76  time.sleep(INIT_TIME.total_seconds())
77  os.kill(process.pid, signal.SIGINT)
79 
80 
81 def wait(process):
82  with process_lock:
83  processes.append(process)
85 
86 
87 # TODO(lidiz) enable exit tests once the root cause found.
88 @unittest.skip('https://github.com/grpc/grpc/issues/23982')
89 @unittest.skip('https://github.com/grpc/grpc/issues/23028')
90 class ExitTest(unittest.TestCase):
91 
93  process = subprocess.Popen(BASE_COMMAND +
94  [_exit_scenarios.UNSTARTED_SERVER],
95  stdout=sys.stdout,
96  stderr=sys.stderr)
97  wait(process)
98 
100  process = subprocess.Popen(BASE_SIGTERM_COMMAND +
101  [_exit_scenarios.UNSTARTED_SERVER],
102  stdout=sys.stdout)
103  interrupt_and_wait(process)
104 
106  process = subprocess.Popen(BASE_COMMAND +
107  [_exit_scenarios.RUNNING_SERVER],
108  stdout=sys.stdout,
109  stderr=sys.stderr)
110  wait(process)
111 
113  process = subprocess.Popen(BASE_SIGTERM_COMMAND +
114  [_exit_scenarios.RUNNING_SERVER],
115  stdout=sys.stdout,
116  stderr=sys.stderr)
117  interrupt_and_wait(process)
118 
120  process = subprocess.Popen(
121  BASE_COMMAND + [_exit_scenarios.POLL_CONNECTIVITY_NO_SERVER],
122  stdout=sys.stdout,
123  stderr=sys.stderr)
124  wait(process)
125 
127  process = subprocess.Popen(
128  BASE_SIGTERM_COMMAND +
129  [_exit_scenarios.POLL_CONNECTIVITY_NO_SERVER],
130  stdout=sys.stdout,
131  stderr=sys.stderr)
132  interrupt_and_wait(process)
133 
135  process = subprocess.Popen(BASE_COMMAND +
136  [_exit_scenarios.POLL_CONNECTIVITY],
137  stdout=sys.stdout,
138  stderr=sys.stderr)
139  wait(process)
140 
142  process = subprocess.Popen(BASE_SIGTERM_COMMAND +
143  [_exit_scenarios.POLL_CONNECTIVITY],
144  stdout=sys.stdout,
145  stderr=sys.stderr)
146  interrupt_and_wait(process)
147 
148  @unittest.skipIf(os.name == 'nt',
149  'os.kill does not have required permission on Windows')
151  process = subprocess.Popen(BASE_COMMAND +
152  [_exit_scenarios.IN_FLIGHT_UNARY_UNARY_CALL],
153  stdout=sys.stdout,
154  stderr=sys.stderr)
155  interrupt_and_wait(process)
156 
157  @unittest.skipIf(os.name == 'nt',
158  'os.kill does not have required permission on Windows')
160  process = subprocess.Popen(
161  BASE_COMMAND + [_exit_scenarios.IN_FLIGHT_UNARY_STREAM_CALL],
162  stdout=sys.stdout,
163  stderr=sys.stderr)
164  interrupt_and_wait(process)
165 
166  @unittest.skipIf(os.name == 'nt',
167  'os.kill does not have required permission on Windows')
169  process = subprocess.Popen(
170  BASE_COMMAND + [_exit_scenarios.IN_FLIGHT_STREAM_UNARY_CALL],
171  stdout=sys.stdout,
172  stderr=sys.stderr)
173  interrupt_and_wait(process)
174 
175  @unittest.skipIf(os.name == 'nt',
176  'os.kill does not have required permission on Windows')
178  process = subprocess.Popen(
179  BASE_COMMAND + [_exit_scenarios.IN_FLIGHT_STREAM_STREAM_CALL],
180  stdout=sys.stdout,
181  stderr=sys.stderr)
182  interrupt_and_wait(process)
183 
184  @unittest.skipIf(os.name == 'nt',
185  'os.kill does not have required permission on Windows')
187  process = subprocess.Popen(
188  BASE_COMMAND +
189  [_exit_scenarios.IN_FLIGHT_PARTIAL_UNARY_STREAM_CALL],
190  stdout=sys.stdout,
191  stderr=sys.stderr)
192  interrupt_and_wait(process)
193 
194  @unittest.skipIf(os.name == 'nt',
195  'os.kill does not have required permission on Windows')
197  process = subprocess.Popen(
198  BASE_COMMAND +
199  [_exit_scenarios.IN_FLIGHT_PARTIAL_STREAM_UNARY_CALL],
200  stdout=sys.stdout,
201  stderr=sys.stderr)
202  interrupt_and_wait(process)
203 
204  @unittest.skipIf(os.name == 'nt',
205  'os.kill does not have required permission on Windows')
207  process = subprocess.Popen(
208  BASE_COMMAND +
209  [_exit_scenarios.IN_FLIGHT_PARTIAL_STREAM_STREAM_CALL],
210  stdout=sys.stdout,
211  stderr=sys.stderr)
212  interrupt_and_wait(process)
213 
214 
215 if __name__ == '__main__':
216  logging.basicConfig(level=logging.DEBUG)
217  unittest.main(verbosity=2)
tests.unit._exit_test.ExitTest.test_in_flight_partial_stream_stream_call
def test_in_flight_partial_stream_stream_call(self)
Definition: _exit_test.py:206
tests.unit._exit_test.ExitTest.test_in_flight_partial_stream_unary_call
def test_in_flight_partial_stream_unary_call(self)
Definition: _exit_test.py:196
tests.unit._exit_test.ExitTest.test_poll_connectivity_terminate
def test_poll_connectivity_terminate(self)
Definition: _exit_test.py:141
tests.unit._exit_test.ExitTest.test_in_flight_unary_stream_call
def test_in_flight_unary_stream_call(self)
Definition: _exit_test.py:159
tests.unit._exit_test._process_wait_with_timeout
def _process_wait_with_timeout(process, timeout=WAIT_CHECK_DEFAULT_TIMEOUT)
Definition: _exit_test.py:64
tests.unit._exit_test.ExitTest.test_poll_connectivity_no_server_terminate
def test_poll_connectivity_no_server_terminate(self)
Definition: _exit_test.py:126
tests.unit._exit_test.ExitTest.test_in_flight_partial_unary_stream_call
def test_in_flight_partial_unary_stream_call(self)
Definition: _exit_test.py:186
tests.unit._exit_test.cleanup_processes
def cleanup_processes()
Definition: _exit_test.py:52
tests.unit._exit_test.ExitTest.test_running_server_terminate
def test_running_server_terminate(self)
Definition: _exit_test.py:112
tests.unit._exit_test.ExitTest.test_poll_connectivity_no_server
def test_poll_connectivity_no_server(self)
Definition: _exit_test.py:119
tests.unit._exit_test.ExitTest.test_running_server
def test_running_server(self)
Definition: _exit_test.py:105
tests.unit._exit_test.ExitTest.test_poll_connectivity
def test_poll_connectivity(self)
Definition: _exit_test.py:134
tests.unit._exit_test.ExitTest.test_unstarted_server
def test_unstarted_server(self)
Definition: _exit_test.py:92
tests.unit._exit_test.ExitTest.test_in_flight_stream_stream_call
def test_in_flight_stream_stream_call(self)
Definition: _exit_test.py:177
tests.unit._exit_test.ExitTest
Definition: _exit_test.py:90
tests.unit
Definition: src/python/grpcio_tests/tests/unit/__init__.py:1
tests.unit._exit_test.ExitTest.test_unstarted_server_terminate
def test_unstarted_server_terminate(self)
Definition: _exit_test.py:99
tests.unit._exit_test.ExitTest.test_in_flight_unary_unary_call
def test_in_flight_unary_unary_call(self)
Definition: _exit_test.py:150
tests.unit._exit_test.wait
def wait(process)
Definition: _exit_test.py:81
tests.unit._exit_test.ExitTest.test_in_flight_stream_unary_call
def test_in_flight_stream_unary_call(self)
Definition: _exit_test.py:168
tests.unit._exit_test.interrupt_and_wait
def interrupt_and_wait(process)
Definition: _exit_test.py:73


grpc
Author(s):
autogenerated on Thu Mar 13 2025 02:58:27