blob: 8f206a15119819862861162e68d712bd76ea0bf1 [file] [log] [blame]
Mike Frysingerf1ba7ad2022-09-12 05:42:57 -04001# Copyright 2019 The ChromiumOS Authors
Alex Klein19c4cc42019-02-27 14:47:57 -07002# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""SDK tests."""
6
Greg Edelston9dcdc8a2023-01-11 17:07:10 -07007import os
Greg Edelston01ae5942023-01-30 16:26:54 -07008import pathlib
Greg Edelston9dcdc8a2023-01-11 17:07:10 -07009from typing import List, Optional
Mike Frysinger166fea02021-02-12 05:30:33 -050010from unittest import mock
11
Alex Klein231d2da2019-07-22 16:44:45 -060012from chromite.api import api_config
Greg Edelston9dcdc8a2023-01-11 17:07:10 -070013from chromite.api.controller import controller_util
Alex Klein19c4cc42019-02-27 14:47:57 -070014from chromite.api.controller import sdk as sdk_controller
Alex Klein7107bdd2019-03-14 17:14:31 -060015from chromite.api.gen.chromite.api import sdk_pb2
Greg Edelston9dcdc8a2023-01-11 17:07:10 -070016from chromite.api.gen.chromiumos import common_pb2
17from chromite.lib import constants
Alex Klein19c4cc42019-02-27 14:47:57 -070018from chromite.lib import cros_build_lib
Alex Klein231d2da2019-07-22 16:44:45 -060019from chromite.lib import cros_test_lib
Alex Klein19c4cc42019-02-27 14:47:57 -070020from chromite.service import sdk as sdk_service
21
22
Alex Klein231d2da2019-07-22 16:44:45 -060023class SdkCreateTest(cros_test_lib.MockTestCase, api_config.ApiConfigMixin):
Alex Klein1699fab2022-09-08 08:46:06 -060024 """Create tests."""
Alex Klein19c4cc42019-02-27 14:47:57 -070025
Alex Klein1699fab2022-09-08 08:46:06 -060026 def setUp(self):
27 """Setup method."""
28 # We need to run the command outside the chroot.
29 self.PatchObject(cros_build_lib, "IsInsideChroot", return_value=False)
30 self.response = sdk_pb2.CreateResponse()
Alex Klein19c4cc42019-02-27 14:47:57 -070031
Alex Klein1699fab2022-09-08 08:46:06 -060032 def _GetRequest(
33 self,
34 no_replace=False,
Chris McDonald5dcdb892020-02-07 15:10:46 -070035 bootstrap=False,
Alex Klein1699fab2022-09-08 08:46:06 -060036 no_use_image=False,
37 cache_path=None,
38 chroot_path=None,
39 sdk_version=None,
40 skip_chroot_upgrade=False,
41 ):
42 """Helper to build a create request message."""
43 request = sdk_pb2.CreateRequest()
44 request.flags.no_replace = no_replace
45 request.flags.bootstrap = bootstrap
46 request.flags.no_use_image = no_use_image
Alex Klein231d2da2019-07-22 16:44:45 -060047
Alex Klein1699fab2022-09-08 08:46:06 -060048 if cache_path:
49 request.chroot.cache_dir = cache_path
50 if chroot_path:
51 request.chroot.path = chroot_path
52 if sdk_version:
53 request.sdk_version = sdk_version
54 if skip_chroot_upgrade:
55 request.skip_chroot_upgrade = skip_chroot_upgrade
Alex Klein19c4cc42019-02-27 14:47:57 -070056
Alex Klein1699fab2022-09-08 08:46:06 -060057 return request
58
59 def testValidateOnly(self):
Alex Kleinab87ceb2023-01-24 12:00:51 -070060 """Verify a validate-only call does not execute any logic."""
Alex Klein1699fab2022-09-08 08:46:06 -060061 patch = self.PatchObject(sdk_service, "Create")
62
63 sdk_controller.Create(
64 self._GetRequest(), self.response, self.validate_only_config
65 )
66 patch.assert_not_called()
67
68 def testMockCall(self):
69 """Sanity check that a mock call does not execute any logic."""
70 patch = self.PatchObject(sdk_service, "Create")
71
72 rc = sdk_controller.Create(
73 self._GetRequest(), self.response, self.mock_call_config
74 )
75 patch.assert_not_called()
76 self.assertFalse(rc)
77 self.assertTrue(self.response.version.version)
78
79 def testSuccess(self):
80 """Test the successful call output handling."""
81 self.PatchObject(sdk_service, "Create", return_value=1)
82
83 request = self._GetRequest()
84
85 sdk_controller.Create(request, self.response, self.api_config)
86
87 self.assertEqual(1, self.response.version.version)
88
89 def testFalseArguments(self):
90 """Test False argument handling."""
91 # Create the patches.
92 self.PatchObject(sdk_service, "Create", return_value=1)
93 args_patch = self.PatchObject(sdk_service, "CreateArguments")
94
95 # Flag translation tests.
96 # Test all false values in the message.
97 request = self._GetRequest(
98 no_replace=False, bootstrap=False, no_use_image=False
99 )
100 sdk_controller.Create(request, self.response, self.api_config)
101 args_patch.assert_called_with(
102 replace=True,
103 bootstrap=False,
104 use_image=True,
105 chroot_path=mock.ANY,
106 cache_dir=mock.ANY,
107 sdk_version=mock.ANY,
108 skip_chroot_upgrade=mock.ANY,
109 )
110
111 def testTrueArguments(self):
112 """Test True arguments handling."""
113 # Create the patches.
114 self.PatchObject(sdk_service, "Create", return_value=1)
115 args_patch = self.PatchObject(sdk_service, "CreateArguments")
116
117 # Test all True values in the message.
118 request = self._GetRequest(
119 no_replace=True,
120 bootstrap=True,
121 no_use_image=True,
122 sdk_version="foo",
123 skip_chroot_upgrade=True,
124 )
125 sdk_controller.Create(request, self.response, self.api_config)
126 args_patch.assert_called_with(
127 replace=False,
128 bootstrap=True,
129 use_image=False,
130 chroot_path=mock.ANY,
131 cache_dir=mock.ANY,
132 sdk_version="foo",
133 skip_chroot_upgrade=True,
134 )
Mike Frysingercb8992a2020-02-11 05:13:13 +0000135
Alex Kleinaa5c4172019-02-27 17:12:20 -0700136
Michael Mortensene87d8a62020-07-06 11:44:35 -0600137class SdkDeleteTest(cros_test_lib.MockTestCase, api_config.ApiConfigMixin):
Alex Klein1699fab2022-09-08 08:46:06 -0600138 """Create tests."""
Michael Mortensene87d8a62020-07-06 11:44:35 -0600139
Alex Klein1699fab2022-09-08 08:46:06 -0600140 def setUp(self):
141 """Setup method."""
142 # We need to run the command outside the chroot.
143 self.PatchObject(cros_build_lib, "IsInsideChroot", return_value=False)
144 self.response = sdk_pb2.DeleteResponse()
Michael Mortensene87d8a62020-07-06 11:44:35 -0600145
Alex Klein1699fab2022-09-08 08:46:06 -0600146 def _GetRequest(self, chroot_path=None):
147 """Helper to build a delete request message."""
148 request = sdk_pb2.DeleteRequest()
149 if chroot_path:
150 request.chroot.path = chroot_path
Michael Mortensene87d8a62020-07-06 11:44:35 -0600151
Alex Klein1699fab2022-09-08 08:46:06 -0600152 return request
Michael Mortensene87d8a62020-07-06 11:44:35 -0600153
Alex Klein1699fab2022-09-08 08:46:06 -0600154 def testValidateOnly(self):
Alex Kleinab87ceb2023-01-24 12:00:51 -0700155 """Verify a validate-only call does not execute any logic."""
Alex Klein1699fab2022-09-08 08:46:06 -0600156 patch = self.PatchObject(sdk_service, "Delete")
Michael Mortensene87d8a62020-07-06 11:44:35 -0600157
Alex Klein1699fab2022-09-08 08:46:06 -0600158 sdk_controller.Delete(
159 self._GetRequest(), self.response, self.validate_only_config
160 )
161 patch.assert_not_called()
Michael Mortensene87d8a62020-07-06 11:44:35 -0600162
Alex Klein1699fab2022-09-08 08:46:06 -0600163 def testMockCall(self):
164 """Sanity check that a mock call does not execute any logic."""
165 patch = self.PatchObject(sdk_service, "Delete")
Michael Mortensene87d8a62020-07-06 11:44:35 -0600166
Alex Klein1699fab2022-09-08 08:46:06 -0600167 rc = sdk_controller.Delete(
168 self._GetRequest(), self.response, self.mock_call_config
169 )
170 patch.assert_not_called()
171 self.assertFalse(rc)
Michael Mortensene87d8a62020-07-06 11:44:35 -0600172
Alex Klein1699fab2022-09-08 08:46:06 -0600173 def testSuccess(self):
174 """Test the successful call by verifying service invocation."""
175 patch = self.PatchObject(sdk_service, "Delete", return_value=1)
Michael Mortensene87d8a62020-07-06 11:44:35 -0600176
Alex Klein1699fab2022-09-08 08:46:06 -0600177 request = self._GetRequest()
Michael Mortensene87d8a62020-07-06 11:44:35 -0600178
Alex Klein1699fab2022-09-08 08:46:06 -0600179 sdk_controller.Delete(request, self.response, self.api_config)
180 # Verify that by default sdk_service.Delete is called with force=True.
181 patch.assert_called_once_with(mock.ANY, force=True)
Michael Mortensene87d8a62020-07-06 11:44:35 -0600182
183
Michael Mortensen52a98ac2020-07-28 16:00:18 -0600184class SdkUnmountPathTest(cros_test_lib.MockTestCase, api_config.ApiConfigMixin):
Alex Klein1699fab2022-09-08 08:46:06 -0600185 """Update tests."""
Michael Mortensen52a98ac2020-07-28 16:00:18 -0600186
Alex Klein1699fab2022-09-08 08:46:06 -0600187 def setUp(self):
188 """Setup method."""
189 self.response = sdk_pb2.UnmountPathResponse()
Michael Mortensen52a98ac2020-07-28 16:00:18 -0600190
Alex Klein1699fab2022-09-08 08:46:06 -0600191 def _UnmountPathRequest(self, path=None):
192 """Helper to build a delete request message."""
193 request = sdk_pb2.UnmountPathRequest()
194 if path:
195 request.path.path = path
196 return request
Michael Mortensen52a98ac2020-07-28 16:00:18 -0600197
Alex Klein1699fab2022-09-08 08:46:06 -0600198 def testValidateOnly(self):
Alex Kleinab87ceb2023-01-24 12:00:51 -0700199 """Verify a validate-only call does not execute any logic."""
Alex Klein1699fab2022-09-08 08:46:06 -0600200 patch = self.PatchObject(sdk_service, "UnmountPath")
Michael Mortensen52a98ac2020-07-28 16:00:18 -0600201
Alex Klein1699fab2022-09-08 08:46:06 -0600202 sdk_controller.UnmountPath(
203 self._UnmountPathRequest("/test/path"),
204 self.response,
205 self.validate_only_config,
206 )
207 patch.assert_not_called()
Michael Mortensen52a98ac2020-07-28 16:00:18 -0600208
Alex Klein1699fab2022-09-08 08:46:06 -0600209 def testMockCall(self):
210 """Sanity check that a mock call does not execute any logic."""
211 patch = self.PatchObject(sdk_service, "UnmountPath")
Michael Mortensen52a98ac2020-07-28 16:00:18 -0600212
Alex Klein1699fab2022-09-08 08:46:06 -0600213 rc = sdk_controller.UnmountPath(
214 self._UnmountPathRequest(), self.response, self.mock_call_config
215 )
216 patch.assert_not_called()
217 self.assertFalse(rc)
Michael Mortensen52a98ac2020-07-28 16:00:18 -0600218
Alex Klein1699fab2022-09-08 08:46:06 -0600219 def testSuccess(self):
220 """Test the successful call by verifying service invocation."""
221 patch = self.PatchObject(sdk_service, "UnmountPath", return_value=1)
Michael Mortensen52a98ac2020-07-28 16:00:18 -0600222
Alex Klein1699fab2022-09-08 08:46:06 -0600223 request = self._UnmountPathRequest("/test/path")
224 sdk_controller.UnmountPath(request, self.response, self.api_config)
225 patch.assert_called_once_with("/test/path")
Michael Mortensen52a98ac2020-07-28 16:00:18 -0600226
227
Alex Klein231d2da2019-07-22 16:44:45 -0600228class SdkUpdateTest(cros_test_lib.MockTestCase, api_config.ApiConfigMixin):
Alex Klein1699fab2022-09-08 08:46:06 -0600229 """Update tests."""
Alex Kleinaa5c4172019-02-27 17:12:20 -0700230
Alex Klein1699fab2022-09-08 08:46:06 -0600231 def setUp(self):
232 """Setup method."""
233 # We need to run the command inside the chroot.
234 self.PatchObject(cros_build_lib, "IsInsideChroot", return_value=True)
Alex Kleinaa5c4172019-02-27 17:12:20 -0700235
Alex Klein1699fab2022-09-08 08:46:06 -0600236 self.response = sdk_pb2.UpdateResponse()
Alex Klein231d2da2019-07-22 16:44:45 -0600237
Alex Klein1699fab2022-09-08 08:46:06 -0600238 def _GetRequest(self, build_source=False, targets=None):
239 """Helper to simplify building a request instance."""
240 request = sdk_pb2.UpdateRequest()
241 request.flags.build_source = build_source
Alex Kleinaa5c4172019-02-27 17:12:20 -0700242
Alex Klein1699fab2022-09-08 08:46:06 -0600243 for target in targets or []:
244 added = request.toolchain_targets.add()
245 added.name = target
Alex Kleinaa5c4172019-02-27 17:12:20 -0700246
Alex Klein1699fab2022-09-08 08:46:06 -0600247 return request
Alex Kleinaa5c4172019-02-27 17:12:20 -0700248
Alex Klein1699fab2022-09-08 08:46:06 -0600249 def testValidateOnly(self):
Alex Kleinab87ceb2023-01-24 12:00:51 -0700250 """Verify a validate-only call does not execute any logic."""
Alex Klein1699fab2022-09-08 08:46:06 -0600251 patch = self.PatchObject(sdk_service, "Update")
Alex Klein231d2da2019-07-22 16:44:45 -0600252
Alex Klein1699fab2022-09-08 08:46:06 -0600253 sdk_controller.Update(
254 self._GetRequest(), self.response, self.validate_only_config
255 )
256 patch.assert_not_called()
Alex Kleinaa5c4172019-02-27 17:12:20 -0700257
Alex Klein1699fab2022-09-08 08:46:06 -0600258 def testMockCall(self):
259 """Sanity check that a mock call does not execute any logic."""
260 patch = self.PatchObject(sdk_service, "Update")
Alex Klein076841b2019-08-29 15:19:39 -0600261
Alex Klein1699fab2022-09-08 08:46:06 -0600262 rc = sdk_controller.Create(
263 self._GetRequest(), self.response, self.mock_call_config
264 )
265 patch.assert_not_called()
266 self.assertFalse(rc)
267 self.assertTrue(self.response.version.version)
Alex Klein076841b2019-08-29 15:19:39 -0600268
Alex Klein1699fab2022-09-08 08:46:06 -0600269 def testSuccess(self):
270 """Successful call output handling test."""
271 expected_version = 1
272 self.PatchObject(sdk_service, "Update", return_value=expected_version)
273 request = self._GetRequest()
Alex Kleinaa5c4172019-02-27 17:12:20 -0700274
Alex Klein1699fab2022-09-08 08:46:06 -0600275 sdk_controller.Update(request, self.response, self.api_config)
Alex Kleinaa5c4172019-02-27 17:12:20 -0700276
Alex Klein1699fab2022-09-08 08:46:06 -0600277 self.assertEqual(expected_version, self.response.version.version)
Alex Kleinaa5c4172019-02-27 17:12:20 -0700278
Alex Klein1699fab2022-09-08 08:46:06 -0600279 def testArgumentHandling(self):
280 """Test the proto argument handling."""
281 args = sdk_service.UpdateArguments()
282 self.PatchObject(sdk_service, "Update", return_value=1)
283 args_patch = self.PatchObject(
284 sdk_service, "UpdateArguments", return_value=args
285 )
Alex Kleinaa5c4172019-02-27 17:12:20 -0700286
Alex Klein1699fab2022-09-08 08:46:06 -0600287 # No boards and flags False.
288 request = self._GetRequest(build_source=False)
289 sdk_controller.Update(request, self.response, self.api_config)
290 args_patch.assert_called_with(
291 build_source=False, toolchain_targets=[], toolchain_changed=False
292 )
Alex Kleinaa5c4172019-02-27 17:12:20 -0700293
Alex Klein1699fab2022-09-08 08:46:06 -0600294 # Multiple boards and flags True.
295 targets = ["board1", "board2"]
296 request = self._GetRequest(build_source=True, targets=targets)
297 sdk_controller.Update(request, self.response, self.api_config)
298 args_patch.assert_called_with(
299 build_source=True,
300 toolchain_targets=targets,
301 toolchain_changed=False,
302 )
Greg Edelston9dcdc8a2023-01-11 17:07:10 -0700303
304
Greg Edelston01ae5942023-01-30 16:26:54 -0700305class CreateManifestFromSdkTest(
306 cros_test_lib.MockTestCase, api_config.ApiConfigMixin
307):
308 """Test the SdkService/CreateManifestFromSdk endpoint."""
309
310 _chroot_path = "/path/to/chroot"
311 _sdk_path_relative = "build/my_sdk"
312 _dest_dir = "/build"
313 _manifest_path = "/build/my_sdk.Manifest"
314
315 def _NewRequest(self, inside: bool) -> sdk_pb2.CreateManifestFromSdkRequest:
316 return sdk_pb2.CreateManifestFromSdkRequest(
317 chroot=common_pb2.Chroot(path=self._chroot_path),
318 sdk_path=common_pb2.Path(
319 path="/%s" % self._sdk_path_relative,
320 location=common_pb2.Path.Location.INSIDE
321 if inside
322 else common_pb2.Path.Location.OUTSIDE,
323 ),
324 dest_dir=common_pb2.Path(
325 path=self._dest_dir,
326 location=common_pb2.Path.Location.OUTSIDE,
327 ),
328 )
329
330 def _NewResponse(self) -> sdk_pb2.CreateManifestFromSdkResponse:
331 return sdk_pb2.CreateManifestFromSdkResponse()
332
333 def testValidateOnly(self):
334 """Check that a validate only call does not execute any logic."""
335 impl_patch = self.PatchObject(sdk_service, "CreateManifestFromSdk")
336 sdk_controller.BuildSdkToolchain(
337 self._NewRequest(False),
338 self._NewResponse(),
339 self.validate_only_config,
340 )
341 impl_patch.assert_not_called()
342
343 def testOutside(self):
344 """Check that a call with an outside path succeeds."""
345 impl_patch = self.PatchObject(
346 sdk_service,
347 "CreateManifestFromSdk",
348 return_value=pathlib.Path(self._manifest_path),
349 )
350 request = self._NewRequest(inside=False)
351 response = self._NewResponse()
352 sdk_controller.CreateManifestFromSdk(
353 request,
354 response,
355 self.api_config,
356 )
357 impl_patch.assert_called_with(
358 pathlib.Path("/", self._sdk_path_relative),
359 pathlib.Path(self._dest_dir),
360 )
361 self.assertEqual(
362 response.manifest_path.location, common_pb2.Path.Location.OUTSIDE
363 )
364 self.assertEqual(response.manifest_path.path, self._manifest_path)
365
366 def testInside(self):
367 """Check that an inside path parses correctly and the call succeeds."""
368 impl_patch = self.PatchObject(
369 sdk_service,
370 "CreateManifestFromSdk",
371 return_value=pathlib.Path(self._manifest_path),
372 )
373 request = self._NewRequest(inside=True)
374 response = self._NewResponse()
375 sdk_controller.CreateManifestFromSdk(
376 request,
377 response,
378 self.api_config,
379 )
380 impl_patch.assert_called_with(
381 pathlib.Path(self._chroot_path, self._sdk_path_relative),
382 pathlib.Path(self._dest_dir),
383 )
384 self.assertEqual(
385 response.manifest_path.location, common_pb2.Path.Location.OUTSIDE
386 )
387 self.assertEqual(response.manifest_path.path, self._manifest_path)
388
389
Greg Edelston9dcdc8a2023-01-11 17:07:10 -0700390class BuildSdkToolchainTest(
391 cros_test_lib.MockTestCase, api_config.ApiConfigMixin
392):
393 """Test the SdkService/BuildSdkToolchain endpoint."""
394
395 def setUp(self):
396 """Set up the test case."""
397 self._chroot_path = "/path/to/chroot"
398 self._response = sdk_pb2.BuildSdkToolchainResponse()
399 self._generated_filenames = (
400 "armv7a-cros-linux-gnueabihf.tar.xz",
401 "x86_64-cros-linux-gnu.tar.xz",
402 )
403 self._paths_for_generated_files = [
404 common_pb2.Path(
405 path=os.path.join(constants.SDK_TOOLCHAINS_OUTPUT, fname),
406 location=common_pb2.Path.Location.INSIDE,
407 )
408 for fname in self._generated_filenames
409 ]
410
411 def _NewRequest(
412 self,
413 chroot_path: Optional[str] = None,
414 use_flags: Optional[List[str]] = None,
415 ) -> sdk_pb2.BuildSdkToolchainRequest:
416 """Return a new BuildSdkToolchainRequest message."""
417 request = sdk_pb2.BuildSdkToolchainRequest()
418 if chroot_path:
419 request.chroot.path = chroot_path
420 if use_flags:
421 request.use_flags.extend(
422 common_pb2.UseFlag(flag=flag) for flag in use_flags
423 )
424 return request
425
426 def _NewResponse(
427 self, generated_filenames: Optional[List[str]] = None
428 ) -> sdk_pb2.BuildSdkToolchainResponse:
429 """Return a new BuildSdkToolchainResponse message."""
430 response = sdk_pb2.BuildSdkToolchainResponse()
431 if generated_filenames:
432 response.generated_files.extend(
433 common_pb2.Path(
434 path=os.path.join(constants.SDK_TOOLCHAINS_OUTPUT, fname),
435 location=common_pb2.Path.Location.INSIDE,
436 )
437 for fname in generated_filenames
438 )
439 return response
440
441 def testValidateOnly(self):
442 """Check that a validate only call does not execute any logic."""
443 impl_patch = self.PatchObject(sdk_service, "BuildSdkToolchain")
444 sdk_controller.BuildSdkToolchain(
445 self._NewRequest(), self._NewResponse(), self.validate_only_config
446 )
447 impl_patch.assert_not_called()
448
449 def testSuccess(self):
450 """Check that a normal call defers to the SDK service as expected."""
451 impl_patch = self.PatchObject(sdk_service, "BuildSdkToolchain")
452 request = self._NewRequest(use_flags=[])
453 response = self._NewResponse()
454 sdk_controller.BuildSdkToolchain(
455 request,
456 response,
457 self.api_config,
458 )
459 # Can't use assert_called_with, since the chroot objects are equal but
460 # not identical.
461 impl_patch.assert_called_once()
462 self.assertEqual(
463 impl_patch.call_args.args[0],
464 controller_util.ParseChroot(request.chroot),
465 )
466 self.assertEqual(impl_patch.call_args.kwargs["extra_env"], {})
467
468 def testSuccessWithUseFlags(self):
469 """Check that a call with USE flags works as expected."""
470 impl_patch = self.PatchObject(sdk_service, "BuildSdkToolchain")
471 request = self._NewRequest(use_flags=["llvm-next", "another-flag"])
472 response = self._NewResponse()
473 sdk_controller.BuildSdkToolchain(
474 request,
475 response,
476 self.api_config,
477 )
478 # Can't use assert_called_with, since the chroot objects are equal but
479 # not identical.
480 impl_patch.assert_called_once()
481 self.assertEqual(
482 impl_patch.call_args.args[0],
483 controller_util.ParseChroot(request.chroot),
484 )
485 self.assertEqual(
486 impl_patch.call_args.kwargs["extra_env"],
487 {"USE": "llvm-next another-flag"},
488 )