1*9e94795aSAndroid Build Coastguard Worker# Copyright 2024, The Android Open Source Project 2*9e94795aSAndroid Build Coastguard Worker# 3*9e94795aSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 4*9e94795aSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 5*9e94795aSAndroid Build Coastguard Worker# You may obtain a copy of the License at 6*9e94795aSAndroid Build Coastguard Worker# 7*9e94795aSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 8*9e94795aSAndroid Build Coastguard Worker# 9*9e94795aSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 10*9e94795aSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 11*9e94795aSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*9e94795aSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 13*9e94795aSAndroid Build Coastguard Worker# limitations under the License. 14*9e94795aSAndroid Build Coastguard Worker 15*9e94795aSAndroid Build Coastguard Worker"""Testing utilities for tests in the CI package.""" 16*9e94795aSAndroid Build Coastguard Worker 17*9e94795aSAndroid Build Coastguard Workerimport logging 18*9e94795aSAndroid Build Coastguard Workerimport os 19*9e94795aSAndroid Build Coastguard Workerimport unittest 20*9e94795aSAndroid Build Coastguard Workerimport subprocess 21*9e94795aSAndroid Build Coastguard Workerimport pathlib 22*9e94795aSAndroid Build Coastguard Workerimport shutil 23*9e94795aSAndroid Build Coastguard Workerimport tempfile 24*9e94795aSAndroid Build Coastguard Worker 25*9e94795aSAndroid Build Coastguard Worker 26*9e94795aSAndroid Build Coastguard Worker# Export the TestCase class to reduce the number of imports tests have to list. 27*9e94795aSAndroid Build Coastguard WorkerTestCase = unittest.TestCase 28*9e94795aSAndroid Build Coastguard Worker 29*9e94795aSAndroid Build Coastguard Worker 30*9e94795aSAndroid Build Coastguard Workerdef process_alive(pid): 31*9e94795aSAndroid Build Coastguard Worker """Check For the existence of a pid.""" 32*9e94795aSAndroid Build Coastguard Worker 33*9e94795aSAndroid Build Coastguard Worker try: 34*9e94795aSAndroid Build Coastguard Worker os.kill(pid, 0) 35*9e94795aSAndroid Build Coastguard Worker except OSError: 36*9e94795aSAndroid Build Coastguard Worker return False 37*9e94795aSAndroid Build Coastguard Worker 38*9e94795aSAndroid Build Coastguard Worker return True 39*9e94795aSAndroid Build Coastguard Worker 40*9e94795aSAndroid Build Coastguard Worker 41*9e94795aSAndroid Build Coastguard Workerclass TemporaryProcessSession: 42*9e94795aSAndroid Build Coastguard Worker 43*9e94795aSAndroid Build Coastguard Worker def __init__(self, test_case: TestCase): 44*9e94795aSAndroid Build Coastguard Worker self._created_processes = [] 45*9e94795aSAndroid Build Coastguard Worker test_case.addCleanup(self.cleanup) 46*9e94795aSAndroid Build Coastguard Worker 47*9e94795aSAndroid Build Coastguard Worker def create(self, args, kwargs): 48*9e94795aSAndroid Build Coastguard Worker p = subprocess.Popen(*args, **kwargs, start_new_session=True) 49*9e94795aSAndroid Build Coastguard Worker self._created_processes.append(p) 50*9e94795aSAndroid Build Coastguard Worker return p 51*9e94795aSAndroid Build Coastguard Worker 52*9e94795aSAndroid Build Coastguard Worker def cleanup(self): 53*9e94795aSAndroid Build Coastguard Worker for p in self._created_processes: 54*9e94795aSAndroid Build Coastguard Worker if not process_alive(p.pid): 55*9e94795aSAndroid Build Coastguard Worker return 56*9e94795aSAndroid Build Coastguard Worker os.killpg(os.getpgid(p.pid), signal.SIGKILL) 57*9e94795aSAndroid Build Coastguard Worker 58*9e94795aSAndroid Build Coastguard Worker 59*9e94795aSAndroid Build Coastguard Workerclass TestTemporaryDirectory: 60*9e94795aSAndroid Build Coastguard Worker 61*9e94795aSAndroid Build Coastguard Worker def __init__(self, delete: bool, ): 62*9e94795aSAndroid Build Coastguard Worker self._delete = delete 63*9e94795aSAndroid Build Coastguard Worker 64*9e94795aSAndroid Build Coastguard Worker @classmethod 65*9e94795aSAndroid Build Coastguard Worker def create(cls, test_case: TestCase, delete: bool = True): 66*9e94795aSAndroid Build Coastguard Worker temp_dir = TestTemporaryDirectory(delete) 67*9e94795aSAndroid Build Coastguard Worker temp_dir._dir = pathlib.Path(tempfile.mkdtemp()) 68*9e94795aSAndroid Build Coastguard Worker test_case.addCleanup(temp_dir.cleanup) 69*9e94795aSAndroid Build Coastguard Worker return temp_dir._dir 70*9e94795aSAndroid Build Coastguard Worker 71*9e94795aSAndroid Build Coastguard Worker def get_dir(self): 72*9e94795aSAndroid Build Coastguard Worker return self._dir 73*9e94795aSAndroid Build Coastguard Worker 74*9e94795aSAndroid Build Coastguard Worker def cleanup(self): 75*9e94795aSAndroid Build Coastguard Worker if not self._delete: 76*9e94795aSAndroid Build Coastguard Worker return 77*9e94795aSAndroid Build Coastguard Worker shutil.rmtree(self._dir, ignore_errors=True) 78*9e94795aSAndroid Build Coastguard Worker 79*9e94795aSAndroid Build Coastguard Worker 80*9e94795aSAndroid Build Coastguard Workerdef main(): 81*9e94795aSAndroid Build Coastguard Worker 82*9e94795aSAndroid Build Coastguard Worker # Disable logging since it breaks the TF Python test output parser. 83*9e94795aSAndroid Build Coastguard Worker # TODO(hzalek): Use TF's `test-output-file` option to re-enable logging. 84*9e94795aSAndroid Build Coastguard Worker logging.getLogger().disabled = True 85*9e94795aSAndroid Build Coastguard Worker 86*9e94795aSAndroid Build Coastguard Worker unittest.main() 87