blob: 07c9ff93492ae36c3a8f8d72ea19ed8d56f3d615 [file] [log] [blame]
Trent Apted7d2777b2023-06-29 13:35:03 +10001# Copyright 2023 The ChromiumOS Authors
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Unit tests for build_sdk_subtools."""
6
Trent Apted7d2777b2023-06-29 13:35:03 +10007from pathlib import Path
8from unittest import mock
9
10import pytest
11
12from chromite.lib import commandline
13from chromite.lib import cros_build_lib
14from chromite.scripts import build_sdk_subtools
Trent Aptedbd3cb412023-08-18 11:37:02 +100015from chromite.service import sdk_subtools
Trent Apted7d2777b2023-06-29 13:35:03 +100016
17
18@pytest.fixture(name="outside_chroot")
19def outside_chroot_fixture():
20 """Mocks IsInsideChroot to be False."""
21 with mock.patch.object(
22 cros_build_lib, "IsInsideChroot", return_value=False
23 ) as outside_chroot:
24 yield outside_chroot
25
26
27@pytest.fixture(name="mock_emerge")
28def mock_emerge_fixture():
29 """Stubs the build_sdk_subtools emerge helper and sets it up to run."""
30 with mock.patch.multiple(
Trent Aptedbd3cb412023-08-18 11:37:02 +100031 "chromite.service.sdk_subtools",
Trent Apted7d2777b2023-06-29 13:35:03 +100032 _run_system_emerge=mock.DEFAULT,
Trent Aptedbd3cb412023-08-18 11:37:02 +100033 is_inside_subtools_chroot=mock.DEFAULT,
Trent Apted7d2777b2023-06-29 13:35:03 +100034 ) as mocks:
Trent Aptedbd3cb412023-08-18 11:37:02 +100035 mocks["is_inside_subtools_chroot"].return_value = True
Trent Apted7d2777b2023-06-29 13:35:03 +100036 yield mocks["_run_system_emerge"]
37
38
Trent Apted16007b82023-07-06 14:51:57 +100039@pytest.fixture(name="mock_exporter", autouse=True)
40def mock_exporter_fixture():
41 """Stubs the exporter for InstalledSubtools to avoid side-effects."""
42 with mock.patch("chromite.lib.subtool_lib.InstalledSubtools") as mock_lib:
43 yield mock_lib
44
45
Trent Aptedbd3cb412023-08-18 11:37:02 +100046@pytest.fixture(autouse=True)
47def build_sdk_subtools_consistency_check():
48 """Die quickly if the version file is left over in the test SDK.
49
50 This can happen if the build API entrypoint was tested on the local machine.
51 Tests in this file will fail in confusing ways if this is ever the case.
52 """
53 version_file = sdk_subtools.SUBTOOLS_CHROOT_VERSION_FILE
54 assert (
55 not version_file.exists()
56 ), f"{version_file} exists in the chroot (stray?)."
57
58
Trent Apted7d2777b2023-06-29 13:35:03 +100059def test_must_run_outside_sdk(caplog) -> None:
60 """Tests build_sdk_subtools complains if run in the chroot."""
61 with pytest.raises(cros_build_lib.DieSystemExit) as error_info:
62 build_sdk_subtools.main()
63 assert error_info.value.code == 1
64 assert "build_sdk_subtools must be run outside the chroot" in caplog.text
65
66
67def test_cros_sdk(run_mock, outside_chroot) -> None:
68 """Tests the steps leading up to the cros_sdk invocation."""
69 # Fake a failure from cros_sdk to ensure it propagates.
70 run_mock.SetDefaultCmdResult(returncode=42)
71
72 assert build_sdk_subtools.main() == 42
73 assert outside_chroot.called
74 assert run_mock.call_count == 1
75 assert run_mock.call_args_list[0].args[0] == [
76 "cros_sdk",
77 "--chroot",
78 "/mnt/host/source/chroot/build/amd64-subtools-host",
79 "--create",
80 "--skip-chroot-upgrade",
81 ]
82
83
84def test_cros_sdk_clean(run_mock, outside_chroot) -> None:
85 """Tests steps leading up to the cros_sdk invocation with --clean."""
86 run_mock.SetDefaultCmdResult(returncode=42)
87
88 assert build_sdk_subtools.main(["--clean"]) == 42
89 assert outside_chroot.called
90 assert run_mock.call_count == 1
91 cros_sdk_cmd = run_mock.call_args_list[0].args[0]
92 assert cros_sdk_cmd[0] == "cros_sdk"
93 assert "--delete" in cros_sdk_cmd
94
95
96def test_cros_sdk_output_dir(run_mock, outside_chroot) -> None:
97 """Tests steps leading up to the cros_sdk invocation with --output-dir."""
98 run_mock.SetDefaultCmdResult(returncode=42)
99
100 assert build_sdk_subtools.main(["--output-dir", "/foo"]) == 42
101 assert outside_chroot.called
102 cros_sdk_cmd = run_mock.call_args_list[0].args[0]
103 chroot_arg_index = cros_sdk_cmd.index("/mnt/host/source/chroot/foo")
104 assert cros_sdk_cmd[0] == "cros_sdk"
105 assert cros_sdk_cmd[chroot_arg_index - 1] == "--chroot"
106
107
108def test_chroot_required_after_cros_sdk(run_mock, outside_chroot) -> None:
109 """Tests that build_sdk_subtools will ask for chroot when setup."""
110 with pytest.raises(commandline.ChrootRequiredError) as error_info:
111 build_sdk_subtools.main(["--no-setup-chroot"])
112
113 assert run_mock.call_count == 0
114 assert outside_chroot.called
115 assert error_info.value.cmd == ["build_sdk_subtools", "--no-setup-chroot"]
116 assert error_info.value.chroot_args == [
117 "--chroot",
118 "/mnt/host/source/chroot/build/amd64-subtools-host",
119 ]
120
121
122def test_chroots_into_output_dir(run_mock, outside_chroot) -> None:
123 """Tests that --output-dir is consumed properly after setup."""
124 with pytest.raises(commandline.ChrootRequiredError) as error_info:
125 build_sdk_subtools.main(["--no-setup-chroot", "--output-dir", "/foo"])
126
127 assert run_mock.call_count == 0
128 assert outside_chroot.called
129 assert error_info.value.chroot_args == [
130 "--chroot",
131 "/mnt/host/source/chroot/foo",
132 ]
133
134
135def test_setup_sdk_invocation(run_mock, outside_chroot) -> None:
136 """Tests the SDK setup invocation, before it becomes a subtools chroot."""
Trent Aptedbd3cb412023-08-18 11:37:02 +1000137 # Fake success from cros_sdk, failure from setup_base_sdk().
Trent Apted7d2777b2023-06-29 13:35:03 +1000138 run_mock.SetDefaultCmdResult(returncode=0)
139 run_mock.AddCmdResult(
140 ["sudo", "--", "build_sdk_subtools", "--relaunch-for-setup"],
141 returncode=42,
142 )
143
Trent Apted2d9111b2023-08-04 16:20:35 +1000144 assert build_sdk_subtools.main() == 42
Trent Apted7d2777b2023-06-29 13:35:03 +1000145 assert run_mock.call_count == 2
146 assert outside_chroot.called
147
148 sudo_run_cmd = run_mock.call_args_list[1]
149
150 assert sudo_run_cmd.args[0] == [
151 "sudo",
152 "--",
153 "build_sdk_subtools",
154 "--relaunch-for-setup",
155 ]
156 assert sudo_run_cmd.kwargs["enter_chroot"] is True
157 assert sudo_run_cmd.kwargs["chroot_args"] == [
158 "--chroot",
159 "/mnt/host/source/chroot/build/amd64-subtools-host",
160 ]
161 # Stop here: Actually running `--relaunch-for-setup` principally wants to
162 # mutate the SDK state as root, which is too messy as a unit test.
163
164
165def test_default_package(mock_emerge) -> None:
166 """Tests a default virtual package is provided to update packages."""
167 assert build_sdk_subtools.main() == 0
168 assert mock_emerge.call_count == 1
169 emerge_cmd = mock_emerge.call_args.args[0]
170 assert Path("/mnt/host/source/chromite/bin/parallel_emerge") in emerge_cmd
171 assert emerge_cmd[-1] == "virtual/target-sdk-subtools"
172
173
174def test_provided_package(mock_emerge) -> None:
175 """Tests the default package can be passed in from command line."""
176 assert build_sdk_subtools.main(["vim"]) == 0
177 assert mock_emerge.call_args.args[0][-1] == "vim"
178
179
180def test_skip_package_update(mock_emerge) -> None:
181 """Tests --skip-package-update will not try to emerge anything."""
182 assert build_sdk_subtools.main(["--no-update-packages"]) == 0
183 assert mock_emerge.call_count == 0
Trent Apted16007b82023-07-06 14:51:57 +1000184
185
186def test_invokes_exporter(mock_emerge, mock_exporter) -> None:
187 """Tests that the exporter is invoked."""
188 assert build_sdk_subtools.main([]) == 0
189 assert mock_emerge.call_count == 1
190 assert mock_exporter.called
191 installed_subtools = mock_exporter.return_value
192 assert installed_subtools.bundle_all.called
193 assert installed_subtools.export_all.called