1# Copyright 2021 The 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 15import gevent 16from gevent import monkey 17 18monkey.patch_all() 19threadpool = gevent.hub.get_hub().threadpool 20 21# Currently, each channel corresponds to a single native thread in the 22# gevent threadpool. Thus, when the unit test suite spins up hundreds of 23# channels concurrently, some will be starved out, causing the test to 24# increase in duration. We increase the max size here so this does not 25# happen. 26threadpool.maxsize = 1024 27threadpool.size = 32 28 29import traceback, signal 30from typing import Sequence 31 32 33import grpc.experimental.gevent 34grpc.experimental.gevent.init_gevent() 35 36import gevent 37import greenlet 38import datetime 39 40import grpc 41import unittest 42import sys 43import os 44import pkgutil 45import importlib 46 47def trace_callback(event, args): 48 if event in ("switch", "throw"): 49 origin, target = args 50 sys.stderr.write("{} Transfer from {} to {} with {}\n".format(datetime.datetime.now(), origin, target, event)) 51 else: 52 sys.stderr.write("Unknown event {}.\n".format(event)) 53 sys.stderr.flush() 54 55if os.getenv("GREENLET_TRACE") is not None: 56 greenlet.settrace(trace_callback) 57 58def debug(sig, frame): 59 d={'_frame':frame} 60 d.update(frame.f_globals) 61 d.update(frame.f_locals) 62 63 sys.stderr.write("Traceback:\n{}".format("\n".join(traceback.format_stack(frame)))) 64 import gevent.util; gevent.util.print_run_info() 65 sys.stderr.flush() 66 67signal.signal(signal.SIGTERM, debug) 68 69 70class SingleLoader(object): 71 def __init__(self, pattern: str): 72 loader = unittest.TestLoader() 73 self.suite = unittest.TestSuite() 74 tests = [] 75 for importer, module_name, is_package in pkgutil.walk_packages([os.path.dirname(os.path.relpath(__file__))]): 76 if pattern in module_name: 77 spec = importer.find_spec(module_name) 78 module = importlib.util.module_from_spec(spec) 79 spec.loader.exec_module(module) 80 tests.append(loader.loadTestsFromModule(module)) 81 if len(tests) != 1: 82 raise AssertionError("Expected only 1 test module. Found {}".format(tests)) 83 self.suite.addTest(tests[0]) 84 85 86 def loadTestsFromNames(self, names: Sequence[str], module: str = None) -> unittest.TestSuite: 87 return self.suite 88 89if __name__ == "__main__": 90 91 if len(sys.argv) != 2: 92 print(f"USAGE: {sys.argv[0]} TARGET_MODULE", file=sys.stderr) 93 94 target_module = sys.argv[1] 95 96 loader = SingleLoader(target_module) 97 runner = unittest.TextTestRunner() 98 99 result = gevent.spawn(runner.run, loader.suite) 100 result.join() 101 if not result.value.wasSuccessful(): 102 sys.exit("Test failure.") 103