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