blob: ddd5889f10e2cf7c9a1bea68bd1829525c00bf49 [file] [log] [blame]
Evan Hernandezd437b4e2019-03-25 13:48:30 -06001# -*- coding: utf-8 -*-
2# Copyright 2019 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Unittests for Binhost operations."""
7
8from __future__ import print_function
9
Michael Mortensenfc823882019-08-27 14:38:07 -060010import os
Mike Frysingeref94e4c2020-02-10 23:59:54 -050011import sys
12
Alex Klein82c85d42019-08-14 15:47:51 -060013import mock
14
Alex Klein231d2da2019-07-22 16:44:45 -060015from chromite.api import api_config
Evan Hernandezd437b4e2019-03-25 13:48:30 -060016from chromite.api.controller import binhost
17from chromite.api.gen.chromite.api import binhost_pb2
LaMont Jonesc64ae212019-04-15 15:41:28 -060018from chromite.lib import cros_build_lib
Evan Hernandezd437b4e2019-03-25 13:48:30 -060019from chromite.lib import cros_test_lib
Michael Mortensenfc823882019-08-27 14:38:07 -060020from chromite.lib import osutils
Evan Hernandezd437b4e2019-03-25 13:48:30 -060021from chromite.service import binhost as binhost_service
22
Alex Klein231d2da2019-07-22 16:44:45 -060023
Mike Frysingeref94e4c2020-02-10 23:59:54 -050024assert sys.version_info >= (3, 6), 'This module requires Python 3.6+'
25
26
Michael Mortensena0af77b2019-11-13 11:15:15 -070027class GetBinhostsTest(cros_test_lib.MockTestCase, api_config.ApiConfigMixin):
28 """Unittests for GetBinhosts."""
29
30 def setUp(self):
31 self.response = binhost_pb2.BinhostGetResponse()
32
33 def testValidateOnly(self):
34 """Sanity check that a validate only call does not execute any logic."""
35 patch = self.PatchObject(binhost_service, 'GetBinhosts')
36
Michael Mortensen42251f92019-11-14 11:01:43 -070037 request = binhost_pb2.BinhostGetRequest()
Michael Mortensena0af77b2019-11-13 11:15:15 -070038 request.build_target.name = 'target'
39 binhost.GetBinhosts(request, self.response, self.validate_only_config)
40 patch.assert_not_called()
41
42 def testMockCall(self):
43 """Test that a mock call does not execute logic, returns mocked value."""
44 patch = self.PatchObject(binhost_service, 'GetBinhosts')
45
46 input_proto = binhost_pb2.BinhostGetRequest()
47 input_proto.build_target.name = 'target'
48
49 binhost.GetBinhosts(input_proto, self.response, self.mock_call_config)
50
51 self.assertEqual(len(self.response.binhosts), 1)
52 self.assertEqual(self.response.binhosts[0].package_index, 'Packages')
53 patch.assert_not_called()
54
55 def testGetBinhosts(self):
56 """GetBinhosts calls service with correct args."""
57 binhost_list = [
58 'gs://cr-prebuilt/board/amd64-generic/paladin-R66-17.0.0-rc2/packages/',
59 'gs://cr-prebuilt/board/eve/paladin-R66-17.0.0-rc2/packages/']
60 get_binhost = self.PatchObject(binhost_service, 'GetBinhosts',
61 return_value=binhost_list)
62
63 input_proto = binhost_pb2.BinhostGetRequest()
64 input_proto.build_target.name = 'target'
65
66 binhost.GetBinhosts(input_proto, self.response, self.api_config)
67
68 self.assertEqual(len(self.response.binhosts), 2)
69 self.assertEqual(self.response.binhosts[0].package_index, 'Packages')
70 get_binhost.assert_called_once_with(mock.ANY)
71
72
Michael Mortensen42251f92019-11-14 11:01:43 -070073class GetPrivatePrebuiltAclArgsTest(cros_test_lib.MockTestCase,
74 api_config.ApiConfigMixin):
75 """Unittests for GetPrivatePrebuiltAclArgs."""
76
77 def setUp(self):
78 self.response = binhost_pb2.AclArgsResponse()
79
80 def testValidateOnly(self):
81 """Sanity check that a validate only call does not execute any logic."""
82 patch = self.PatchObject(binhost_service, 'GetPrebuiltAclArgs')
83
84 request = binhost_pb2.AclArgsRequest()
85 request.build_target.name = 'target'
86 binhost.GetPrivatePrebuiltAclArgs(request, self.response,
87 self.validate_only_config)
88 patch.assert_not_called()
89
90 def testMockCall(self):
91 """Test that a mock call does not execute logic, returns mocked value."""
92 patch = self.PatchObject(binhost_service, 'GetPrebuiltAclArgs')
93
94 input_proto = binhost_pb2.AclArgsRequest()
95 input_proto.build_target.name = 'target'
96
97 binhost.GetPrivatePrebuiltAclArgs(input_proto, self.response,
98 self.mock_call_config)
99
100 self.assertEqual(len(self.response.args), 1)
101 self.assertEqual(self.response.args[0].arg, '-g')
102 self.assertEqual(self.response.args[0].value, 'group1:READ')
103 patch.assert_not_called()
104
105 def testGetPrivatePrebuiltAclArgs(self):
106 """GetPrivatePrebuildAclsArgs calls service with correct args."""
107 argvalue_list = [['-g', 'group1:READ']]
108 get_binhost = self.PatchObject(binhost_service, 'GetPrebuiltAclArgs',
109 return_value=argvalue_list)
110
111 input_proto = binhost_pb2.AclArgsRequest()
112 input_proto.build_target.name = 'target'
113
114 binhost.GetPrivatePrebuiltAclArgs(input_proto, self.response,
115 self.api_config)
116
117 self.assertEqual(len(self.response.args), 1)
118 self.assertEqual(self.response.args[0].arg, '-g')
119 self.assertEqual(self.response.args[0].value, 'group1:READ')
120 get_binhost.assert_called_once_with(mock.ANY)
121
122
Alex Klein231d2da2019-07-22 16:44:45 -0600123class PrepareBinhostUploadsTest(cros_test_lib.MockTestCase,
124 api_config.ApiConfigMixin):
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600125 """Unittests for PrepareBinhostUploads."""
126
127 def setUp(self):
128 self.PatchObject(binhost_service, 'GetPrebuiltsRoot',
129 return_value='/build/target/packages')
130 self.PatchObject(binhost_service, 'GetPrebuiltsFiles',
131 return_value=['foo.tbz2', 'bar.tbz2'])
132 self.PatchObject(binhost_service, 'UpdatePackageIndex',
133 return_value='/build/target/packages/Packages')
134
Alex Klein231d2da2019-07-22 16:44:45 -0600135 self.response = binhost_pb2.PrepareBinhostUploadsResponse()
136
137 def testValidateOnly(self):
138 """Sanity check that a validate only call does not execute any logic."""
139 patch = self.PatchObject(binhost_service, 'GetPrebuiltsRoot')
140
141 request = binhost_pb2.PrepareBinhostUploadsRequest()
142 request.build_target.name = 'target'
143 request.uri = 'gs://chromeos-prebuilt/target'
144 rc = binhost.PrepareBinhostUploads(request, self.response,
145 self.validate_only_config)
146 patch.assert_not_called()
147 self.assertEqual(rc, 0)
148
Michael Mortensen42251f92019-11-14 11:01:43 -0700149 def testMockCall(self):
150 """Test that a mock call does not execute logic, returns mocked value."""
151 patch = self.PatchObject(binhost_service, 'GetPrebuiltsRoot')
152
153 request = binhost_pb2.PrepareBinhostUploadsRequest()
154 request.build_target.name = 'target'
155 request.uri = 'gs://chromeos-prebuilt/target'
156 rc = binhost.PrepareBinhostUploads(request, self.response,
157 self.mock_call_config)
158 self.assertEqual(self.response.uploads_dir, '/upload/directory')
159 self.assertEqual(self.response.upload_targets[0].path, 'upload_target')
160 patch.assert_not_called()
161 self.assertEqual(rc, 0)
162
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600163 def testPrepareBinhostUploads(self):
164 """PrepareBinhostUploads returns Packages and tar files."""
165 input_proto = binhost_pb2.PrepareBinhostUploadsRequest()
166 input_proto.build_target.name = 'target'
167 input_proto.uri = 'gs://chromeos-prebuilt/target'
Alex Klein231d2da2019-07-22 16:44:45 -0600168 binhost.PrepareBinhostUploads(input_proto, self.response, self.api_config)
169 self.assertEqual(self.response.uploads_dir, '/build/target/packages')
Mike Frysinger678735c2019-09-28 18:23:28 -0400170 self.assertCountEqual(
Alex Klein231d2da2019-07-22 16:44:45 -0600171 [ut.path for ut in self.response.upload_targets],
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600172 ['Packages', 'foo.tbz2', 'bar.tbz2'])
173
174 def testPrepareBinhostUploadsNonGsUri(self):
175 """PrepareBinhostUploads dies when URI does not point to GS."""
176 input_proto = binhost_pb2.PrepareBinhostUploadsRequest()
177 input_proto.build_target.name = 'target'
178 input_proto.uri = 'https://foo.bar'
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600179 with self.assertRaises(ValueError):
Alex Klein231d2da2019-07-22 16:44:45 -0600180 binhost.PrepareBinhostUploads(input_proto, self.response, self.api_config)
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600181
182
Alex Klein231d2da2019-07-22 16:44:45 -0600183class SetBinhostTest(cros_test_lib.MockTestCase, api_config.ApiConfigMixin):
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600184 """Unittests for SetBinhost."""
185
Alex Klein231d2da2019-07-22 16:44:45 -0600186 def setUp(self):
187 self.response = binhost_pb2.SetBinhostResponse()
188
189 def testValidateOnly(self):
190 """Sanity check that a validate only call does not execute any logic."""
Michael Mortensen42251f92019-11-14 11:01:43 -0700191 patch = self.PatchObject(binhost_service, 'SetBinhost')
Alex Klein231d2da2019-07-22 16:44:45 -0600192
Michael Mortensen42251f92019-11-14 11:01:43 -0700193 request = binhost_pb2.SetBinhostRequest()
Alex Klein231d2da2019-07-22 16:44:45 -0600194 request.build_target.name = 'target'
Michael Mortensen42251f92019-11-14 11:01:43 -0700195 request.key = binhost_pb2.POSTSUBMIT_BINHOST
Alex Klein231d2da2019-07-22 16:44:45 -0600196 request.uri = 'gs://chromeos-prebuilt/target'
Michael Mortensen42251f92019-11-14 11:01:43 -0700197 binhost.SetBinhost(request, self.response, self.validate_only_config)
Alex Klein231d2da2019-07-22 16:44:45 -0600198 patch.assert_not_called()
199
Michael Mortensen42251f92019-11-14 11:01:43 -0700200 def testMockCall(self):
201 """Test that a mock call does not execute logic, returns mocked value."""
202 patch = self.PatchObject(binhost_service, 'SetBinhost')
203
204 request = binhost_pb2.SetBinhostRequest()
205 request.build_target.name = 'target'
206 request.key = binhost_pb2.POSTSUBMIT_BINHOST
207 request.uri = 'gs://chromeos-prebuilt/target'
208 binhost.SetBinhost(request, self.response, self.mock_call_config)
209 patch.assert_not_called()
210 self.assertEqual(self.response.output_file, '/path/to/BINHOST.conf')
211
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600212 def testSetBinhost(self):
213 """SetBinhost calls service with correct args."""
214 set_binhost = self.PatchObject(binhost_service, 'SetBinhost',
215 return_value='/path/to/BINHOST.conf')
216
217 input_proto = binhost_pb2.SetBinhostRequest()
218 input_proto.build_target.name = 'target'
219 input_proto.private = True
220 input_proto.key = binhost_pb2.POSTSUBMIT_BINHOST
221 input_proto.uri = 'gs://chromeos-prebuilt/target'
222
Alex Klein231d2da2019-07-22 16:44:45 -0600223 binhost.SetBinhost(input_proto, self.response, self.api_config)
Evan Hernandezd437b4e2019-03-25 13:48:30 -0600224
Alex Klein231d2da2019-07-22 16:44:45 -0600225 self.assertEqual(self.response.output_file, '/path/to/BINHOST.conf')
LaMont Jonesc64ae212019-04-15 15:41:28 -0600226 set_binhost.assert_called_once_with(
Alex Kleinc010de02019-10-11 15:44:04 -0600227 'target',
228 'POSTSUBMIT_BINHOST',
229 'gs://chromeos-prebuilt/target',
230 private=True)
LaMont Jonesc64ae212019-04-15 15:41:28 -0600231
Alex Klein231d2da2019-07-22 16:44:45 -0600232
233class RegenBuildCacheTest(cros_test_lib.MockTestCase,
234 api_config.ApiConfigMixin):
LaMont Jonesc64ae212019-04-15 15:41:28 -0600235 """Unittests for RegenBuildCache."""
236
Alex Klein231d2da2019-07-22 16:44:45 -0600237 def setUp(self):
238 self.response = binhost_pb2.RegenBuildCacheResponse()
239
240 def testValidateOnly(self):
241 """Sanity check that a validate only call does not execute any logic."""
242 patch = self.PatchObject(binhost_service, 'RegenBuildCache')
243
244 request = binhost_pb2.RegenBuildCacheRequest()
245 request.overlay_type = binhost_pb2.OVERLAYTYPE_BOTH
246 binhost.RegenBuildCache(request, self.response, self.validate_only_config)
247 patch.assert_not_called()
248
Michael Mortensen42251f92019-11-14 11:01:43 -0700249 def testMockCall(self):
250 """Test that a mock call does not execute logic, returns mocked value."""
251 patch = self.PatchObject(binhost_service, 'RegenBuildCache')
252
253 request = binhost_pb2.RegenBuildCacheRequest()
254 request.overlay_type = binhost_pb2.OVERLAYTYPE_BOTH
255 binhost.RegenBuildCache(request, self.response, self.mock_call_config)
256 patch.assert_not_called()
257 self.assertEqual(len(self.response.modified_overlays), 1)
258 self.assertEqual(self.response.modified_overlays[0].path,
259 '/path/to/BuildCache')
260
261
LaMont Jonesc64ae212019-04-15 15:41:28 -0600262 def testRegenBuildCache(self):
263 """RegenBuildCache calls service with the correct args."""
264 regen_cache = self.PatchObject(binhost_service, 'RegenBuildCache')
265
266 input_proto = binhost_pb2.RegenBuildCacheRequest()
267 input_proto.overlay_type = binhost_pb2.OVERLAYTYPE_BOTH
LaMont Jonesc64ae212019-04-15 15:41:28 -0600268
Alex Klein231d2da2019-07-22 16:44:45 -0600269 binhost.RegenBuildCache(input_proto, self.response, self.api_config)
Alex Klein82c85d42019-08-14 15:47:51 -0600270 regen_cache.assert_called_once_with(mock.ANY, 'both')
LaMont Jonesc64ae212019-04-15 15:41:28 -0600271
272 def testRequiresOverlayType(self):
273 """RegenBuildCache dies if overlay_type not specified."""
274 regen_cache = self.PatchObject(binhost_service, 'RegenBuildCache')
LaMont Jonesc64ae212019-04-15 15:41:28 -0600275
276 input_proto = binhost_pb2.RegenBuildCacheRequest()
277 input_proto.overlay_type = binhost_pb2.OVERLAYTYPE_UNSPECIFIED
LaMont Jonesc64ae212019-04-15 15:41:28 -0600278
Alex Klein231d2da2019-07-22 16:44:45 -0600279 with self.assertRaises(cros_build_lib.DieSystemExit):
280 binhost.RegenBuildCache(input_proto, self.response, self.api_config)
LaMont Jonesc64ae212019-04-15 15:41:28 -0600281 regen_cache.assert_not_called()
Michael Mortensenfc823882019-08-27 14:38:07 -0600282
283
284class PrepareDevInstallerBinhostUploadsTest(cros_test_lib.MockTempDirTestCase,
285 api_config.ApiConfigMixin):
286 """Tests for the UploadDevInstallerPrebuilts stage."""
287 def setUp(self):
288 # target packages dir
289 self.chroot_path = os.path.join(self.tempdir, 'chroot')
290 self.sysroot_path = '/build/target'
291 self.chroot_path = os.path.join(self.tempdir, 'chroot')
292 full_sysroot_path = os.path.join(self.chroot_path,
293 self.sysroot_path.lstrip(os.sep))
294 self.full_sysroot_package_path = os.path.join(full_sysroot_path,
295 'packages')
296 osutils.SafeMakedirs(self.full_sysroot_package_path)
297 self.uploads_dir = os.path.join(self.tempdir, 'uploads_dir')
298 osutils.SafeMakedirs(self.uploads_dir)
299 # Create packages/Packages file
300 packages_file = os.path.join(self.full_sysroot_package_path, 'Packages')
301 packages_content = """\
302USE: test
303
304CPV: app-arch/brotli-1.0.6
305
306CPV: app-arch/zip-3.0-r3
307
308CPV: chromeos-base/shill-0.0.1-r1
309
310CPV: chromeos-base/test-0.0.1-r1
311
312CPV: virtual/chromium-os-printing-1-r4
313
314CPV: virtual/python-enum34-1
315
316"""
317 osutils.WriteFile(packages_file, packages_content)
318
319
320 # Create package.installable file
321 self.dev_install_packages = ['app-arch/zip-3.0-r3',
322 'virtual/chromium-os-printing-1-r4',
323 'virtual/python-enum34-1']
324 package_installable_dir = os.path.join(full_sysroot_path,
325 'build/dev-install')
326 osutils.SafeMakedirs(package_installable_dir)
327 package_installable_filename = os.path.join(package_installable_dir,
328 'package.installable')
329
330 # Create path to the dev_install_packages
331 packages_dir = os.path.join(full_sysroot_path, 'packages')
332 osutils.SafeMakedirs(packages_dir)
333 for package in self.dev_install_packages:
334 # Since a package has a category, such as app-arch/zip-3.0-r3, we need
335 # to create the packages_dir / category dir as needed.
336 category = package.split(os.sep)[0]
337 osutils.SafeMakedirs(os.path.join(packages_dir, category))
338 package_tbz2_file = os.path.join(packages_dir, package) + '.tbz2'
339 osutils.Touch(package_tbz2_file)
340 package_installable_file = open(package_installable_filename, 'w')
341 for package in self.dev_install_packages:
342 package_installable_file.write(package + '\n')
343 package_installable_file.close()
344 self.response = binhost_pb2.PrepareDevInstallBinhostUploadsResponse()
345
Michael Mortensen42251f92019-11-14 11:01:43 -0700346 def testValidateOnly(self):
347 """Sanity check that a validate only call does not execute any logic."""
348 patch = self.PatchObject(binhost_service,
349 'ReadDevInstallFilesToCreatePackageIndex')
350
351 input_proto = binhost_pb2.PrepareDevInstallBinhostUploadsRequest()
352 input_proto.uri = 'gs://chromeos-prebuilt/target'
353 input_proto.chroot.path = self.chroot_path
354 input_proto.sysroot.path = self.sysroot_path
355 input_proto.uploads_dir = self.uploads_dir
356 binhost.PrepareDevInstallBinhostUploads(input_proto, self.response,
357 self.validate_only_config)
358 patch.assert_not_called()
359
360 def testMockCall(self):
361 """Test that a mock call does not execute logic, returns mocked value."""
362 patch = self.PatchObject(binhost_service,
363 'ReadDevInstallFilesToCreatePackageIndex')
364
365 input_proto = binhost_pb2.PrepareDevInstallBinhostUploadsRequest()
366 input_proto.uri = 'gs://chromeos-prebuilt/target'
367 input_proto.chroot.path = self.chroot_path
368 input_proto.sysroot.path = self.sysroot_path
369 input_proto.uploads_dir = self.uploads_dir
370 binhost.PrepareDevInstallBinhostUploads(input_proto, self.response,
371 self.mock_call_config)
372 self.assertEqual(len(self.response.upload_targets), 3)
373 self.assertEqual(self.response.upload_targets[2].path, 'Packages')
374 patch.assert_not_called()
375
Michael Mortensenfc823882019-08-27 14:38:07 -0600376 def testDevInstallerUpload(self):
377 """Basic sanity test testing uploads of dev installer prebuilts."""
378 # self.RunStage()
379 input_proto = binhost_pb2.PrepareDevInstallBinhostUploadsRequest()
380 input_proto.uri = 'gs://chromeos-prebuilt/target'
381 input_proto.chroot.path = self.chroot_path
382 input_proto.sysroot.path = self.sysroot_path
383 input_proto.uploads_dir = self.uploads_dir
384 # Call method under test
385 binhost.PrepareDevInstallBinhostUploads(input_proto, self.response,
386 self.api_config)
387 # Verify results
388 expected_upload_targets = ['app-arch/zip-3.0-r3.tbz2',
389 'virtual/chromium-os-printing-1-r4.tbz2',
390 'virtual/python-enum34-1.tbz2',
391 'Packages']
Mike Frysinger678735c2019-09-28 18:23:28 -0400392 self.assertCountEqual(
Michael Mortensenfc823882019-08-27 14:38:07 -0600393 [ut.path for ut in self.response.upload_targets],
394 expected_upload_targets)
395 # All of the upload_targets should also be in the uploads_directory
396 for target in self.response.upload_targets:
397 self.assertExists(os.path.join(input_proto.uploads_dir, target.path))
398
399 def testPrepareBinhostUploadsNonGsUri(self):
400 """PrepareBinhostUploads dies when URI does not point to GS."""
401 input_proto = binhost_pb2.PrepareDevInstallBinhostUploadsRequest()
402 input_proto.chroot.path = self.chroot_path
403 input_proto.sysroot.path = self.sysroot_path
404 input_proto.uploads_dir = self.uploads_dir
405 input_proto.uri = 'https://foo.bar'
406 with self.assertRaises(ValueError):
407 binhost.PrepareDevInstallBinhostUploads(input_proto, self.response,
408 self.api_config)