blob: f5ae5a8bc8df2eab733943c1fcc73cc317f6bda2 [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
Mike Frysingerf134dc22023-07-11 23:19:50 -040020from chromite.lib import cros_test_lib
Chris McDonald320ef422020-04-18 04:57:04 -060021from chromite.lib import parallel
Chris McDonald6ce00962020-04-14 04:05:21 -060022from chromite.lib import retry_stats
Alex Klein75df1792020-06-11 14:42:49 -060023from chromite.lib.parser import package_info
Chris McDonald2e9a09c2020-04-03 16:09:32 -060024
Chris McDonaldee2fbda2020-04-30 18:10:01 -060025# We use wildcard imports here to make fixtures defined in the test module
26# globally visible.
27# pylint: disable=unused-wildcard-import, wildcard-import
Mike Frysinger94cfdef2019-08-25 00:04:27 -040028#
Chris McDonaldee2fbda2020-04-30 18:10:01 -060029# Importing from *_fixtures.py files into conftest.py is the only time a
30# module should use a wildcard import. *_fixtures.py files should ensure
31# that the only items visible to a wildcard import are pytest fixtures,
32# usually by declaring __all__ if necessary.
33from chromite.test.portage_fixtures import *
34
Chris McDonald2e9a09c2020-04-03 16:09:32 -060035
Alex Klein1699fab2022-09-08 08:46:06 -060036@pytest.fixture(scope="class", autouse=True)
Chris McDonald2e9a09c2020-04-03 16:09:32 -060037def mock_cidb_connection():
Alex Klein1699fab2022-09-08 08:46:06 -060038 """Ensure that the CIDB connection factory is initialized as a mock.
Chris McDonald2e9a09c2020-04-03 16:09:32 -060039
Alex Klein1699fab2022-09-08 08:46:06 -060040 Unit tests should never connect to any live instances of CIDB and this
41 initialization ensures that they only ever get a mock connection instance.
Chris McDonald2e9a09c2020-04-03 16:09:32 -060042
Alex Klein1699fab2022-09-08 08:46:06 -060043 Previously cros_test_lib.TestProgram.runTests was responsible for globally
44 initializing this mock and multiple tests are flaky if this mock connection
45 is not initialized before any tests are run.
46 """
47 # pylint: disable=protected-access
48 cidb.CIDBConnectionFactory._ClearCIDBSetup()
49 cidb.CIDBConnectionFactory.SetupMockCidb()
Chris McDonaldffe2a412020-04-15 02:27:25 -060050
51
Alex Klein1699fab2022-09-08 08:46:06 -060052@pytest.fixture(scope="class", autouse=True)
Chris McDonaldffe2a412020-04-15 02:27:25 -060053def assert_no_zombies():
Alex Klein1699fab2022-09-08 08:46:06 -060054 """Assert that tests have no active child processes after completion.
Chris McDonaldffe2a412020-04-15 02:27:25 -060055
Alex Kleina248dc02023-04-04 15:49:13 -060056 This assertion runs after class tearDown methods because of the
57 scope='class' declaration.
Alex Klein1699fab2022-09-08 08:46:06 -060058 """
59 yield
60 children = multiprocessing.active_children()
61 if children:
62 pytest.fail(
63 "Test has %s active child processes after tearDown: %s"
64 % (len(children), children)
65 )
Chris McDonalde13f0242020-04-07 18:37:15 -060066
67
Alex Klein1699fab2022-09-08 08:46:06 -060068@pytest.fixture(scope="class", autouse=True)
Chris McDonald6ce00962020-04-14 04:05:21 -060069def clear_retry_stats_manager():
Alex Klein1699fab2022-09-08 08:46:06 -060070 """Reset the global state of the stats manager before every test.
Chris McDonald6ce00962020-04-14 04:05:21 -060071
Alex Klein1699fab2022-09-08 08:46:06 -060072 Without this fixture many tests fail due to this global value being set and
73 then not cleared. The child manager process may have been killed but this
74 module level variable is still pointing at it, leading to the test trying to
75 write to a closed pipe.
76 """
77 # pylint: disable=protected-access
78 retry_stats._STATS_COLLECTION = None
79
Chris McDonald6ce00962020-04-14 04:05:21 -060080
Chris McDonald3e1ef0a2020-10-16 13:13:13 -060081@pytest.fixture(autouse=True)
82def set_testing_environment_variable(monkeypatch):
Alex Kleina248dc02023-04-04 15:49:13 -060083 """Set environment marker to relax certain strict checks for test code."""
Alex Klein1699fab2022-09-08 08:46:06 -060084 monkeypatch.setenv("CHROMITE_INSIDE_PYTEST", "1")
85
Chris McDonald6ce00962020-04-14 04:05:21 -060086
Chris McDonalde13f0242020-04-07 18:37:15 -060087@pytest.fixture
Chris McDonald320ef422020-04-18 04:57:04 -060088def singleton_manager(monkeypatch):
Alex Klein1699fab2022-09-08 08:46:06 -060089 """Force tests to use a singleton Manager and automatically clean it up."""
90 m = parallel.Manager()
Chris McDonald320ef422020-04-18 04:57:04 -060091
Alex Klein1699fab2022-09-08 08:46:06 -060092 def our_manager():
93 return m
Chris McDonald320ef422020-04-18 04:57:04 -060094
Alex Klein1699fab2022-09-08 08:46:06 -060095 monkeypatch.setattr(parallel, "Manager", our_manager)
96 yield
97 m.shutdown()
Chris McDonald320ef422020-04-18 04:57:04 -060098
99
100@pytest.fixture
Chris McDonalde13f0242020-04-07 18:37:15 -0600101def legacy_capture_output(request, capfd):
Alex Klein1699fab2022-09-08 08:46:06 -0600102 """Adds the `capfd` fixture to TestCase-style test classes.
Chris McDonalde13f0242020-04-07 18:37:15 -0600103
Alex Kleina248dc02023-04-04 15:49:13 -0600104 This fixture should only be used on cros_test_lib.TestCase test classes,
105 since it doesn't yield anything and just attaches the built-in pytest
106 `capfd` fixture to the requesting class. Tests written as standalone
107 functions should use pytest's built-in `capfd` fixture instead of this. See
108 the documentation for more information on how to use the `capfd` fixture
109 that this provides:
Alex Klein1699fab2022-09-08 08:46:06 -0600110 https://docs.pytest.org/en/latest/reference/reference.html#std-fixture-capfd
Chris McDonalde13f0242020-04-07 18:37:15 -0600111
Alex Kleina248dc02023-04-04 15:49:13 -0600112 See the following documentation for an explanation of why fixtures have to
113 be provided to TestCase classes in this manner:
Alex Klein1699fab2022-09-08 08:46:06 -0600114 https://docs.pytest.org/en/latest/how-to/unittest.html#mixing-pytest-fixtures-into-unittest-testcase-subclasses-using-marks
115 """
116 request.cls.capfd = capfd
Chris McDonald6ce00962020-04-14 04:05:21 -0600117
118
119@pytest.fixture
120def testcase_caplog(request, caplog):
Alex Klein1699fab2022-09-08 08:46:06 -0600121 """Adds the `caplog` fixture to TestCase-style test classes.
Chris McDonald6ce00962020-04-14 04:05:21 -0600122
Alex Kleina248dc02023-04-04 15:49:13 -0600123 This fixture should only be used on cros_test_lib.TestCase test classes,
124 since it doesn't yield anything and just attaches the built-in pytest
125 `caplog` fixture to the requesting class. Tests written as standalone
126 functions should use pytest's built-in `caplog` fixture instead of this. See
127 the documentation for more information on how to use the `caplog` fixture
128 that this provides:
Alex Klein1699fab2022-09-08 08:46:06 -0600129 https://docs.pytest.org/en/latest/reference/reference.html#caplog
Chris McDonald6ce00962020-04-14 04:05:21 -0600130
Alex Kleina248dc02023-04-04 15:49:13 -0600131 See the following documentation for an explanation of why fixtures have to
132 be provided to TestCase classes in this manner:
Alex Klein1699fab2022-09-08 08:46:06 -0600133 https://docs.pytest.org/en/latest/how-to/unittest.html#mixing-pytest-fixtures-into-unittest-testcase-subclasses-using-marks
134 """
135 request.cls.caplog = caplog
Chris McDonald05511c92020-05-01 16:45:56 -0600136
137
Michael Mortensende716a12020-05-15 11:27:00 -0600138@pytest.fixture
139def testcase_monkeypatch(request, monkeypatch):
Alex Klein1699fab2022-09-08 08:46:06 -0600140 """Adds the `monkeypatch` fixture to TestCase-style test classes.
Michael Mortensende716a12020-05-15 11:27:00 -0600141
Alex Kleina248dc02023-04-04 15:49:13 -0600142 This fixture should only be used on cros_test_lib.TestCase test classes,
143 since it doesn't yield anything and just attaches the built-in pytest
144 `monkeypatch` fixture to the requesting class. Tests written as standalone
145 functions should use pytest's built-in `monkeypatch` fixture instead of
146 this. See the documentation for more information on how to use the
147 `monkeypatch` fixture that this provides:
Alex Klein1699fab2022-09-08 08:46:06 -0600148 https://docs.pytest.org/en/latest/reference/reference.html#monkeypatch
Michael Mortensende716a12020-05-15 11:27:00 -0600149
Alex Kleina248dc02023-04-04 15:49:13 -0600150 See the following documentation for an explanation of why fixtures have to
151 be provided to TestCase classes in this manner:
Alex Klein1699fab2022-09-08 08:46:06 -0600152 https://docs.pytest.org/en/latest/how-to/unittest.html#mixing-pytest-fixtures-into-unittest-testcase-subclasses-using-marks
153 """
154 request.cls.monkeypatch = monkeypatch
Michael Mortensende716a12020-05-15 11:27:00 -0600155
156
Chris McDonald05511c92020-05-01 16:45:56 -0600157def pytest_assertrepr_compare(op, left, right):
Alex Klein1699fab2022-09-08 08:46:06 -0600158 """Global hook for defining detailed explanations for failed assertions.
Chris McDonald05511c92020-05-01 16:45:56 -0600159
Alex Klein1699fab2022-09-08 08:46:06 -0600160 https://docs.pytest.org/en/latest/how-to/assert.html
161 """
162 if (
163 isinstance(left, package_info.CPV)
164 and isinstance(right, cr.test.Overlay)
165 and op == "in"
166 ):
167 package_path = right.path / left.category / left.package
168 return [
169 f"{left.pv}.ebuild exists in {right.path}",
170 "Ebuild does not exist in overlay.",
171 "Ebuilds found in overlay with same category and package:",
172 ] + sorted(
173 "\t" + str(p.relative_to(package_path))
174 for p in package_path.glob("*.ebuild")
175 )
Chris McDonaldcdfd1132020-05-12 07:09:51 -0600176
177
178def pytest_addoption(parser):
Alex Klein1699fab2022-09-08 08:46:06 -0600179 """Adds additional options to the default pytest CLI args."""
180 parser.addoption(
181 "--no-chroot",
182 dest="chroot",
183 action="store_false",
184 help="Skip any tests that require a chroot to function.",
185 )
Chris McDonaldcdfd1132020-05-12 07:09:51 -0600186
187
188def pytest_collection_modifyitems(config, items):
Alex Klein1699fab2022-09-08 08:46:06 -0600189 """Modifies the list of test items pytest has collected.
Chris McDonaldcdfd1132020-05-12 07:09:51 -0600190
Alex Klein1699fab2022-09-08 08:46:06 -0600191 See the following link for full documentation on pytest collection hooks:
192 https://docs.pytest.org/en/latest/reference/reference.html#collection-hooks
193 """
194 if config.option.chroot:
195 return
196 skip_inside_only = pytest.mark.skip(reason="Test requires a chroot to run.")
197 for item in items:
198 if "inside_only" in item.keywords:
199 item.add_marker(skip_inside_only)
Mike Frysinger3f058842023-07-09 00:34:07 -0400200
201
202@pytest.fixture
203def run_mock():
204 """Robust mock for cros_build_lib.run."""
Mike Frysinger3f058842023-07-09 00:34:07 -0400205 with cros_test_lib.RunCommandMock() as rc_mock:
206 rc_mock.SetDefaultCmdResult()
207 yield rc_mock
Mike Frysingerf134dc22023-07-11 23:19:50 -0400208
209
210@pytest.fixture(scope="session", autouse=True)
211def _check_network_test(request):
212 """Detect whether the test uses network_test marker.
213
214 This can be helpful for code to detect when network traffic is attempted but
215 network tests weren't requested which indicates a bad test -- one that needs
216 to be decorated with @cros_test_lib.pytestmark_network_test.
217 """
218 for item in request.session.items:
219 if item.get_closest_marker("network_test") is not None:
220 cros_test_lib.NETWORK_TESTS_ENABLED = True
221 break