blob: 61919f4a0c37297cd0d78067c951ae734e5111c6 [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
15
16
17@pytest.fixture(name="outside_chroot")
18def outside_chroot_fixture():
19 """Mocks IsInsideChroot to be False."""
20 with mock.patch.object(
21 cros_build_lib, "IsInsideChroot", return_value=False
22 ) as outside_chroot:
23 yield outside_chroot
24
25
26@pytest.fixture(name="mock_emerge")
27def mock_emerge_fixture():
28 """Stubs the build_sdk_subtools emerge helper and sets it up to run."""
29 with mock.patch.multiple(
30 "chromite.scripts.build_sdk_subtools",
31 _run_system_emerge=mock.DEFAULT,
32 _is_inside_subtools_chroot=mock.DEFAULT,
33 ) as mocks:
34 mocks["_is_inside_subtools_chroot"].return_value = True
35 yield mocks["_run_system_emerge"]
36
37
Trent Apted16007b82023-07-06 14:51:57 +100038@pytest.fixture(name="mock_exporter", autouse=True)
39def mock_exporter_fixture():
40 """Stubs the exporter for InstalledSubtools to avoid side-effects."""
41 with mock.patch("chromite.lib.subtool_lib.InstalledSubtools") as mock_lib:
42 yield mock_lib
43
44
Trent Apted7d2777b2023-06-29 13:35:03 +100045def test_must_run_outside_sdk(caplog) -> None:
46 """Tests build_sdk_subtools complains if run in the chroot."""
47 with pytest.raises(cros_build_lib.DieSystemExit) as error_info:
48 build_sdk_subtools.main()
49 assert error_info.value.code == 1
50 assert "build_sdk_subtools must be run outside the chroot" in caplog.text
51
52
53def test_cros_sdk(run_mock, outside_chroot) -> None:
54 """Tests the steps leading up to the cros_sdk invocation."""
55 # Fake a failure from cros_sdk to ensure it propagates.
56 run_mock.SetDefaultCmdResult(returncode=42)
57
58 assert build_sdk_subtools.main() == 42
59 assert outside_chroot.called
60 assert run_mock.call_count == 1
61 assert run_mock.call_args_list[0].args[0] == [
62 "cros_sdk",
63 "--chroot",
64 "/mnt/host/source/chroot/build/amd64-subtools-host",
65 "--create",
66 "--skip-chroot-upgrade",
67 ]
68
69
70def test_cros_sdk_clean(run_mock, outside_chroot) -> None:
71 """Tests steps leading up to the cros_sdk invocation with --clean."""
72 run_mock.SetDefaultCmdResult(returncode=42)
73
74 assert build_sdk_subtools.main(["--clean"]) == 42
75 assert outside_chroot.called
76 assert run_mock.call_count == 1
77 cros_sdk_cmd = run_mock.call_args_list[0].args[0]
78 assert cros_sdk_cmd[0] == "cros_sdk"
79 assert "--delete" in cros_sdk_cmd
80
81
82def test_cros_sdk_output_dir(run_mock, outside_chroot) -> None:
83 """Tests steps leading up to the cros_sdk invocation with --output-dir."""
84 run_mock.SetDefaultCmdResult(returncode=42)
85
86 assert build_sdk_subtools.main(["--output-dir", "/foo"]) == 42
87 assert outside_chroot.called
88 cros_sdk_cmd = run_mock.call_args_list[0].args[0]
89 chroot_arg_index = cros_sdk_cmd.index("/mnt/host/source/chroot/foo")
90 assert cros_sdk_cmd[0] == "cros_sdk"
91 assert cros_sdk_cmd[chroot_arg_index - 1] == "--chroot"
92
93
94def test_chroot_required_after_cros_sdk(run_mock, outside_chroot) -> None:
95 """Tests that build_sdk_subtools will ask for chroot when setup."""
96 with pytest.raises(commandline.ChrootRequiredError) as error_info:
97 build_sdk_subtools.main(["--no-setup-chroot"])
98
99 assert run_mock.call_count == 0
100 assert outside_chroot.called
101 assert error_info.value.cmd == ["build_sdk_subtools", "--no-setup-chroot"]
102 assert error_info.value.chroot_args == [
103 "--chroot",
104 "/mnt/host/source/chroot/build/amd64-subtools-host",
105 ]
106
107
108def test_chroots_into_output_dir(run_mock, outside_chroot) -> None:
109 """Tests that --output-dir is consumed properly after setup."""
110 with pytest.raises(commandline.ChrootRequiredError) as error_info:
111 build_sdk_subtools.main(["--no-setup-chroot", "--output-dir", "/foo"])
112
113 assert run_mock.call_count == 0
114 assert outside_chroot.called
115 assert error_info.value.chroot_args == [
116 "--chroot",
117 "/mnt/host/source/chroot/foo",
118 ]
119
120
121def test_setup_sdk_invocation(run_mock, outside_chroot) -> None:
122 """Tests the SDK setup invocation, before it becomes a subtools chroot."""
123 # Fake success from cros_sdk, failure from _setup_base_sdk().
124 run_mock.SetDefaultCmdResult(returncode=0)
125 run_mock.AddCmdResult(
126 ["sudo", "--", "build_sdk_subtools", "--relaunch-for-setup"],
127 returncode=42,
128 )
129
Trent Apted2d9111b2023-08-04 16:20:35 +1000130 assert build_sdk_subtools.main() == 42
Trent Apted7d2777b2023-06-29 13:35:03 +1000131 assert run_mock.call_count == 2
132 assert outside_chroot.called
133
134 sudo_run_cmd = run_mock.call_args_list[1]
135
136 assert sudo_run_cmd.args[0] == [
137 "sudo",
138 "--",
139 "build_sdk_subtools",
140 "--relaunch-for-setup",
141 ]
142 assert sudo_run_cmd.kwargs["enter_chroot"] is True
143 assert sudo_run_cmd.kwargs["chroot_args"] == [
144 "--chroot",
145 "/mnt/host/source/chroot/build/amd64-subtools-host",
146 ]
147 # Stop here: Actually running `--relaunch-for-setup` principally wants to
148 # mutate the SDK state as root, which is too messy as a unit test.
149
150
151def test_default_package(mock_emerge) -> None:
152 """Tests a default virtual package is provided to update packages."""
153 assert build_sdk_subtools.main() == 0
154 assert mock_emerge.call_count == 1
155 emerge_cmd = mock_emerge.call_args.args[0]
156 assert Path("/mnt/host/source/chromite/bin/parallel_emerge") in emerge_cmd
157 assert emerge_cmd[-1] == "virtual/target-sdk-subtools"
158
159
160def test_provided_package(mock_emerge) -> None:
161 """Tests the default package can be passed in from command line."""
162 assert build_sdk_subtools.main(["vim"]) == 0
163 assert mock_emerge.call_args.args[0][-1] == "vim"
164
165
166def test_skip_package_update(mock_emerge) -> None:
167 """Tests --skip-package-update will not try to emerge anything."""
168 assert build_sdk_subtools.main(["--no-update-packages"]) == 0
169 assert mock_emerge.call_count == 0
Trent Apted16007b82023-07-06 14:51:57 +1000170
171
172def test_invokes_exporter(mock_emerge, mock_exporter) -> None:
173 """Tests that the exporter is invoked."""
174 assert build_sdk_subtools.main([]) == 0
175 assert mock_emerge.call_count == 1
176 assert mock_exporter.called
177 installed_subtools = mock_exporter.return_value
178 assert installed_subtools.bundle_all.called
179 assert installed_subtools.export_all.called