1*6777b538SAndroid Build Coastguard Worker#!/usr/bin/env python3 2*6777b538SAndroid Build Coastguard Worker# Copyright 2019 The Chromium Authors 3*6777b538SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 4*6777b538SAndroid Build Coastguard Worker# found in the LICENSE file. 5*6777b538SAndroid Build Coastguard Worker 6*6777b538SAndroid Build Coastguard Worker"""Unit tests for test_env.py functionality. 7*6777b538SAndroid Build Coastguard Worker 8*6777b538SAndroid Build Coastguard WorkerEach unit test is launches python process that uses test_env.py 9*6777b538SAndroid Build Coastguard Workerto launch another python process. Then signal handling and 10*6777b538SAndroid Build Coastguard Workerpropagation is tested. This similates how Swarming uses test_env.py. 11*6777b538SAndroid Build Coastguard Worker""" 12*6777b538SAndroid Build Coastguard Worker 13*6777b538SAndroid Build Coastguard Workerimport os 14*6777b538SAndroid Build Coastguard Workerimport signal 15*6777b538SAndroid Build Coastguard Workerimport subprocess 16*6777b538SAndroid Build Coastguard Workerimport sys 17*6777b538SAndroid Build Coastguard Workerimport time 18*6777b538SAndroid Build Coastguard Workerimport unittest 19*6777b538SAndroid Build Coastguard Worker 20*6777b538SAndroid Build Coastguard WorkerHERE = os.path.dirname(os.path.abspath(__file__)) 21*6777b538SAndroid Build Coastguard WorkerTEST_SCRIPT = os.path.join(HERE, 'test_env_user_script.py') 22*6777b538SAndroid Build Coastguard Worker 23*6777b538SAndroid Build Coastguard Worker 24*6777b538SAndroid Build Coastguard Workerdef launch_process_windows(args): 25*6777b538SAndroid Build Coastguard Worker # The `universal_newlines` option is equivalent to `text` in Python 3. 26*6777b538SAndroid Build Coastguard Worker return subprocess.Popen( 27*6777b538SAndroid Build Coastguard Worker [sys.executable, TEST_SCRIPT] + args, 28*6777b538SAndroid Build Coastguard Worker stdout=subprocess.PIPE, 29*6777b538SAndroid Build Coastguard Worker stderr=subprocess.STDOUT, 30*6777b538SAndroid Build Coastguard Worker env=os.environ.copy(), 31*6777b538SAndroid Build Coastguard Worker creationflags=subprocess.CREATE_NEW_PROCESS_GROUP, 32*6777b538SAndroid Build Coastguard Worker universal_newlines=True) 33*6777b538SAndroid Build Coastguard Worker 34*6777b538SAndroid Build Coastguard Worker 35*6777b538SAndroid Build Coastguard Workerdef launch_process_nonwindows(args): 36*6777b538SAndroid Build Coastguard Worker # The `universal_newlines` option is equivalent to `text` in Python 3. 37*6777b538SAndroid Build Coastguard Worker return subprocess.Popen( 38*6777b538SAndroid Build Coastguard Worker [sys.executable, TEST_SCRIPT] + args, 39*6777b538SAndroid Build Coastguard Worker stdout=subprocess.PIPE, 40*6777b538SAndroid Build Coastguard Worker stderr=subprocess.STDOUT, 41*6777b538SAndroid Build Coastguard Worker env=os.environ.copy(), 42*6777b538SAndroid Build Coastguard Worker universal_newlines=True) 43*6777b538SAndroid Build Coastguard Worker 44*6777b538SAndroid Build Coastguard Worker 45*6777b538SAndroid Build Coastguard Worker# pylint: disable=inconsistent-return-statements 46*6777b538SAndroid Build Coastguard Workerdef read_subprocess_message(proc, starts_with): 47*6777b538SAndroid Build Coastguard Worker """Finds the value after first line prefix condition.""" 48*6777b538SAndroid Build Coastguard Worker for line in proc.stdout: 49*6777b538SAndroid Build Coastguard Worker if line.startswith(starts_with): 50*6777b538SAndroid Build Coastguard Worker return line.rstrip().replace(starts_with, '') 51*6777b538SAndroid Build Coastguard Worker# pylint: enable=inconsistent-return-statements 52*6777b538SAndroid Build Coastguard Worker 53*6777b538SAndroid Build Coastguard Worker 54*6777b538SAndroid Build Coastguard Workerdef send_and_wait(proc, sig, sleep_time=0.6): 55*6777b538SAndroid Build Coastguard Worker """Sends a signal to subprocess.""" 56*6777b538SAndroid Build Coastguard Worker time.sleep(sleep_time) # gives process time to launch. 57*6777b538SAndroid Build Coastguard Worker os.kill(proc.pid, sig) 58*6777b538SAndroid Build Coastguard Worker proc.wait() 59*6777b538SAndroid Build Coastguard Worker 60*6777b538SAndroid Build Coastguard Worker 61*6777b538SAndroid Build Coastguard Workerclass SignalingWindowsTest(unittest.TestCase): 62*6777b538SAndroid Build Coastguard Worker 63*6777b538SAndroid Build Coastguard Worker def setUp(self): 64*6777b538SAndroid Build Coastguard Worker super().setUp() 65*6777b538SAndroid Build Coastguard Worker if sys.platform != 'win32': 66*6777b538SAndroid Build Coastguard Worker self.skipTest('test only runs on Windows') 67*6777b538SAndroid Build Coastguard Worker 68*6777b538SAndroid Build Coastguard Worker def test_send_ctrl_break_event(self): 69*6777b538SAndroid Build Coastguard Worker proc = launch_process_windows([]) 70*6777b538SAndroid Build Coastguard Worker send_and_wait(proc, signal.CTRL_BREAK_EVENT) # pylint: disable=no-member 71*6777b538SAndroid Build Coastguard Worker sig = read_subprocess_message(proc, 'Signal :') 72*6777b538SAndroid Build Coastguard Worker # This test is flaky because it relies on the child process starting quickly 73*6777b538SAndroid Build Coastguard Worker # "enough", which it fails to do sometimes. This is tracked by 74*6777b538SAndroid Build Coastguard Worker # https://crbug.com/1335123 and it is hoped that increasing the timeout will 75*6777b538SAndroid Build Coastguard Worker # reduce the flakiness. 76*6777b538SAndroid Build Coastguard Worker self.assertEqual(sig, str(int(signal.SIGBREAK))) # pylint: disable=no-member 77*6777b538SAndroid Build Coastguard Worker 78*6777b538SAndroid Build Coastguard Worker 79*6777b538SAndroid Build Coastguard Workerclass SignalingNonWindowsTest(unittest.TestCase): 80*6777b538SAndroid Build Coastguard Worker 81*6777b538SAndroid Build Coastguard Worker def setUp(self): 82*6777b538SAndroid Build Coastguard Worker super().setUp() 83*6777b538SAndroid Build Coastguard Worker if sys.platform == 'win32': 84*6777b538SAndroid Build Coastguard Worker self.skipTest('test does not run on Windows') 85*6777b538SAndroid Build Coastguard Worker 86*6777b538SAndroid Build Coastguard Worker def test_send_sigterm(self): 87*6777b538SAndroid Build Coastguard Worker proc = launch_process_nonwindows([]) 88*6777b538SAndroid Build Coastguard Worker send_and_wait(proc, signal.SIGTERM) 89*6777b538SAndroid Build Coastguard Worker sig = read_subprocess_message(proc, 'Signal :') 90*6777b538SAndroid Build Coastguard Worker self.assertEqual(sig, str(int(signal.SIGTERM))) 91*6777b538SAndroid Build Coastguard Worker 92*6777b538SAndroid Build Coastguard Worker def test_send_sigint(self): 93*6777b538SAndroid Build Coastguard Worker proc = launch_process_nonwindows([]) 94*6777b538SAndroid Build Coastguard Worker send_and_wait(proc, signal.SIGINT) 95*6777b538SAndroid Build Coastguard Worker sig = read_subprocess_message(proc, 'Signal :') 96*6777b538SAndroid Build Coastguard Worker self.assertEqual(sig, str(int(signal.SIGINT))) 97*6777b538SAndroid Build Coastguard Worker 98*6777b538SAndroid Build Coastguard Worker 99*6777b538SAndroid Build Coastguard Workerif __name__ == '__main__': 100*6777b538SAndroid Build Coastguard Worker unittest.main() 101