1*6777b538SAndroid Build Coastguard Worker#!/usr/bin/env python 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 xvfb.py functionality. 7*6777b538SAndroid Build Coastguard Worker 8*6777b538SAndroid Build Coastguard WorkerEach unit test is launching xvfb_test_script.py 9*6777b538SAndroid Build Coastguard Workerthrough xvfb.py as a subprocess, then tests its expected output. 10*6777b538SAndroid Build Coastguard Worker""" 11*6777b538SAndroid Build Coastguard Worker 12*6777b538SAndroid Build Coastguard Workerimport os 13*6777b538SAndroid Build Coastguard Workerimport signal 14*6777b538SAndroid Build Coastguard Workerimport subprocess 15*6777b538SAndroid Build Coastguard Workerimport sys 16*6777b538SAndroid Build Coastguard Workerimport time 17*6777b538SAndroid Build Coastguard Workerimport unittest 18*6777b538SAndroid Build Coastguard Worker 19*6777b538SAndroid Build Coastguard Worker# pylint: disable=super-with-arguments 20*6777b538SAndroid Build Coastguard Worker 21*6777b538SAndroid Build Coastguard Worker 22*6777b538SAndroid Build Coastguard WorkerTEST_FILE = __file__.replace('.pyc', '.py') 23*6777b538SAndroid Build Coastguard WorkerXVFB = TEST_FILE.replace('_unittest', '') 24*6777b538SAndroid Build Coastguard WorkerXVFB_TEST_SCRIPT = TEST_FILE.replace('_unittest', '_test_script') 25*6777b538SAndroid Build Coastguard Worker 26*6777b538SAndroid Build Coastguard Worker 27*6777b538SAndroid Build Coastguard Workerdef launch_process(args): 28*6777b538SAndroid Build Coastguard Worker """Launches a sub process to run through xvfb.py.""" 29*6777b538SAndroid Build Coastguard Worker return subprocess.Popen( 30*6777b538SAndroid Build Coastguard Worker [XVFB, XVFB_TEST_SCRIPT] + args, stdout=subprocess.PIPE, 31*6777b538SAndroid Build Coastguard Worker stderr=subprocess.STDOUT, env=os.environ.copy()) 32*6777b538SAndroid Build Coastguard Worker 33*6777b538SAndroid Build Coastguard Worker 34*6777b538SAndroid Build Coastguard Worker# pylint: disable=inconsistent-return-statements 35*6777b538SAndroid Build Coastguard Workerdef read_subprocess_message(proc, starts_with): 36*6777b538SAndroid Build Coastguard Worker """Finds the value after first line prefix condition.""" 37*6777b538SAndroid Build Coastguard Worker for line in proc.stdout.read().decode('utf-8').splitlines(True): 38*6777b538SAndroid Build Coastguard Worker if str(line).startswith(starts_with): 39*6777b538SAndroid Build Coastguard Worker return line.rstrip().replace(starts_with, '') 40*6777b538SAndroid Build Coastguard Worker# pylint: enable=inconsistent-return-statements 41*6777b538SAndroid Build Coastguard Worker 42*6777b538SAndroid Build Coastguard Worker 43*6777b538SAndroid Build Coastguard Workerdef send_signal(proc, sig, sleep_time=0.3): 44*6777b538SAndroid Build Coastguard Worker """Sends a signal to subprocess.""" 45*6777b538SAndroid Build Coastguard Worker time.sleep(sleep_time) # gives process time to launch. 46*6777b538SAndroid Build Coastguard Worker os.kill(proc.pid, sig) 47*6777b538SAndroid Build Coastguard Worker proc.wait() 48*6777b538SAndroid Build Coastguard Worker 49*6777b538SAndroid Build Coastguard Worker 50*6777b538SAndroid Build Coastguard Workerclass XvfbLinuxTest(unittest.TestCase): 51*6777b538SAndroid Build Coastguard Worker 52*6777b538SAndroid Build Coastguard Worker def setUp(self): 53*6777b538SAndroid Build Coastguard Worker super(XvfbLinuxTest, self).setUp() 54*6777b538SAndroid Build Coastguard Worker if not sys.platform.startswith('linux'): 55*6777b538SAndroid Build Coastguard Worker self.skipTest('linux only test') 56*6777b538SAndroid Build Coastguard Worker self._procs = [] 57*6777b538SAndroid Build Coastguard Worker 58*6777b538SAndroid Build Coastguard Worker def test_no_xvfb_display(self): 59*6777b538SAndroid Build Coastguard Worker self._procs.append(launch_process(['--no-xvfb'])) 60*6777b538SAndroid Build Coastguard Worker self._procs[0].wait() 61*6777b538SAndroid Build Coastguard Worker display = read_subprocess_message(self._procs[0], 'Display :') 62*6777b538SAndroid Build Coastguard Worker self.assertEqual(display, os.environ.get('DISPLAY', 'None')) 63*6777b538SAndroid Build Coastguard Worker 64*6777b538SAndroid Build Coastguard Worker def test_xvfb_display(self): 65*6777b538SAndroid Build Coastguard Worker self._procs.append(launch_process([])) 66*6777b538SAndroid Build Coastguard Worker self._procs[0].wait() 67*6777b538SAndroid Build Coastguard Worker display = read_subprocess_message(self._procs[0], 'Display :') 68*6777b538SAndroid Build Coastguard Worker self.assertIsNotNone(display) # Openbox likely failed to open DISPLAY 69*6777b538SAndroid Build Coastguard Worker self.assertNotEqual(display, os.environ.get('DISPLAY', 'None')) 70*6777b538SAndroid Build Coastguard Worker 71*6777b538SAndroid Build Coastguard Worker def test_no_xvfb_flag(self): 72*6777b538SAndroid Build Coastguard Worker self._procs.append(launch_process(['--no-xvfb'])) 73*6777b538SAndroid Build Coastguard Worker self._procs[0].wait() 74*6777b538SAndroid Build Coastguard Worker 75*6777b538SAndroid Build Coastguard Worker def test_xvfb_flag(self): 76*6777b538SAndroid Build Coastguard Worker self._procs.append(launch_process([])) 77*6777b538SAndroid Build Coastguard Worker self._procs[0].wait() 78*6777b538SAndroid Build Coastguard Worker 79*6777b538SAndroid Build Coastguard Worker @unittest.skip("flaky; crbug.com/1320399") 80*6777b538SAndroid Build Coastguard Worker def test_xvfb_race_condition(self): 81*6777b538SAndroid Build Coastguard Worker self._procs = [launch_process([]) for _ in range(15)] 82*6777b538SAndroid Build Coastguard Worker for proc in self._procs: 83*6777b538SAndroid Build Coastguard Worker proc.wait() 84*6777b538SAndroid Build Coastguard Worker display_list = [read_subprocess_message(p, 'Display :') 85*6777b538SAndroid Build Coastguard Worker for p in self._procs] 86*6777b538SAndroid Build Coastguard Worker for display in display_list: 87*6777b538SAndroid Build Coastguard Worker self.assertIsNotNone(display) # Openbox likely failed to open DISPLAY 88*6777b538SAndroid Build Coastguard Worker self.assertNotEqual(display, os.environ.get('DISPLAY', 'None')) 89*6777b538SAndroid Build Coastguard Worker 90*6777b538SAndroid Build Coastguard Worker def tearDown(self): 91*6777b538SAndroid Build Coastguard Worker super(XvfbLinuxTest, self).tearDown() 92*6777b538SAndroid Build Coastguard Worker for proc in self._procs: 93*6777b538SAndroid Build Coastguard Worker if proc.stdout: 94*6777b538SAndroid Build Coastguard Worker proc.stdout.close() 95*6777b538SAndroid Build Coastguard Worker 96*6777b538SAndroid Build Coastguard Worker 97*6777b538SAndroid Build Coastguard Worker 98*6777b538SAndroid Build Coastguard Workerclass XvfbTest(unittest.TestCase): 99*6777b538SAndroid Build Coastguard Worker 100*6777b538SAndroid Build Coastguard Worker def setUp(self): 101*6777b538SAndroid Build Coastguard Worker super(XvfbTest, self).setUp() 102*6777b538SAndroid Build Coastguard Worker if sys.platform == 'win32': 103*6777b538SAndroid Build Coastguard Worker self.skipTest('non-win32 test') 104*6777b538SAndroid Build Coastguard Worker self._proc = None 105*6777b538SAndroid Build Coastguard Worker 106*6777b538SAndroid Build Coastguard Worker 107*6777b538SAndroid Build Coastguard Worker def test_send_sigint(self): 108*6777b538SAndroid Build Coastguard Worker self._proc = launch_process(['--sleep']) 109*6777b538SAndroid Build Coastguard Worker # Give time for subprocess to install signal handlers 110*6777b538SAndroid Build Coastguard Worker time.sleep(.3) 111*6777b538SAndroid Build Coastguard Worker send_signal(self._proc, signal.SIGINT, 1) 112*6777b538SAndroid Build Coastguard Worker sig = read_subprocess_message(self._proc, 'Signal :') 113*6777b538SAndroid Build Coastguard Worker self.assertIsNotNone(sig) # OpenBox likely failed to start 114*6777b538SAndroid Build Coastguard Worker self.assertEqual(int(sig), int(signal.SIGINT)) 115*6777b538SAndroid Build Coastguard Worker 116*6777b538SAndroid Build Coastguard Worker def test_send_sigterm(self): 117*6777b538SAndroid Build Coastguard Worker self._proc = launch_process(['--sleep']) 118*6777b538SAndroid Build Coastguard Worker # Give time for subprocess to install signal handlers 119*6777b538SAndroid Build Coastguard Worker time.sleep(.3) 120*6777b538SAndroid Build Coastguard Worker send_signal(self._proc, signal.SIGTERM, 1) 121*6777b538SAndroid Build Coastguard Worker sig = read_subprocess_message(self._proc, 'Signal :') 122*6777b538SAndroid Build Coastguard Worker self.assertIsNotNone(sig) # OpenBox likely failed to start 123*6777b538SAndroid Build Coastguard Worker self.assertEqual(int(sig), int(signal.SIGTERM)) 124*6777b538SAndroid Build Coastguard Worker 125*6777b538SAndroid Build Coastguard Worker def tearDown(self): 126*6777b538SAndroid Build Coastguard Worker super(XvfbTest, self).tearDown() 127*6777b538SAndroid Build Coastguard Worker if self._proc.stdout: 128*6777b538SAndroid Build Coastguard Worker self._proc.stdout.close() 129*6777b538SAndroid Build Coastguard Worker 130*6777b538SAndroid Build Coastguard Workerif __name__ == '__main__': 131*6777b538SAndroid Build Coastguard Worker unittest.main() 132