blob: 7cfe28edc74cfcd9cf2ea62c6ffcd512802e19ff [file] [log] [blame]
Chris McDonald2e9a09c2020-04-03 16:09:32 -06001# Copyright 2020 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Configuration and fixtures for pytest.
6
7See the following doc link for an explanation of conftest.py and how it is used
8by pytest:
9https://docs.pytest.org/en/latest/fixture.html#conftest-py-sharing-fixture-functions
10"""
11
Chris McDonald05511c92020-05-01 16:45:56 -060012from __future__ import division
Chris McDonald2e9a09c2020-04-03 16:09:32 -060013
Chris McDonaldffe2a412020-04-15 02:27:25 -060014import multiprocessing
15
Chris McDonaldee2fbda2020-04-30 18:10:01 -060016import pytest
Chris McDonald2e9a09c2020-04-03 16:09:32 -060017
Chris McDonald05511c92020-05-01 16:45:56 -060018import chromite as cr
Chris McDonald2e9a09c2020-04-03 16:09:32 -060019from chromite.lib import cidb
Chris McDonald320ef422020-04-18 04:57:04 -060020from chromite.lib import parallel
Chris McDonald6ce00962020-04-14 04:05:21 -060021from chromite.lib import retry_stats
Alex Klein75df1792020-06-11 14:42:49 -060022from chromite.lib.parser import package_info
Chris McDonald2e9a09c2020-04-03 16:09:32 -060023
Chris McDonaldee2fbda2020-04-30 18:10:01 -060024# We use wildcard imports here to make fixtures defined in the test module
25# globally visible.
26# pylint: disable=unused-wildcard-import, wildcard-import
27
28# Importing from *_fixtures.py files into conftest.py is the only time a
29# module should use a wildcard import. *_fixtures.py files should ensure
30# that the only items visible to a wildcard import are pytest fixtures,
31# usually by declaring __all__ if necessary.
32from chromite.test.portage_fixtures import *
33
Chris McDonald2e9a09c2020-04-03 16:09:32 -060034
Chris McDonalde53dde12020-04-07 13:43:14 -060035@pytest.fixture(scope='class', autouse=True)
Chris McDonald2e9a09c2020-04-03 16:09:32 -060036def mock_cidb_connection():
37 """Ensure that the CIDB connection factory is initialized as a mock.
38
39 Unit tests should never connect to any live instances of CIDB and this
40 initialization ensures that they only ever get a mock connection instance.
41
42 Previously cros_test_lib.TestProgram.runTests was responsible for globally
43 initializing this mock and multiple tests are flaky if this mock connection
44 is not initialized before any tests are run.
45 """
Chris McDonalde53dde12020-04-07 13:43:14 -060046 # pylint: disable=protected-access
47 cidb.CIDBConnectionFactory._ClearCIDBSetup()
Chris McDonald2e9a09c2020-04-03 16:09:32 -060048 cidb.CIDBConnectionFactory.SetupMockCidb()
Chris McDonaldffe2a412020-04-15 02:27:25 -060049
50
51@pytest.fixture(scope='class', autouse=True)
52def assert_no_zombies():
53 """Assert that tests have no active child processes after completion.
54
55 This assertion runs after class tearDown methods because of the scope='class'
56 declaration.
57 """
58 yield
59 children = multiprocessing.active_children()
60 if children:
61 pytest.fail('Test has %s active child processes after tearDown: %s' %
62 (len(children), children))
Chris McDonalde13f0242020-04-07 18:37:15 -060063
64
Chris McDonald6ce00962020-04-14 04:05:21 -060065@pytest.fixture(scope='class', autouse=True)
66def clear_retry_stats_manager():
67 """Reset the global state of the stats manager before every test.
68
69 Without this fixture many tests fail due to this global value being set and
70 then not cleared. The child manager process may have been killed but this
71 module level variable is still pointing at it, leading to the test trying to
72 write to a closed pipe.
73 """
74 # pylint: disable=protected-access
75 retry_stats._STATS_COLLECTION = None
76
Chris McDonald3e1ef0a2020-10-16 13:13:13 -060077@pytest.fixture(autouse=True)
78def set_testing_environment_variable(monkeypatch):
79 """Set an environment marker to relax certain strict checks for test code."""
80 monkeypatch.setenv('CHROMITE_INSIDE_PYTEST', '1')
Chris McDonald6ce00962020-04-14 04:05:21 -060081
Chris McDonalde13f0242020-04-07 18:37:15 -060082@pytest.fixture
Chris McDonald320ef422020-04-18 04:57:04 -060083def singleton_manager(monkeypatch):
84 """Force tests to use a singleton Manager and automatically clean it up."""
85 m = parallel.Manager()
86
87 def our_manager():
88 return m
89
90 monkeypatch.setattr(parallel, 'Manager', our_manager)
91 yield
92 m.shutdown()
93
94
95@pytest.fixture
Chris McDonalde13f0242020-04-07 18:37:15 -060096def legacy_capture_output(request, capfd):
97 """Adds the `capfd` fixture to TestCase-style test classes.
98
99 This fixture should only be used on cros_test_lib.TestCase test classes, since
100 it doesn't yield anything and just attaches the built-in pytest `capfd`
101 fixture to the requesting class. Tests written as standalone functions should
102 use pytest's built-in `capfd` fixture instead of this. See the documentation
103 for more information on how to use the `capfd` fixture that this provides:
104 https://docs.pytest.org/en/latest/reference.html#capfd
105
106 See the following documentation for an explanation of why fixtures have to be
107 provided to TestCase classes in this manner:
108 https://docs.pytest.org/en/latest/unittest.html#mixing-pytest-fixtures-into-unittest-testcase-subclasses-using-marks
109 """
110 request.cls.capfd = capfd
Chris McDonald6ce00962020-04-14 04:05:21 -0600111
112
113@pytest.fixture
114def testcase_caplog(request, caplog):
115 """Adds the `caplog` fixture to TestCase-style test classes.
116
117 This fixture should only be used on cros_test_lib.TestCase test classes, since
118 it doesn't yield anything and just attaches the built-in pytest `caplog`
119 fixture to the requesting class. Tests written as standalone functions should
120 use pytest's built-in `caplog` fixture instead of this. See the documentation
121 for more information on how to use the `caplog` fixture that this provides:
122 https://docs.pytest.org/en/latest/reference.html#caplog
123
124 See the following documentation for an explanation of why fixtures have to be
125 provided to TestCase classes in this manner:
126 https://docs.pytest.org/en/latest/unittest.html#mixing-pytest-fixtures-into-unittest-testcase-subclasses-using-marks
127 """
128 request.cls.caplog = caplog
Chris McDonald05511c92020-05-01 16:45:56 -0600129
130
Michael Mortensende716a12020-05-15 11:27:00 -0600131@pytest.fixture
132def testcase_monkeypatch(request, monkeypatch):
133 """Adds the `monkeypatch` fixture to TestCase-style test classes.
134
135 This fixture should only be used on cros_test_lib.TestCase test classes, since
136 it doesn't yield anything and just attaches the built-in pytest `monkeypatch`
137 fixture to the requesting class. Tests written as standalone functions should
138 use pytest's built-in `monkeypatch` fixture instead of this. See the
139 documentation for more information on how to use the `monkeypatch` fixture
140 that this provides:
141 https://docs.pytest.org/en/latest/reference.html#monkeypatch
142
143 See the following documentation for an explanation of why fixtures have to be
144 provided to TestCase classes in this manner:
145 https://docs.pytest.org/en/latest/unittest.html#mixing-pytest-fixtures-into-unittest-testcase-subclasses-using-marks
146 """
147 request.cls.monkeypatch = monkeypatch
148
149
Chris McDonald05511c92020-05-01 16:45:56 -0600150def pytest_assertrepr_compare(op, left, right):
151 """Global hook for defining detailed explanations for failed assertions.
152
153 https://docs.pytest.org/en/latest/assert.html#defining-your-own-explanation-for-failed-assertions
154 """
Alex Klein75df1792020-06-11 14:42:49 -0600155 if isinstance(left, package_info.CPV) and isinstance(
Chris McDonald05511c92020-05-01 16:45:56 -0600156 right, cr.test.Overlay) and op == 'in':
157 package_path = right.path / left.category / left.package
158 return [
159 f'{left.pv}.ebuild exists in {right.path}',
160 'Ebuild does not exist in overlay.',
161 'Ebuilds found in overlay with same category and package:'
162 ] + sorted('\t' + str(p.relative_to(package_path))
163 for p in package_path.glob('*.ebuild'))
Chris McDonaldcdfd1132020-05-12 07:09:51 -0600164
165
166def pytest_addoption(parser):
167 """Adds additional options to the default pytest CLI args."""
168 parser.addoption(
169 '--no-chroot',
170 dest='chroot',
171 action='store_false',
172 help='Skip any tests that require a chroot to function.',
173 )
174
175
176def pytest_collection_modifyitems(config, items):
177 """Modifies the list of test items pytest has collected.
178
179 See the following link for full documentation on pytest collection hooks:
180 https://docs.pytest.org/en/latest/reference.html?highlight=pytest_collection_modifyitems#collection-hooks
181 """
182 if config.option.chroot:
183 return
184 skip_inside_only = pytest.mark.skip(reason='Test requires a chroot to run.')
185 for item in items:
186 if 'inside_only' in item.keywords:
187 item.add_marker(skip_inside_only)