• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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"""Unit tests for xvfb.py functionality.
6
7Each unit test is launching xvfb_test_script.py
8through xvfb.py as a subprocess, then tests its expected output.
9"""
10
11import os
12import signal
13import subprocess
14import sys
15import time
16import unittest
17
18# pylint: disable=super-with-arguments
19
20TEST_FILE = __file__.replace('.pyc', '.py')
21XVFB = TEST_FILE.replace('_unittest', '')
22XVFB_TEST_SCRIPT = TEST_FILE.replace('_unittest', '_test_script')
23
24
25def launch_process(args):
26  """Launches a sub process to run through xvfb.py."""
27  return subprocess.Popen([XVFB, XVFB_TEST_SCRIPT] + args,
28                          stdout=subprocess.PIPE,
29                          stderr=subprocess.STDOUT,
30                          env=os.environ.copy())
31
32
33# pylint: disable=inconsistent-return-statements
34def read_subprocess_message(proc, starts_with):
35  """Finds the value after first line prefix condition."""
36  for line in proc.stdout.read().decode('utf-8').splitlines(True):
37    if str(line).startswith(starts_with):
38      return line.rstrip().replace(starts_with, '')
39
40
41# pylint: enable=inconsistent-return-statements
42
43
44def send_signal(proc, sig, sleep_time=0.3):
45  """Sends a signal to subprocess."""
46  time.sleep(sleep_time)  # gives process time to launch.
47  os.kill(proc.pid, sig)
48  proc.wait()
49
50
51class XvfbLinuxTest(unittest.TestCase):
52
53  def setUp(self):
54    super(XvfbLinuxTest, self).setUp()
55    if not sys.platform.startswith('linux'):
56      self.skipTest('linux only test')
57    self._procs = []
58
59  def test_no_xvfb_display(self):
60    self._procs.append(launch_process(['--no-xvfb']))
61    self._procs[0].wait()
62    display = read_subprocess_message(self._procs[0], 'Display :')
63    self.assertEqual(display, os.environ.get('DISPLAY', 'None'))
64
65  def test_xvfb_display(self):
66    self._procs.append(launch_process([]))
67    self._procs[0].wait()
68    display = read_subprocess_message(self._procs[0], 'Display :')
69    self.assertIsNotNone(display)  # Openbox likely failed to open DISPLAY
70    self.assertNotEqual(display, os.environ.get('DISPLAY', 'None'))
71
72  def test_no_xvfb_flag(self):
73    self._procs.append(launch_process(['--no-xvfb']))
74    self._procs[0].wait()
75
76  def test_xvfb_flag(self):
77    self._procs.append(launch_process([]))
78    self._procs[0].wait()
79
80  @unittest.skip('flaky; crbug.com/1320399')
81  def test_xvfb_race_condition(self):
82    self._procs = [launch_process([]) for _ in range(15)]
83    for proc in self._procs:
84      proc.wait()
85    display_list = [
86        read_subprocess_message(p, 'Display :') for p in self._procs
87    ]
88    for display in display_list:
89      self.assertIsNotNone(display)  # Openbox likely failed to open DISPLAY
90      self.assertNotEqual(display, os.environ.get('DISPLAY', 'None'))
91
92  def tearDown(self):
93    super(XvfbLinuxTest, self).tearDown()
94    for proc in self._procs:
95      if proc.stdout:
96        proc.stdout.close()
97
98
99class XvfbTest(unittest.TestCase):
100
101  def setUp(self):
102    super(XvfbTest, self).setUp()
103    if sys.platform == 'win32':
104      self.skipTest('non-win32 test')
105    self._proc = None
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
130
131if __name__ == '__main__':
132  unittest.main()
133