blob: d92cf1ac4da06d4e232fc0c1a4a1ed3f13a22608 [file] [log] [blame]
Mike Frysingerf1ba7ad2022-09-12 05:42:57 -04001# Copyright 2020 The ChromiumOS Authors
Chris McDonald2e9a09c2020-04-03 16:09:32 -06002# 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:
Mike Frysinger43eb3ec2021-05-25 22:43:38 -04009https://docs.pytest.org/en/latest/explanation/fixtures.html
Chris McDonald2e9a09c2020-04-03 16:09:32 -060010"""
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
Mike Frysinger94cfdef2019-08-25 00:04:27 -040027#
Chris McDonaldee2fbda2020-04-30 18:10:01 -060028# 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
Alex Klein1699fab2022-09-08 08:46:06 -060035@pytest.fixture(scope="class", autouse=True)
Chris McDonald2e9a09c2020-04-03 16:09:32 -060036def mock_cidb_connection():
Alex Klein1699fab2022-09-08 08:46:06 -060037 """Ensure that the CIDB connection factory is initialized as a mock.
Chris McDonald2e9a09c2020-04-03 16:09:32 -060038
Alex Klein1699fab2022-09-08 08:46:06 -060039 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.
Chris McDonald2e9a09c2020-04-03 16:09:32 -060041
Alex Klein1699fab2022-09-08 08:46:06 -060042 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 """
46 # pylint: disable=protected-access
47 cidb.CIDBConnectionFactory._ClearCIDBSetup()
48 cidb.CIDBConnectionFactory.SetupMockCidb()
Chris McDonaldffe2a412020-04-15 02:27:25 -060049
50
Alex Klein1699fab2022-09-08 08:46:06 -060051@pytest.fixture(scope="class", autouse=True)
Chris McDonaldffe2a412020-04-15 02:27:25 -060052def assert_no_zombies():
Alex Klein1699fab2022-09-08 08:46:06 -060053 """Assert that tests have no active child processes after completion.
Chris McDonaldffe2a412020-04-15 02:27:25 -060054
Alex Kleina248dc02023-04-04 15:49:13 -060055 This assertion runs after class tearDown methods because of the
56 scope='class' declaration.
Alex Klein1699fab2022-09-08 08:46:06 -060057 """
58 yield
59 children = multiprocessing.active_children()
60 if children:
61 pytest.fail(
62 "Test has %s active child processes after tearDown: %s"
63 % (len(children), children)
64 )
Chris McDonalde13f0242020-04-07 18:37:15 -060065
66
Alex Klein1699fab2022-09-08 08:46:06 -060067@pytest.fixture(scope="class", autouse=True)
Chris McDonald6ce00962020-04-14 04:05:21 -060068def clear_retry_stats_manager():
Alex Klein1699fab2022-09-08 08:46:06 -060069 """Reset the global state of the stats manager before every test.
Chris McDonald6ce00962020-04-14 04:05:21 -060070
Alex Klein1699fab2022-09-08 08:46:06 -060071 Without this fixture many tests fail due to this global value being set and
72 then not cleared. The child manager process may have been killed but this
73 module level variable is still pointing at it, leading to the test trying to
74 write to a closed pipe.
75 """
76 # pylint: disable=protected-access
77 retry_stats._STATS_COLLECTION = None
78
Chris McDonald6ce00962020-04-14 04:05:21 -060079
Chris McDonald3e1ef0a2020-10-16 13:13:13 -060080@pytest.fixture(autouse=True)
81def set_testing_environment_variable(monkeypatch):
Alex Kleina248dc02023-04-04 15:49:13 -060082 """Set environment marker to relax certain strict checks for test code."""
Alex Klein1699fab2022-09-08 08:46:06 -060083 monkeypatch.setenv("CHROMITE_INSIDE_PYTEST", "1")
84
Chris McDonald6ce00962020-04-14 04:05:21 -060085
Chris McDonalde13f0242020-04-07 18:37:15 -060086@pytest.fixture
Chris McDonald320ef422020-04-18 04:57:04 -060087def singleton_manager(monkeypatch):
Alex Klein1699fab2022-09-08 08:46:06 -060088 """Force tests to use a singleton Manager and automatically clean it up."""
89 m = parallel.Manager()
Chris McDonald320ef422020-04-18 04:57:04 -060090
Alex Klein1699fab2022-09-08 08:46:06 -060091 def our_manager():
92 return m
Chris McDonald320ef422020-04-18 04:57:04 -060093
Alex Klein1699fab2022-09-08 08:46:06 -060094 monkeypatch.setattr(parallel, "Manager", our_manager)
95 yield
96 m.shutdown()
Chris McDonald320ef422020-04-18 04:57:04 -060097
98
99@pytest.fixture
Chris McDonalde13f0242020-04-07 18:37:15 -0600100def legacy_capture_output(request, capfd):
Alex Klein1699fab2022-09-08 08:46:06 -0600101 """Adds the `capfd` fixture to TestCase-style test classes.
Chris McDonalde13f0242020-04-07 18:37:15 -0600102
Alex Kleina248dc02023-04-04 15:49:13 -0600103 This fixture should only be used on cros_test_lib.TestCase test classes,
104 since it doesn't yield anything and just attaches the built-in pytest
105 `capfd` fixture to the requesting class. Tests written as standalone
106 functions should use pytest's built-in `capfd` fixture instead of this. See
107 the documentation for more information on how to use the `capfd` fixture
108 that this provides:
Alex Klein1699fab2022-09-08 08:46:06 -0600109 https://docs.pytest.org/en/latest/reference/reference.html#std-fixture-capfd
Chris McDonalde13f0242020-04-07 18:37:15 -0600110
Alex Kleina248dc02023-04-04 15:49:13 -0600111 See the following documentation for an explanation of why fixtures have to
112 be provided to TestCase classes in this manner:
Alex Klein1699fab2022-09-08 08:46:06 -0600113 https://docs.pytest.org/en/latest/how-to/unittest.html#mixing-pytest-fixtures-into-unittest-testcase-subclasses-using-marks
114 """
115 request.cls.capfd = capfd
Chris McDonald6ce00962020-04-14 04:05:21 -0600116
117
118@pytest.fixture
119def testcase_caplog(request, caplog):
Alex Klein1699fab2022-09-08 08:46:06 -0600120 """Adds the `caplog` fixture to TestCase-style test classes.
Chris McDonald6ce00962020-04-14 04:05:21 -0600121
Alex Kleina248dc02023-04-04 15:49:13 -0600122 This fixture should only be used on cros_test_lib.TestCase test classes,
123 since it doesn't yield anything and just attaches the built-in pytest
124 `caplog` fixture to the requesting class. Tests written as standalone
125 functions should use pytest's built-in `caplog` fixture instead of this. See
126 the documentation for more information on how to use the `caplog` fixture
127 that this provides:
Alex Klein1699fab2022-09-08 08:46:06 -0600128 https://docs.pytest.org/en/latest/reference/reference.html#caplog
Chris McDonald6ce00962020-04-14 04:05:21 -0600129
Alex Kleina248dc02023-04-04 15:49:13 -0600130 See the following documentation for an explanation of why fixtures have to
131 be provided to TestCase classes in this manner:
Alex Klein1699fab2022-09-08 08:46:06 -0600132 https://docs.pytest.org/en/latest/how-to/unittest.html#mixing-pytest-fixtures-into-unittest-testcase-subclasses-using-marks
133 """
134 request.cls.caplog = caplog
Chris McDonald05511c92020-05-01 16:45:56 -0600135
136
Michael Mortensende716a12020-05-15 11:27:00 -0600137@pytest.fixture
138def testcase_monkeypatch(request, monkeypatch):
Alex Klein1699fab2022-09-08 08:46:06 -0600139 """Adds the `monkeypatch` fixture to TestCase-style test classes.
Michael Mortensende716a12020-05-15 11:27:00 -0600140
Alex Kleina248dc02023-04-04 15:49:13 -0600141 This fixture should only be used on cros_test_lib.TestCase test classes,
142 since it doesn't yield anything and just attaches the built-in pytest
143 `monkeypatch` fixture to the requesting class. Tests written as standalone
144 functions should use pytest's built-in `monkeypatch` fixture instead of
145 this. See the documentation for more information on how to use the
146 `monkeypatch` fixture that this provides:
Alex Klein1699fab2022-09-08 08:46:06 -0600147 https://docs.pytest.org/en/latest/reference/reference.html#monkeypatch
Michael Mortensende716a12020-05-15 11:27:00 -0600148
Alex Kleina248dc02023-04-04 15:49:13 -0600149 See the following documentation for an explanation of why fixtures have to
150 be provided to TestCase classes in this manner:
Alex Klein1699fab2022-09-08 08:46:06 -0600151 https://docs.pytest.org/en/latest/how-to/unittest.html#mixing-pytest-fixtures-into-unittest-testcase-subclasses-using-marks
152 """
153 request.cls.monkeypatch = monkeypatch
Michael Mortensende716a12020-05-15 11:27:00 -0600154
155
Chris McDonald05511c92020-05-01 16:45:56 -0600156def pytest_assertrepr_compare(op, left, right):
Alex Klein1699fab2022-09-08 08:46:06 -0600157 """Global hook for defining detailed explanations for failed assertions.
Chris McDonald05511c92020-05-01 16:45:56 -0600158
Alex Klein1699fab2022-09-08 08:46:06 -0600159 https://docs.pytest.org/en/latest/how-to/assert.html
160 """
161 if (
162 isinstance(left, package_info.CPV)
163 and isinstance(right, cr.test.Overlay)
164 and op == "in"
165 ):
166 package_path = right.path / left.category / left.package
167 return [
168 f"{left.pv}.ebuild exists in {right.path}",
169 "Ebuild does not exist in overlay.",
170 "Ebuilds found in overlay with same category and package:",
171 ] + sorted(
172 "\t" + str(p.relative_to(package_path))
173 for p in package_path.glob("*.ebuild")
174 )
Chris McDonaldcdfd1132020-05-12 07:09:51 -0600175
176
177def pytest_addoption(parser):
Alex Klein1699fab2022-09-08 08:46:06 -0600178 """Adds additional options to the default pytest CLI args."""
179 parser.addoption(
180 "--no-chroot",
181 dest="chroot",
182 action="store_false",
183 help="Skip any tests that require a chroot to function.",
184 )
Chris McDonaldcdfd1132020-05-12 07:09:51 -0600185
186
187def pytest_collection_modifyitems(config, items):
Alex Klein1699fab2022-09-08 08:46:06 -0600188 """Modifies the list of test items pytest has collected.
Chris McDonaldcdfd1132020-05-12 07:09:51 -0600189
Alex Klein1699fab2022-09-08 08:46:06 -0600190 See the following link for full documentation on pytest collection hooks:
191 https://docs.pytest.org/en/latest/reference/reference.html#collection-hooks
192 """
193 if config.option.chroot:
194 return
195 skip_inside_only = pytest.mark.skip(reason="Test requires a chroot to run.")
196 for item in items:
197 if "inside_only" in item.keywords:
198 item.add_marker(skip_inside_only)
Mike Frysinger3f058842023-07-09 00:34:07 -0400199
200
201@pytest.fixture
202def run_mock():
203 """Robust mock for cros_build_lib.run."""
204 from chromite.lib import cros_test_lib
205
206 with cros_test_lib.RunCommandMock() as rc_mock:
207 rc_mock.SetDefaultCmdResult()
208 yield rc_mock