blob: bd4d26477463aff2229febd65eb7c312f7207ce1 [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
Trent Apted2d9111b2023-08-04 16:20:35 +100015import os
16from unittest import mock
Chris McDonaldffe2a412020-04-15 02:27:25 -060017
Chris McDonaldee2fbda2020-04-30 18:10:01 -060018import pytest
Chris McDonald2e9a09c2020-04-03 16:09:32 -060019
Chris McDonald05511c92020-05-01 16:45:56 -060020import chromite as cr
Chris McDonald2e9a09c2020-04-03 16:09:32 -060021from chromite.lib import cidb
Trent Apted2d9111b2023-08-04 16:20:35 +100022from chromite.lib import constants
Mike Frysingerf134dc22023-07-11 23:19:50 -040023from chromite.lib import cros_test_lib
Chris McDonald320ef422020-04-18 04:57:04 -060024from chromite.lib import parallel
Chris McDonald6ce00962020-04-14 04:05:21 -060025from chromite.lib import retry_stats
Alex Klein75df1792020-06-11 14:42:49 -060026from chromite.lib.parser import package_info
Chris McDonald2e9a09c2020-04-03 16:09:32 -060027
Chris McDonaldee2fbda2020-04-30 18:10:01 -060028# We use wildcard imports here to make fixtures defined in the test module
29# globally visible.
30# pylint: disable=unused-wildcard-import, wildcard-import
Mike Frysinger94cfdef2019-08-25 00:04:27 -040031#
Chris McDonaldee2fbda2020-04-30 18:10:01 -060032# Importing from *_fixtures.py files into conftest.py is the only time a
33# module should use a wildcard import. *_fixtures.py files should ensure
34# that the only items visible to a wildcard import are pytest fixtures,
35# usually by declaring __all__ if necessary.
36from chromite.test.portage_fixtures import *
37
Chris McDonald2e9a09c2020-04-03 16:09:32 -060038
Alex Klein1699fab2022-09-08 08:46:06 -060039@pytest.fixture(scope="class", autouse=True)
Chris McDonald2e9a09c2020-04-03 16:09:32 -060040def mock_cidb_connection():
Alex Klein1699fab2022-09-08 08:46:06 -060041 """Ensure that the CIDB connection factory is initialized as a mock.
Chris McDonald2e9a09c2020-04-03 16:09:32 -060042
Alex Klein1699fab2022-09-08 08:46:06 -060043 Unit tests should never connect to any live instances of CIDB and this
44 initialization ensures that they only ever get a mock connection instance.
Chris McDonald2e9a09c2020-04-03 16:09:32 -060045
Alex Klein1699fab2022-09-08 08:46:06 -060046 Previously cros_test_lib.TestProgram.runTests was responsible for globally
47 initializing this mock and multiple tests are flaky if this mock connection
48 is not initialized before any tests are run.
49 """
50 # pylint: disable=protected-access
51 cidb.CIDBConnectionFactory._ClearCIDBSetup()
52 cidb.CIDBConnectionFactory.SetupMockCidb()
Chris McDonaldffe2a412020-04-15 02:27:25 -060053
54
Alex Klein1699fab2022-09-08 08:46:06 -060055@pytest.fixture(scope="class", autouse=True)
Chris McDonaldffe2a412020-04-15 02:27:25 -060056def assert_no_zombies():
Alex Klein1699fab2022-09-08 08:46:06 -060057 """Assert that tests have no active child processes after completion.
Chris McDonaldffe2a412020-04-15 02:27:25 -060058
Alex Kleina248dc02023-04-04 15:49:13 -060059 This assertion runs after class tearDown methods because of the
60 scope='class' declaration.
Alex Klein1699fab2022-09-08 08:46:06 -060061 """
62 yield
63 children = multiprocessing.active_children()
64 if children:
65 pytest.fail(
66 "Test has %s active child processes after tearDown: %s"
67 % (len(children), children)
68 )
Chris McDonalde13f0242020-04-07 18:37:15 -060069
70
Alex Klein1699fab2022-09-08 08:46:06 -060071@pytest.fixture(scope="class", autouse=True)
Chris McDonald6ce00962020-04-14 04:05:21 -060072def clear_retry_stats_manager():
Alex Klein1699fab2022-09-08 08:46:06 -060073 """Reset the global state of the stats manager before every test.
Chris McDonald6ce00962020-04-14 04:05:21 -060074
Alex Klein1699fab2022-09-08 08:46:06 -060075 Without this fixture many tests fail due to this global value being set and
76 then not cleared. The child manager process may have been killed but this
77 module level variable is still pointing at it, leading to the test trying to
78 write to a closed pipe.
79 """
80 # pylint: disable=protected-access
81 retry_stats._STATS_COLLECTION = None
82
Chris McDonald6ce00962020-04-14 04:05:21 -060083
Chris McDonald3e1ef0a2020-10-16 13:13:13 -060084@pytest.fixture(autouse=True)
Trent Apted2d9111b2023-08-04 16:20:35 +100085def set_testing_environment_variables():
86 """Sets a standard environment, and ensures often-used state is restored."""
87 # Use a `mock.patch` ContextManager to snapshot and restore the entire dict.
88 with mock.patch.dict(os.environ):
89 # Set environment marker to relax certain strict checks for test code.
90 os.environ["CHROMITE_INSIDE_PYTEST"] = "1"
91
92 # Force all log lines in tests to include ANSI color prefixes, since it
93 # can be configured per-user.
94 os.environ["NOCOLOR"] = "no"
95
96 # Clear environment variables that chromite is globally sensitive to and
97 # that should be suppressed for tests.
98 os.environ.pop(constants.SHARED_CACHE_ENVVAR, None)
99
100 yield
Alex Klein1699fab2022-09-08 08:46:06 -0600101
Chris McDonald6ce00962020-04-14 04:05:21 -0600102
Chris McDonalde13f0242020-04-07 18:37:15 -0600103@pytest.fixture
Chris McDonald320ef422020-04-18 04:57:04 -0600104def singleton_manager(monkeypatch):
Alex Klein1699fab2022-09-08 08:46:06 -0600105 """Force tests to use a singleton Manager and automatically clean it up."""
106 m = parallel.Manager()
Chris McDonald320ef422020-04-18 04:57:04 -0600107
Alex Klein1699fab2022-09-08 08:46:06 -0600108 def our_manager():
109 return m
Chris McDonald320ef422020-04-18 04:57:04 -0600110
Alex Klein1699fab2022-09-08 08:46:06 -0600111 monkeypatch.setattr(parallel, "Manager", our_manager)
112 yield
113 m.shutdown()
Chris McDonald320ef422020-04-18 04:57:04 -0600114
115
116@pytest.fixture
Chris McDonalde13f0242020-04-07 18:37:15 -0600117def legacy_capture_output(request, capfd):
Alex Klein1699fab2022-09-08 08:46:06 -0600118 """Adds the `capfd` fixture to TestCase-style test classes.
Chris McDonalde13f0242020-04-07 18:37:15 -0600119
Alex Kleina248dc02023-04-04 15:49:13 -0600120 This fixture should only be used on cros_test_lib.TestCase test classes,
121 since it doesn't yield anything and just attaches the built-in pytest
122 `capfd` fixture to the requesting class. Tests written as standalone
123 functions should use pytest's built-in `capfd` fixture instead of this. See
124 the documentation for more information on how to use the `capfd` fixture
125 that this provides:
Alex Klein1699fab2022-09-08 08:46:06 -0600126 https://docs.pytest.org/en/latest/reference/reference.html#std-fixture-capfd
Chris McDonalde13f0242020-04-07 18:37:15 -0600127
Alex Kleina248dc02023-04-04 15:49:13 -0600128 See the following documentation for an explanation of why fixtures have to
129 be provided to TestCase classes in this manner:
Alex Klein1699fab2022-09-08 08:46:06 -0600130 https://docs.pytest.org/en/latest/how-to/unittest.html#mixing-pytest-fixtures-into-unittest-testcase-subclasses-using-marks
131 """
132 request.cls.capfd = capfd
Chris McDonald6ce00962020-04-14 04:05:21 -0600133
134
135@pytest.fixture
136def testcase_caplog(request, caplog):
Alex Klein1699fab2022-09-08 08:46:06 -0600137 """Adds the `caplog` fixture to TestCase-style test classes.
Chris McDonald6ce00962020-04-14 04:05:21 -0600138
Alex Kleina248dc02023-04-04 15:49:13 -0600139 This fixture should only be used on cros_test_lib.TestCase test classes,
140 since it doesn't yield anything and just attaches the built-in pytest
141 `caplog` fixture to the requesting class. Tests written as standalone
142 functions should use pytest's built-in `caplog` fixture instead of this. See
143 the documentation for more information on how to use the `caplog` fixture
144 that this provides:
Alex Klein1699fab2022-09-08 08:46:06 -0600145 https://docs.pytest.org/en/latest/reference/reference.html#caplog
Chris McDonald6ce00962020-04-14 04:05:21 -0600146
Alex Kleina248dc02023-04-04 15:49:13 -0600147 See the following documentation for an explanation of why fixtures have to
148 be provided to TestCase classes in this manner:
Alex Klein1699fab2022-09-08 08:46:06 -0600149 https://docs.pytest.org/en/latest/how-to/unittest.html#mixing-pytest-fixtures-into-unittest-testcase-subclasses-using-marks
150 """
151 request.cls.caplog = caplog
Chris McDonald05511c92020-05-01 16:45:56 -0600152
153
Michael Mortensende716a12020-05-15 11:27:00 -0600154@pytest.fixture
155def testcase_monkeypatch(request, monkeypatch):
Alex Klein1699fab2022-09-08 08:46:06 -0600156 """Adds the `monkeypatch` fixture to TestCase-style test classes.
Michael Mortensende716a12020-05-15 11:27:00 -0600157
Alex Kleina248dc02023-04-04 15:49:13 -0600158 This fixture should only be used on cros_test_lib.TestCase test classes,
159 since it doesn't yield anything and just attaches the built-in pytest
160 `monkeypatch` fixture to the requesting class. Tests written as standalone
161 functions should use pytest's built-in `monkeypatch` fixture instead of
162 this. See the documentation for more information on how to use the
163 `monkeypatch` fixture that this provides:
Alex Klein1699fab2022-09-08 08:46:06 -0600164 https://docs.pytest.org/en/latest/reference/reference.html#monkeypatch
Michael Mortensende716a12020-05-15 11:27:00 -0600165
Alex Kleina248dc02023-04-04 15:49:13 -0600166 See the following documentation for an explanation of why fixtures have to
167 be provided to TestCase classes in this manner:
Alex Klein1699fab2022-09-08 08:46:06 -0600168 https://docs.pytest.org/en/latest/how-to/unittest.html#mixing-pytest-fixtures-into-unittest-testcase-subclasses-using-marks
169 """
170 request.cls.monkeypatch = monkeypatch
Michael Mortensende716a12020-05-15 11:27:00 -0600171
172
Chris McDonald05511c92020-05-01 16:45:56 -0600173def pytest_assertrepr_compare(op, left, right):
Alex Klein1699fab2022-09-08 08:46:06 -0600174 """Global hook for defining detailed explanations for failed assertions.
Chris McDonald05511c92020-05-01 16:45:56 -0600175
Alex Klein1699fab2022-09-08 08:46:06 -0600176 https://docs.pytest.org/en/latest/how-to/assert.html
177 """
178 if (
179 isinstance(left, package_info.CPV)
180 and isinstance(right, cr.test.Overlay)
181 and op == "in"
182 ):
183 package_path = right.path / left.category / left.package
184 return [
185 f"{left.pv}.ebuild exists in {right.path}",
186 "Ebuild does not exist in overlay.",
187 "Ebuilds found in overlay with same category and package:",
188 ] + sorted(
189 "\t" + str(p.relative_to(package_path))
190 for p in package_path.glob("*.ebuild")
191 )
Chris McDonaldcdfd1132020-05-12 07:09:51 -0600192
193
194def pytest_addoption(parser):
Alex Klein1699fab2022-09-08 08:46:06 -0600195 """Adds additional options to the default pytest CLI args."""
196 parser.addoption(
197 "--no-chroot",
198 dest="chroot",
199 action="store_false",
200 help="Skip any tests that require a chroot to function.",
201 )
Chris McDonaldcdfd1132020-05-12 07:09:51 -0600202
203
204def pytest_collection_modifyitems(config, items):
Alex Klein1699fab2022-09-08 08:46:06 -0600205 """Modifies the list of test items pytest has collected.
Chris McDonaldcdfd1132020-05-12 07:09:51 -0600206
Alex Klein1699fab2022-09-08 08:46:06 -0600207 See the following link for full documentation on pytest collection hooks:
208 https://docs.pytest.org/en/latest/reference/reference.html#collection-hooks
209 """
210 if config.option.chroot:
211 return
212 skip_inside_only = pytest.mark.skip(reason="Test requires a chroot to run.")
213 for item in items:
214 if "inside_only" in item.keywords:
215 item.add_marker(skip_inside_only)
Mike Frysinger3f058842023-07-09 00:34:07 -0400216
217
218@pytest.fixture
219def run_mock():
220 """Robust mock for cros_build_lib.run."""
Mike Frysinger3f058842023-07-09 00:34:07 -0400221 with cros_test_lib.RunCommandMock() as rc_mock:
222 rc_mock.SetDefaultCmdResult()
223 yield rc_mock
Mike Frysingerf134dc22023-07-11 23:19:50 -0400224
225
226@pytest.fixture(scope="session", autouse=True)
227def _check_network_test(request):
228 """Detect whether the test uses network_test marker.
229
230 This can be helpful for code to detect when network traffic is attempted but
231 network tests weren't requested which indicates a bad test -- one that needs
232 to be decorated with @cros_test_lib.pytestmark_network_test.
233 """
234 for item in request.session.items:
235 if item.get_closest_marker("network_test") is not None:
236 cros_test_lib.NETWORK_TESTS_ENABLED = True
237 break