xref: /aosp_15_r20/tools/acloud/internal/lib/android_build_client_test.py (revision 800a58d989c669b8eb8a71d8df53b1ba3d411444)
1#!/usr/bin/env python
2#
3# Copyright 2016 - The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#     http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17"""Tests for acloud.internal.lib.android_build_client."""
18
19import io
20import time
21
22import unittest
23
24from unittest import mock
25
26import apiclient
27
28from acloud import errors
29from acloud.internal import constants
30from acloud.internal.lib import android_build_client
31from acloud.internal.lib import driver_test_lib
32
33
34# pylint: disable=protected-access
35class AndroidBuildClientTest(driver_test_lib.BaseDriverTest):
36    """Test AndroidBuildClient."""
37
38    BUILD_BRANCH = "fake_branch"
39    BUILD_TARGET = "fake_target"
40    BUILD_ID = 12345
41    RESOURCE_ID = "avd-system.tar.gz"
42    LOCAL_DEST = "/fake/local/path"
43    DESTINATION_BUCKET = "fake_bucket"
44
45    def setUp(self):
46        """Set up test."""
47        super().setUp()
48        self.Patch(android_build_client.AndroidBuildClient,
49                   "InitResourceHandle")
50        self.client = android_build_client.AndroidBuildClient(mock.MagicMock())
51        self.client._service = mock.MagicMock()
52
53    # pylint: disable=no-member
54    def testDownloadArtifact(self):
55        """Test DownloadArtifact."""
56        # Create mocks.
57        mock_file = mock.MagicMock()
58        mock_file_io = mock.MagicMock()
59        mock_file_io.__enter__.return_value = mock_file
60        mock_downloader = mock.MagicMock()
61        mock_downloader.next_chunk = mock.MagicMock(
62            side_effect=[(mock.MagicMock(), False), (mock.MagicMock(), True)])
63        mock_api = mock.MagicMock()
64        self.Patch(io, "FileIO", return_value=mock_file_io)
65        self.Patch(
66            apiclient.http,
67            "MediaIoBaseDownload",
68            return_value=mock_downloader)
69        mock_resource = mock.MagicMock()
70        self.client._service.buildartifact = mock.MagicMock(
71            return_value=mock_resource)
72        mock_resource.get_media = mock.MagicMock(return_value=mock_api)
73        # Make the call to the api
74        self.client.DownloadArtifact(self.BUILD_TARGET, self.BUILD_ID,
75                                     self.RESOURCE_ID, self.LOCAL_DEST)
76        # Verify
77        mock_resource.get_media.assert_called_with(
78            buildId=self.BUILD_ID,
79            target=self.BUILD_TARGET,
80            attemptId="0",
81            resourceId=self.RESOURCE_ID)
82        io.FileIO.assert_called_with(self.LOCAL_DEST, mode="wb")
83        mock_call = mock.call(
84            mock_file,
85            mock_api,
86            chunksize=android_build_client.AndroidBuildClient.
87            DEFAULT_CHUNK_SIZE)
88        apiclient.http.MediaIoBaseDownload.assert_has_calls([mock_call])
89        self.assertEqual(mock_downloader.next_chunk.call_count, 2)
90
91    def testDownloadArtifactOSError(self):
92        """Test DownloadArtifact when OSError is raised."""
93        self.Patch(io, "FileIO", side_effect=OSError("fake OSError"))
94        self.assertRaises(errors.DriverError, self.client.DownloadArtifact,
95                          self.BUILD_TARGET, self.BUILD_ID, self.RESOURCE_ID,
96                          self.LOCAL_DEST)
97
98    def testCopyTo(self):
99        """Test CopyTo."""
100        mock_resource = mock.MagicMock()
101        self.client._service.buildartifact = mock.MagicMock(
102            return_value=mock_resource)
103        self.client.CopyTo(
104            build_target=self.BUILD_TARGET,
105            build_id=self.BUILD_ID,
106            artifact_name=self.RESOURCE_ID,
107            destination_bucket=self.DESTINATION_BUCKET,
108            destination_path=self.RESOURCE_ID)
109        mock_resource.copyTo.assert_called_once_with(
110            buildId=self.BUILD_ID,
111            target=self.BUILD_TARGET,
112            attemptId=self.client.DEFAULT_ATTEMPT_ID,
113            artifactName=self.RESOURCE_ID,
114            destinationBucket=self.DESTINATION_BUCKET,
115            destinationPath=self.RESOURCE_ID)
116
117    def testCopyToWithRetry(self):
118        """Test CopyTo with retry."""
119        self.Patch(time, "sleep")
120        mock_resource = mock.MagicMock()
121        mock_api_request = mock.MagicMock()
122        mock_resource.copyTo.return_value = mock_api_request
123        self.client._service.buildartifact.return_value = mock_resource
124        mock_api_request.execute.side_effect = errors.HttpError(503,
125                                                                "fake error")
126        self.assertRaises(
127            errors.HttpError,
128            self.client.CopyTo,
129            build_id=self.BUILD_ID,
130            build_target=self.BUILD_TARGET,
131            artifact_name=self.RESOURCE_ID,
132            destination_bucket=self.DESTINATION_BUCKET,
133            destination_path=self.RESOURCE_ID)
134        self.assertEqual(mock_api_request.execute.call_count, 6)
135
136    def testGetBranch(self):
137        """Test GetBuild."""
138        build_info = {"branch": "aosp-master"}
139        mock_api = mock.MagicMock()
140        mock_build = mock.MagicMock()
141        mock_build.get.return_value = mock_api
142        self.client._service.build = mock.MagicMock(return_value=mock_build)
143        mock_api.execute = mock.MagicMock(return_value=build_info)
144        branch = self.client.GetBranch(self.BUILD_TARGET, self.BUILD_ID)
145        mock_build.get.assert_called_once_with(
146            target=self.BUILD_TARGET,
147            buildId=self.BUILD_ID)
148        self.assertEqual(branch, build_info["branch"])
149
150    def testGetLKGB(self):
151        """Test GetLKGB."""
152        build_info = {"nextPageToken":"Test", "builds": [{"buildId": "3950000"}]}
153        mock_api = mock.MagicMock()
154        mock_build = mock.MagicMock()
155        mock_build.list.return_value = mock_api
156        self.client._service.build = mock.MagicMock(return_value=mock_build)
157        mock_api.execute = mock.MagicMock(return_value=build_info)
158        build_id = self.client.GetLKGB(self.BUILD_TARGET, self.BUILD_BRANCH)
159        mock_build.list.assert_called_once_with(
160            target=self.BUILD_TARGET,
161            branch=self.BUILD_BRANCH,
162            buildAttemptStatus=self.client.BUILD_STATUS_COMPLETE,
163            buildType=self.client.BUILD_TYPE_SUBMITTED,
164            maxResults=self.client.ONE_RESULT,
165            successful=self.client.BUILD_SUCCESSFUL)
166        self.assertEqual(build_id, build_info.get("builds")[0].get("buildId"))
167
168    def testGetFetchBuildArgs(self):
169        """Test GetFetchBuildArgs."""
170        default_build = {constants.BUILD_ID: "1234",
171                         constants.BUILD_BRANCH: "base_branch",
172                         constants.BUILD_TARGET: "base_target"}
173        system_build = {constants.BUILD_ID: "2345",
174                        constants.BUILD_BRANCH: "system_branch",
175                        constants.BUILD_TARGET: "system_target"}
176        kernel_build = {constants.BUILD_ID: "3456",
177                        constants.BUILD_BRANCH: "kernel_branch",
178                        constants.BUILD_TARGET: "kernel_target"}
179        ota_build = {constants.BUILD_ID: "4567",
180                     constants.BUILD_BRANCH: "ota_branch",
181                     constants.BUILD_TARGET: "ota_target"}
182        bootloader_build = {constants.BUILD_ID: "10111213",
183                            constants.BUILD_TARGET: "boot_crosvm_x86_64"}
184        android_efi_loader_build = {constants.BUILD_ID: "6789",
185                                    constants.BUILD_ARTIFACT: "gbl_x86_32.efi"}
186        boot_build = {constants.BUILD_ID: "5678",
187                      constants.BUILD_BRANCH: "boot_branch",
188                      constants.BUILD_TARGET: "boot_target",
189                      constants.BUILD_ARTIFACT: "boot-5.10.img"}
190        host_package_build = {constants.BUILD_ID: "6789",
191                              constants.BUILD_BRANCH: "host_package_branch",
192                              constants.BUILD_TARGET: "host_package_target"}
193
194        # Test base image.
195        expected_args = ["-default_build=1234/base_target"]
196        self.assertEqual(
197            expected_args,
198            self.client.GetFetchBuildArgs(
199                default_build, {}, {}, {}, {}, {}, {}, {}))
200
201        # Test base image with system image.
202        expected_args = ["-default_build=1234/base_target",
203                         "-system_build=2345/system_target"]
204        self.assertEqual(
205            expected_args,
206            self.client.GetFetchBuildArgs(
207                default_build, system_build, {}, {}, {}, {}, {}, {}))
208
209        # Test base image with kernel image.
210        expected_args = ["-default_build=1234/base_target",
211                         "-kernel_build=3456/kernel_target"]
212        self.assertEqual(
213            expected_args,
214            self.client.GetFetchBuildArgs(
215                default_build, {}, kernel_build, {}, {}, {}, {}, {}))
216
217        # Test base image with boot image.
218        expected_args = ["-default_build=1234/base_target",
219                         "-boot_build=5678/boot_target",
220                         "-boot_artifact=boot-5.10.img"]
221        self.assertEqual(
222            expected_args,
223            self.client.GetFetchBuildArgs(
224                default_build, {}, {}, boot_build, {}, {}, {}, {}))
225
226        # Test base image with bootloader.
227        expected_args = ["-default_build=1234/base_target",
228                         "-bootloader_build=10111213/boot_crosvm_x86_64"]
229        self.assertEqual(
230            expected_args,
231            self.client.GetFetchBuildArgs(
232                default_build, {}, {}, {}, bootloader_build, {}, {}, {}))
233
234        # Test base image with android efi.
235        expected_args = ["-default_build=1234/base_target",
236                         "-android_efi_loader_build 6789{gbl_x86_32.efi}"]
237        self.assertEqual(
238            expected_args,
239            self.client.GetFetchBuildArgs(
240                default_build, {}, {}, {}, {}, android_efi_loader_build, {}, {}))
241
242        # Test base image with otatools.
243        expected_args = ["-default_build=1234/base_target",
244                         "-otatools_build=4567/ota_target"]
245        self.assertEqual(
246            expected_args,
247            self.client.GetFetchBuildArgs(
248                default_build, {}, {}, {}, {}, {}, ota_build, {}))
249
250        # Test base image with host_package.
251        expected_args = ["-default_build=1234/base_target",
252                         "-host_package_build=6789/host_package_target"]
253        self.assertEqual(
254            expected_args,
255            self.client.GetFetchBuildArgs(
256                default_build, {}, {}, {}, {}, {}, {}, host_package_build))
257
258    def testGetFetchCertArg(self):
259        """Test GetFetchCertArg."""
260        cert_file_path = "fake_path"
261        certification = (
262            "{"
263            "  \"data\": ["
264            "    {"
265            "      \"credential\": {"
266            "        \"access_token\": \"fake_token\""
267            "      }"
268            "    }"
269            "  ]"
270            "}"
271        )
272        expected_arg = "-credential_source=fake_token"
273        with mock.patch("builtins.open",
274                        mock.mock_open(read_data=certification)):
275            cert_arg = self.client.GetFetchCertArg(cert_file_path)
276            self.assertEqual(expected_arg, cert_arg)
277
278    def testProcessBuild(self):
279        """Test creating "cuttlefish build" strings."""
280        build_id = constants.BUILD_ID
281        branch = constants.BUILD_BRANCH
282        build_target = constants.BUILD_TARGET
283        self.assertEqual(
284            self.client.ProcessBuild(
285                {build_id: "123", branch: "abc", build_target: "def"}),
286            "123/def")
287        self.assertEqual(
288            self.client.ProcessBuild(
289                {build_id: None, branch: "abc", build_target: "def"}),
290            "abc/def")
291        self.assertEqual(
292            self.client.ProcessBuild(
293                {build_id: "123", branch: None, build_target: "def"}),
294            "123/def")
295        self.assertEqual(
296            self.client.ProcessBuild(
297                {build_id: "123", branch: "abc", build_target: None}),
298            "123")
299        self.assertEqual(
300            self.client.ProcessBuild(
301                {build_id: None, branch: "abc", build_target: None}),
302            "abc")
303        self.assertEqual(
304            self.client.ProcessBuild(
305                {build_id: "123", branch: None, build_target: None}),
306            "123")
307        self.assertEqual(
308            self.client.ProcessBuild(
309                {build_id: None, branch: None, build_target: None}),
310            None)
311
312
313if __name__ == "__main__":
314    unittest.main()
315