xref: /aosp_15_r20/tools/acloud/internal/lib/cvd_utils_test.py (revision 800a58d989c669b8eb8a71d8df53b1ba3d411444)
1*800a58d9SAndroid Build Coastguard Worker# Copyright 2022 - The Android Open Source Project
2*800a58d9SAndroid Build Coastguard Worker#
3*800a58d9SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
4*800a58d9SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
5*800a58d9SAndroid Build Coastguard Worker# You may obtain a copy of the License at
6*800a58d9SAndroid Build Coastguard Worker#
7*800a58d9SAndroid Build Coastguard Worker#     http://www.apache.org/licenses/LICENSE-2.0
8*800a58d9SAndroid Build Coastguard Worker#
9*800a58d9SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
10*800a58d9SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
11*800a58d9SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*800a58d9SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
13*800a58d9SAndroid Build Coastguard Worker# limitations under the License.
14*800a58d9SAndroid Build Coastguard Worker
15*800a58d9SAndroid Build Coastguard Worker"""Tests for cvd_utils."""
16*800a58d9SAndroid Build Coastguard Worker
17*800a58d9SAndroid Build Coastguard Workerimport os
18*800a58d9SAndroid Build Coastguard Workerimport subprocess
19*800a58d9SAndroid Build Coastguard Workerimport tempfile
20*800a58d9SAndroid Build Coastguard Workerimport unittest
21*800a58d9SAndroid Build Coastguard Workerfrom unittest import mock
22*800a58d9SAndroid Build Coastguard Workerimport zipfile
23*800a58d9SAndroid Build Coastguard Worker
24*800a58d9SAndroid Build Coastguard Workerfrom acloud import errors
25*800a58d9SAndroid Build Coastguard Workerfrom acloud.create import create_common
26*800a58d9SAndroid Build Coastguard Workerfrom acloud.internal import constants
27*800a58d9SAndroid Build Coastguard Workerfrom acloud.internal.lib import cvd_utils
28*800a58d9SAndroid Build Coastguard Workerfrom acloud.internal.lib import driver_test_lib
29*800a58d9SAndroid Build Coastguard Worker
30*800a58d9SAndroid Build Coastguard Worker
31*800a58d9SAndroid Build Coastguard Worker# pylint: disable=too-many-public-methods
32*800a58d9SAndroid Build Coastguard Workerclass CvdUtilsTest(driver_test_lib.BaseDriverTest):
33*800a58d9SAndroid Build Coastguard Worker    """Test the functions in cvd_utils."""
34*800a58d9SAndroid Build Coastguard Worker
35*800a58d9SAndroid Build Coastguard Worker    # Remote host instance name.
36*800a58d9SAndroid Build Coastguard Worker    _PRODUCT_NAME = "aosp_cf_x86_64_phone"
37*800a58d9SAndroid Build Coastguard Worker    _BUILD_ID = "2263051"
38*800a58d9SAndroid Build Coastguard Worker    _REMOTE_HOSTNAME_1 = "192.0.2.1"
39*800a58d9SAndroid Build Coastguard Worker    _REMOTE_HOSTNAME_2 = "host.NAME-1234"
40*800a58d9SAndroid Build Coastguard Worker    _REMOTE_HOST_INSTANCE_NAME_1 = (
41*800a58d9SAndroid Build Coastguard Worker        "host-192.0.2.1-1-2263051-aosp_cf_x86_64_phone")
42*800a58d9SAndroid Build Coastguard Worker    _REMOTE_HOST_INSTANCE_NAME_2 = (
43*800a58d9SAndroid Build Coastguard Worker        "host-host.NAME_1234-2-2263051-aosp_cf_x86_64_phone")
44*800a58d9SAndroid Build Coastguard Worker
45*800a58d9SAndroid Build Coastguard Worker    def testGetAdbPorts(self):
46*800a58d9SAndroid Build Coastguard Worker        """Test GetAdbPorts."""
47*800a58d9SAndroid Build Coastguard Worker        self.assertEqual([6520], cvd_utils.GetAdbPorts(None, None))
48*800a58d9SAndroid Build Coastguard Worker        self.assertEqual([6520], cvd_utils.GetAdbPorts(1, 1))
49*800a58d9SAndroid Build Coastguard Worker        self.assertEqual([6521, 6522], cvd_utils.GetAdbPorts(2, 2))
50*800a58d9SAndroid Build Coastguard Worker
51*800a58d9SAndroid Build Coastguard Worker    def testGetVncPorts(self):
52*800a58d9SAndroid Build Coastguard Worker        """Test GetVncPorts."""
53*800a58d9SAndroid Build Coastguard Worker        self.assertEqual([6444], cvd_utils.GetVncPorts(None, None))
54*800a58d9SAndroid Build Coastguard Worker        self.assertEqual([6444], cvd_utils.GetVncPorts(1, 1))
55*800a58d9SAndroid Build Coastguard Worker        self.assertEqual([6445, 6446], cvd_utils.GetVncPorts(2, 2))
56*800a58d9SAndroid Build Coastguard Worker
57*800a58d9SAndroid Build Coastguard Worker    def testExtractTargetFilesZip(self):
58*800a58d9SAndroid Build Coastguard Worker        """Test ExtractTargetFilesZip."""
59*800a58d9SAndroid Build Coastguard Worker        with tempfile.TemporaryDirectory() as temp_dir:
60*800a58d9SAndroid Build Coastguard Worker            zip_path = os.path.join(temp_dir, "in.zip")
61*800a58d9SAndroid Build Coastguard Worker            output_dir = os.path.join(temp_dir, "out")
62*800a58d9SAndroid Build Coastguard Worker            with zipfile.ZipFile(zip_path, "w") as zip_file:
63*800a58d9SAndroid Build Coastguard Worker                for entry in ["IMAGES/", "META/", "test.img",
64*800a58d9SAndroid Build Coastguard Worker                              "IMAGES/system.img", "IMAGES/system.map",
65*800a58d9SAndroid Build Coastguard Worker                              "IMAGES/bootloader", "IMAGES/kernel",
66*800a58d9SAndroid Build Coastguard Worker                              "META/misc_info.txt"]:
67*800a58d9SAndroid Build Coastguard Worker                    zip_file.writestr(entry, "")
68*800a58d9SAndroid Build Coastguard Worker            cvd_utils.ExtractTargetFilesZip(zip_path, output_dir)
69*800a58d9SAndroid Build Coastguard Worker
70*800a58d9SAndroid Build Coastguard Worker            self.assertEqual(["IMAGES", "META"],
71*800a58d9SAndroid Build Coastguard Worker                             sorted(os.listdir(output_dir)))
72*800a58d9SAndroid Build Coastguard Worker            self.assertEqual(
73*800a58d9SAndroid Build Coastguard Worker                ["bootloader", "kernel", "system.img"],
74*800a58d9SAndroid Build Coastguard Worker                sorted(os.listdir(os.path.join(output_dir, "IMAGES"))))
75*800a58d9SAndroid Build Coastguard Worker            self.assertEqual(["misc_info.txt"],
76*800a58d9SAndroid Build Coastguard Worker                             os.listdir(os.path.join(output_dir, "META")))
77*800a58d9SAndroid Build Coastguard Worker
78*800a58d9SAndroid Build Coastguard Worker    @staticmethod
79*800a58d9SAndroid Build Coastguard Worker    @mock.patch("acloud.internal.lib.cvd_utils.os.path.isdir",
80*800a58d9SAndroid Build Coastguard Worker                return_value=False)
81*800a58d9SAndroid Build Coastguard Worker    def testUploadImageZip(_mock_isdir):
82*800a58d9SAndroid Build Coastguard Worker        """Test UploadArtifacts with image zip."""
83*800a58d9SAndroid Build Coastguard Worker        mock_ssh = mock.Mock()
84*800a58d9SAndroid Build Coastguard Worker        cvd_utils.UploadArtifacts(mock_ssh, "dir", "/mock/img.zip",
85*800a58d9SAndroid Build Coastguard Worker                                  "/mock/cvd.tar.gz")
86*800a58d9SAndroid Build Coastguard Worker        mock_ssh.Run.assert_any_call("/usr/bin/install_zip.sh dir < "
87*800a58d9SAndroid Build Coastguard Worker                                     "/mock/img.zip")
88*800a58d9SAndroid Build Coastguard Worker        mock_ssh.Run.assert_any_call("tar -xzf - -C dir < /mock/cvd.tar.gz")
89*800a58d9SAndroid Build Coastguard Worker
90*800a58d9SAndroid Build Coastguard Worker    @mock.patch("acloud.internal.lib.cvd_utils.glob")
91*800a58d9SAndroid Build Coastguard Worker    @mock.patch("acloud.internal.lib.cvd_utils.os.path.isdir")
92*800a58d9SAndroid Build Coastguard Worker    @mock.patch("acloud.internal.lib.cvd_utils.ssh.ShellCmdWithRetry")
93*800a58d9SAndroid Build Coastguard Worker    def testUploadImageDir(self, mock_shell, mock_isdir, mock_glob):
94*800a58d9SAndroid Build Coastguard Worker        """Test UploadArtifacts with image directory."""
95*800a58d9SAndroid Build Coastguard Worker        mock_isdir.side_effect = lambda path: path != "/mock/cvd.tar.gz"
96*800a58d9SAndroid Build Coastguard Worker        mock_ssh = mock.Mock()
97*800a58d9SAndroid Build Coastguard Worker        mock_ssh.GetBaseCmd.return_value = "/mock/ssh"
98*800a58d9SAndroid Build Coastguard Worker        expected_image_shell_cmd = ("tar -cf - --lzop -S -C local/dir "
99*800a58d9SAndroid Build Coastguard Worker                                    "super.img bootloader kernel android-info.txt | "
100*800a58d9SAndroid Build Coastguard Worker                                    "/mock/ssh -- "
101*800a58d9SAndroid Build Coastguard Worker                                    "tar -xf - --lzop -S -C remote/dir")
102*800a58d9SAndroid Build Coastguard Worker        expected_target_files_shell_cmd = expected_image_shell_cmd.replace(
103*800a58d9SAndroid Build Coastguard Worker            "local/dir", "local/dir/IMAGES")
104*800a58d9SAndroid Build Coastguard Worker        expected_cvd_tar_ssh_cmd = "tar -xzf - -C remote/dir < /mock/cvd.tar.gz"
105*800a58d9SAndroid Build Coastguard Worker        expected_cvd_dir_shell_cmd = ("tar -cf - --lzop -S -C /mock/cvd . | "
106*800a58d9SAndroid Build Coastguard Worker                                      "/mock/ssh -- "
107*800a58d9SAndroid Build Coastguard Worker                                      "tar -xf - --lzop -S -C remote/dir")
108*800a58d9SAndroid Build Coastguard Worker
109*800a58d9SAndroid Build Coastguard Worker        # Test with cvd directory.
110*800a58d9SAndroid Build Coastguard Worker        mock_open = mock.mock_open(read_data="super.img\nbootloader\nkernel")
111*800a58d9SAndroid Build Coastguard Worker        with mock.patch("acloud.internal.lib.cvd_utils.open", mock_open):
112*800a58d9SAndroid Build Coastguard Worker            cvd_utils.UploadArtifacts(mock_ssh, "remote/dir","local/dir",
113*800a58d9SAndroid Build Coastguard Worker                                      "/mock/cvd")
114*800a58d9SAndroid Build Coastguard Worker        mock_open.assert_called_with("local/dir/required_images", "r",
115*800a58d9SAndroid Build Coastguard Worker                                     encoding="utf-8")
116*800a58d9SAndroid Build Coastguard Worker        mock_glob.glob.assert_called_once_with("local/dir/*.img")
117*800a58d9SAndroid Build Coastguard Worker        mock_shell.assert_has_calls([mock.call(expected_image_shell_cmd),
118*800a58d9SAndroid Build Coastguard Worker                                     mock.call(expected_cvd_dir_shell_cmd)])
119*800a58d9SAndroid Build Coastguard Worker
120*800a58d9SAndroid Build Coastguard Worker        # Test with required_images file.
121*800a58d9SAndroid Build Coastguard Worker        mock_glob.glob.reset_mock()
122*800a58d9SAndroid Build Coastguard Worker        mock_ssh.reset_mock()
123*800a58d9SAndroid Build Coastguard Worker        mock_shell.reset_mock()
124*800a58d9SAndroid Build Coastguard Worker        mock_open = mock.mock_open(read_data="super.img\nbootloader\nkernel")
125*800a58d9SAndroid Build Coastguard Worker        with mock.patch("acloud.internal.lib.cvd_utils.open", mock_open):
126*800a58d9SAndroid Build Coastguard Worker            cvd_utils.UploadArtifacts(mock_ssh, "remote/dir","local/dir",
127*800a58d9SAndroid Build Coastguard Worker                                      "/mock/cvd.tar.gz")
128*800a58d9SAndroid Build Coastguard Worker        mock_open.assert_called_with("local/dir/required_images", "r",
129*800a58d9SAndroid Build Coastguard Worker                                     encoding="utf-8")
130*800a58d9SAndroid Build Coastguard Worker        mock_glob.glob.assert_called_once_with("local/dir/*.img")
131*800a58d9SAndroid Build Coastguard Worker        mock_shell.assert_called_with(expected_image_shell_cmd)
132*800a58d9SAndroid Build Coastguard Worker        mock_ssh.Run.assert_called_with(expected_cvd_tar_ssh_cmd)
133*800a58d9SAndroid Build Coastguard Worker
134*800a58d9SAndroid Build Coastguard Worker        # Test with target files directory and glob.
135*800a58d9SAndroid Build Coastguard Worker        mock_glob.glob.reset_mock()
136*800a58d9SAndroid Build Coastguard Worker        mock_ssh.reset_mock()
137*800a58d9SAndroid Build Coastguard Worker        mock_shell.reset_mock()
138*800a58d9SAndroid Build Coastguard Worker        mock_glob.glob.side_effect = (
139*800a58d9SAndroid Build Coastguard Worker            lambda path: [path.replace("*", "super")] if
140*800a58d9SAndroid Build Coastguard Worker                         path.startswith("local/dir/IMAGES") else [])
141*800a58d9SAndroid Build Coastguard Worker        with mock.patch("acloud.internal.lib.cvd_utils.open",
142*800a58d9SAndroid Build Coastguard Worker                        side_effect=IOError("file does not exist")):
143*800a58d9SAndroid Build Coastguard Worker            cvd_utils.UploadArtifacts(mock_ssh, "remote/dir", "local/dir",
144*800a58d9SAndroid Build Coastguard Worker                                      "/mock/cvd.tar.gz")
145*800a58d9SAndroid Build Coastguard Worker        self.assertGreater(mock_glob.glob.call_count, 2)
146*800a58d9SAndroid Build Coastguard Worker        mock_shell.assert_called_with(expected_target_files_shell_cmd)
147*800a58d9SAndroid Build Coastguard Worker        mock_ssh.Run.assert_called_with(expected_cvd_tar_ssh_cmd)
148*800a58d9SAndroid Build Coastguard Worker
149*800a58d9SAndroid Build Coastguard Worker    @mock.patch("acloud.internal.lib.cvd_utils.create_common")
150*800a58d9SAndroid Build Coastguard Worker    def testUploadBootImages(self, mock_create_common):
151*800a58d9SAndroid Build Coastguard Worker        """Test FindBootImages and UploadExtraImages."""
152*800a58d9SAndroid Build Coastguard Worker        mock_ssh = mock.Mock()
153*800a58d9SAndroid Build Coastguard Worker        with tempfile.TemporaryDirectory(prefix="cvd_utils") as image_dir:
154*800a58d9SAndroid Build Coastguard Worker            mock_create_common.FindBootImage.return_value = "boot.img"
155*800a58d9SAndroid Build Coastguard Worker            self.CreateFile(os.path.join(image_dir, "vendor_boot.img"))
156*800a58d9SAndroid Build Coastguard Worker
157*800a58d9SAndroid Build Coastguard Worker            mock_avd_spec = mock.Mock(local_kernel_image="boot.img",
158*800a58d9SAndroid Build Coastguard Worker                                      local_system_image=None,
159*800a58d9SAndroid Build Coastguard Worker                                      local_system_dlkm_image=None,
160*800a58d9SAndroid Build Coastguard Worker                                      local_vendor_image=None,
161*800a58d9SAndroid Build Coastguard Worker                                      local_vendor_boot_image=None)
162*800a58d9SAndroid Build Coastguard Worker            args = cvd_utils.UploadExtraImages(mock_ssh, "dir", mock_avd_spec,
163*800a58d9SAndroid Build Coastguard Worker                                               None)
164*800a58d9SAndroid Build Coastguard Worker            self.assertEqual([("-boot_image", "dir/acloud_image/boot.img")],
165*800a58d9SAndroid Build Coastguard Worker                             args)
166*800a58d9SAndroid Build Coastguard Worker            mock_ssh.Run.assert_called_once_with("mkdir -p dir/acloud_image")
167*800a58d9SAndroid Build Coastguard Worker            mock_ssh.ScpPushFile.assert_called_once_with(
168*800a58d9SAndroid Build Coastguard Worker                "boot.img", "dir/acloud_image/boot.img")
169*800a58d9SAndroid Build Coastguard Worker
170*800a58d9SAndroid Build Coastguard Worker            mock_ssh.reset_mock()
171*800a58d9SAndroid Build Coastguard Worker            mock_avd_spec.local_kernel_image = image_dir
172*800a58d9SAndroid Build Coastguard Worker            args = cvd_utils.UploadExtraImages(mock_ssh, "dir", mock_avd_spec,
173*800a58d9SAndroid Build Coastguard Worker                                               None)
174*800a58d9SAndroid Build Coastguard Worker            self.assertEqual(
175*800a58d9SAndroid Build Coastguard Worker                [("-boot_image", "dir/acloud_image/boot.img"),
176*800a58d9SAndroid Build Coastguard Worker                 ("-vendor_boot_image", "dir/acloud_image/vendor_boot.img")],
177*800a58d9SAndroid Build Coastguard Worker                args)
178*800a58d9SAndroid Build Coastguard Worker            mock_ssh.Run.assert_called_once()
179*800a58d9SAndroid Build Coastguard Worker            self.assertEqual(2, mock_ssh.ScpPushFile.call_count)
180*800a58d9SAndroid Build Coastguard Worker
181*800a58d9SAndroid Build Coastguard Worker    def testUploadKernelImages(self):
182*800a58d9SAndroid Build Coastguard Worker        """Test FindKernelImages and UploadExtraImages."""
183*800a58d9SAndroid Build Coastguard Worker        mock_ssh = mock.Mock()
184*800a58d9SAndroid Build Coastguard Worker        with tempfile.TemporaryDirectory(prefix="cvd_utils") as image_dir:
185*800a58d9SAndroid Build Coastguard Worker            kernel_image_path = os.path.join(image_dir, "Image")
186*800a58d9SAndroid Build Coastguard Worker            self.CreateFile(kernel_image_path)
187*800a58d9SAndroid Build Coastguard Worker            self.CreateFile(os.path.join(image_dir, "initramfs.img"))
188*800a58d9SAndroid Build Coastguard Worker            self.CreateFile(os.path.join(image_dir, "boot.img"))
189*800a58d9SAndroid Build Coastguard Worker
190*800a58d9SAndroid Build Coastguard Worker            mock_avd_spec = mock.Mock(local_kernel_image=kernel_image_path,
191*800a58d9SAndroid Build Coastguard Worker                                      local_system_image=None,
192*800a58d9SAndroid Build Coastguard Worker                                      local_system_dlkm_image=None,
193*800a58d9SAndroid Build Coastguard Worker                                      local_vendor_image=None,
194*800a58d9SAndroid Build Coastguard Worker                                      local_vendor_boot_image=None)
195*800a58d9SAndroid Build Coastguard Worker            with self.assertRaises(errors.GetLocalImageError):
196*800a58d9SAndroid Build Coastguard Worker                cvd_utils.UploadExtraImages(mock_ssh, "dir", mock_avd_spec,
197*800a58d9SAndroid Build Coastguard Worker                                            None)
198*800a58d9SAndroid Build Coastguard Worker
199*800a58d9SAndroid Build Coastguard Worker            mock_ssh.reset_mock()
200*800a58d9SAndroid Build Coastguard Worker            mock_avd_spec.local_kernel_image = image_dir
201*800a58d9SAndroid Build Coastguard Worker            args = cvd_utils.UploadExtraImages(mock_ssh, "dir", mock_avd_spec,
202*800a58d9SAndroid Build Coastguard Worker                                               None)
203*800a58d9SAndroid Build Coastguard Worker            self.assertEqual(
204*800a58d9SAndroid Build Coastguard Worker                [("-kernel_path", "dir/acloud_image/kernel"),
205*800a58d9SAndroid Build Coastguard Worker                 ("-initramfs_path", "dir/acloud_image/initramfs.img")],
206*800a58d9SAndroid Build Coastguard Worker                args)
207*800a58d9SAndroid Build Coastguard Worker            mock_ssh.Run.assert_called_once()
208*800a58d9SAndroid Build Coastguard Worker            self.assertEqual(2, mock_ssh.ScpPushFile.call_count)
209*800a58d9SAndroid Build Coastguard Worker
210*800a58d9SAndroid Build Coastguard Worker    @mock.patch("acloud.internal.lib.ota_tools.FindOtaTools")
211*800a58d9SAndroid Build Coastguard Worker    @mock.patch("acloud.internal.lib.ssh.ShellCmdWithRetry")
212*800a58d9SAndroid Build Coastguard Worker    def testUploadSuperImage(self, mock_shell, mock_find_ota_tools):
213*800a58d9SAndroid Build Coastguard Worker        """Test UploadExtraImages."""
214*800a58d9SAndroid Build Coastguard Worker        self.Patch(create_common, "GetNonEmptyEnvVars", return_value=[])
215*800a58d9SAndroid Build Coastguard Worker        mock_ssh = mock.Mock()
216*800a58d9SAndroid Build Coastguard Worker        mock_ota_tools_object = mock.Mock()
217*800a58d9SAndroid Build Coastguard Worker        mock_find_ota_tools.return_value = mock_ota_tools_object
218*800a58d9SAndroid Build Coastguard Worker
219*800a58d9SAndroid Build Coastguard Worker        with tempfile.TemporaryDirectory(prefix="cvd_utils") as temp_dir:
220*800a58d9SAndroid Build Coastguard Worker            target_files_dir = os.path.join(temp_dir, "target_files")
221*800a58d9SAndroid Build Coastguard Worker            extra_image_dir = os.path.join(temp_dir, "extra")
222*800a58d9SAndroid Build Coastguard Worker            mock_avd_spec = mock.Mock(local_kernel_image=None,
223*800a58d9SAndroid Build Coastguard Worker                                      local_system_image=extra_image_dir,
224*800a58d9SAndroid Build Coastguard Worker                                      local_system_dlkm_image=extra_image_dir,
225*800a58d9SAndroid Build Coastguard Worker                                      local_vendor_image=extra_image_dir,
226*800a58d9SAndroid Build Coastguard Worker                                      local_vendor_boot_image=None,
227*800a58d9SAndroid Build Coastguard Worker                                      local_tool_dirs=[])
228*800a58d9SAndroid Build Coastguard Worker            self.CreateFile(
229*800a58d9SAndroid Build Coastguard Worker                os.path.join(target_files_dir, "IMAGES", "boot.img"))
230*800a58d9SAndroid Build Coastguard Worker            self.CreateFile(
231*800a58d9SAndroid Build Coastguard Worker                os.path.join(target_files_dir, "META", "misc_info.txt"))
232*800a58d9SAndroid Build Coastguard Worker            for image_name in ["system.img", "system_dlkm.img", "vendor.img",
233*800a58d9SAndroid Build Coastguard Worker                               "vendor_dlkm.img", "odm.img", "odm_dlkm.img"]:
234*800a58d9SAndroid Build Coastguard Worker                self.CreateFile(os.path.join(extra_image_dir, image_name))
235*800a58d9SAndroid Build Coastguard Worker            args = cvd_utils.UploadExtraImages(mock_ssh, "dir", mock_avd_spec,
236*800a58d9SAndroid Build Coastguard Worker                                               target_files_dir)
237*800a58d9SAndroid Build Coastguard Worker
238*800a58d9SAndroid Build Coastguard Worker        self.assertEqual(
239*800a58d9SAndroid Build Coastguard Worker            [("-super_image", "dir/acloud_image/super.img"),
240*800a58d9SAndroid Build Coastguard Worker             ("-vbmeta_image", "dir/acloud_image/vbmeta.img")],
241*800a58d9SAndroid Build Coastguard Worker            args)
242*800a58d9SAndroid Build Coastguard Worker        mock_find_ota_tools.assert_called_once_with([])
243*800a58d9SAndroid Build Coastguard Worker        mock_ssh.Run.assert_called_once_with("mkdir -p dir/acloud_image")
244*800a58d9SAndroid Build Coastguard Worker        # Super image
245*800a58d9SAndroid Build Coastguard Worker        mock_shell.assert_called_once()
246*800a58d9SAndroid Build Coastguard Worker        upload_args = mock_shell.call_args[0]
247*800a58d9SAndroid Build Coastguard Worker        self.assertEqual(1, len(upload_args))
248*800a58d9SAndroid Build Coastguard Worker        self.assertIn(" super.img", upload_args[0])
249*800a58d9SAndroid Build Coastguard Worker        self.assertIn("dir/acloud_image", upload_args[0])
250*800a58d9SAndroid Build Coastguard Worker        mock_ota_tools_object.MixSuperImage.assert_called_once_with(
251*800a58d9SAndroid Build Coastguard Worker            mock.ANY, mock.ANY, os.path.join(target_files_dir, "IMAGES"),
252*800a58d9SAndroid Build Coastguard Worker            system_image=os.path.join(extra_image_dir, "system.img"),
253*800a58d9SAndroid Build Coastguard Worker            system_ext_image=None,
254*800a58d9SAndroid Build Coastguard Worker            product_image=None,
255*800a58d9SAndroid Build Coastguard Worker            system_dlkm_image=os.path.join(extra_image_dir, "system_dlkm.img"),
256*800a58d9SAndroid Build Coastguard Worker            vendor_image=os.path.join(extra_image_dir, "vendor.img"),
257*800a58d9SAndroid Build Coastguard Worker            vendor_dlkm_image=os.path.join(extra_image_dir, "vendor_dlkm.img"),
258*800a58d9SAndroid Build Coastguard Worker            odm_image=os.path.join(extra_image_dir, "odm.img"),
259*800a58d9SAndroid Build Coastguard Worker            odm_dlkm_image=os.path.join(extra_image_dir, "odm_dlkm.img"))
260*800a58d9SAndroid Build Coastguard Worker        # vbmeta image
261*800a58d9SAndroid Build Coastguard Worker        mock_ota_tools_object.MakeDisabledVbmetaImage.assert_called_once()
262*800a58d9SAndroid Build Coastguard Worker        mock_ssh.ScpPushFile.assert_called_once_with(
263*800a58d9SAndroid Build Coastguard Worker            mock.ANY, "dir/acloud_image/vbmeta.img")
264*800a58d9SAndroid Build Coastguard Worker
265*800a58d9SAndroid Build Coastguard Worker
266*800a58d9SAndroid Build Coastguard Worker    def testUploadVendorBootImages(self):
267*800a58d9SAndroid Build Coastguard Worker        """Test UploadExtraImages."""
268*800a58d9SAndroid Build Coastguard Worker        mock_ssh = mock.Mock()
269*800a58d9SAndroid Build Coastguard Worker        with tempfile.TemporaryDirectory(prefix="cvd_utils") as image_dir:
270*800a58d9SAndroid Build Coastguard Worker            vendor_boot_image_path = os.path.join(image_dir,
271*800a58d9SAndroid Build Coastguard Worker                                                  "vendor_boot-debug_test.img")
272*800a58d9SAndroid Build Coastguard Worker            self.CreateFile(vendor_boot_image_path)
273*800a58d9SAndroid Build Coastguard Worker
274*800a58d9SAndroid Build Coastguard Worker            mock_avd_spec = mock.Mock(
275*800a58d9SAndroid Build Coastguard Worker                local_kernel_image=None,
276*800a58d9SAndroid Build Coastguard Worker                local_system_image=None,
277*800a58d9SAndroid Build Coastguard Worker                local_system_dlkm_image=None,
278*800a58d9SAndroid Build Coastguard Worker                local_vendor_image=None,
279*800a58d9SAndroid Build Coastguard Worker                local_vendor_boot_image=vendor_boot_image_path)
280*800a58d9SAndroid Build Coastguard Worker
281*800a58d9SAndroid Build Coastguard Worker            args = cvd_utils.UploadExtraImages(mock_ssh, "dir", mock_avd_spec,
282*800a58d9SAndroid Build Coastguard Worker                                               None)
283*800a58d9SAndroid Build Coastguard Worker            self.assertEqual(
284*800a58d9SAndroid Build Coastguard Worker                [("-vendor_boot_image", "dir/acloud_image/vendor_boot.img")],
285*800a58d9SAndroid Build Coastguard Worker                args)
286*800a58d9SAndroid Build Coastguard Worker            mock_ssh.Run.assert_called_once()
287*800a58d9SAndroid Build Coastguard Worker            mock_ssh.ScpPushFile.assert_called_once_with(
288*800a58d9SAndroid Build Coastguard Worker                mock.ANY, "dir/acloud_image/vendor_boot.img")
289*800a58d9SAndroid Build Coastguard Worker
290*800a58d9SAndroid Build Coastguard Worker            mock_ssh.reset_mock()
291*800a58d9SAndroid Build Coastguard Worker            self.CreateFile(os.path.join(image_dir, "vendor_boot.img"))
292*800a58d9SAndroid Build Coastguard Worker            mock_avd_spec.local_vendor_boot_image = image_dir
293*800a58d9SAndroid Build Coastguard Worker            args = cvd_utils.UploadExtraImages(mock_ssh, "dir", mock_avd_spec,
294*800a58d9SAndroid Build Coastguard Worker                                               None)
295*800a58d9SAndroid Build Coastguard Worker            self.assertEqual(
296*800a58d9SAndroid Build Coastguard Worker                [("-vendor_boot_image", "dir/acloud_image/vendor_boot.img")],
297*800a58d9SAndroid Build Coastguard Worker                args)
298*800a58d9SAndroid Build Coastguard Worker            mock_ssh.Run.assert_called_once()
299*800a58d9SAndroid Build Coastguard Worker            mock_ssh.ScpPushFile.assert_called_once_with(
300*800a58d9SAndroid Build Coastguard Worker                mock.ANY, "dir/acloud_image/vendor_boot.img")
301*800a58d9SAndroid Build Coastguard Worker
302*800a58d9SAndroid Build Coastguard Worker
303*800a58d9SAndroid Build Coastguard Worker    def testCleanUpRemoteCvd(self):
304*800a58d9SAndroid Build Coastguard Worker        """Test CleanUpRemoteCvd."""
305*800a58d9SAndroid Build Coastguard Worker        mock_ssh = mock.Mock()
306*800a58d9SAndroid Build Coastguard Worker        mock_ssh.Run.side_effect = ["", "", ""]
307*800a58d9SAndroid Build Coastguard Worker        cvd_utils.CleanUpRemoteCvd(mock_ssh, "dir", raise_error=True)
308*800a58d9SAndroid Build Coastguard Worker        mock_ssh.Run.assert_has_calls([
309*800a58d9SAndroid Build Coastguard Worker            mock.call("'readlink -n -e dir/image_dir_link || true'"),
310*800a58d9SAndroid Build Coastguard Worker            mock.call("'HOME=$HOME/dir dir/bin/stop_cvd'"),
311*800a58d9SAndroid Build Coastguard Worker            mock.call("'rm -rf dir/*'")])
312*800a58d9SAndroid Build Coastguard Worker
313*800a58d9SAndroid Build Coastguard Worker        mock_ssh.reset_mock()
314*800a58d9SAndroid Build Coastguard Worker        mock_ssh.Run.side_effect = ["img_dir", "", "", ""]
315*800a58d9SAndroid Build Coastguard Worker        cvd_utils.CleanUpRemoteCvd(mock_ssh, "dir", raise_error=True)
316*800a58d9SAndroid Build Coastguard Worker        mock_ssh.Run.assert_has_calls([
317*800a58d9SAndroid Build Coastguard Worker            mock.call("'readlink -n -e dir/image_dir_link || true'"),
318*800a58d9SAndroid Build Coastguard Worker            mock.call("'mkdir -p img_dir && flock img_dir.lock -c '\"'\"'"
319*800a58d9SAndroid Build Coastguard Worker                      "rm -f dir/image_dir_link && "
320*800a58d9SAndroid Build Coastguard Worker                      "expr $(test -s img_dir.lock && "
321*800a58d9SAndroid Build Coastguard Worker                      "cat img_dir.lock || echo 1) - 1 > img_dir.lock || "
322*800a58d9SAndroid Build Coastguard Worker                      "rm -rf img_dir img_dir.lock'\"'\"''"),
323*800a58d9SAndroid Build Coastguard Worker            mock.call("'HOME=$HOME/dir dir/bin/stop_cvd'"),
324*800a58d9SAndroid Build Coastguard Worker            mock.call("'rm -rf dir/*'")])
325*800a58d9SAndroid Build Coastguard Worker
326*800a58d9SAndroid Build Coastguard Worker        mock_ssh.reset_mock()
327*800a58d9SAndroid Build Coastguard Worker        mock_ssh.Run.side_effect = [
328*800a58d9SAndroid Build Coastguard Worker            "",
329*800a58d9SAndroid Build Coastguard Worker            subprocess.CalledProcessError(cmd="should raise", returncode=1)]
330*800a58d9SAndroid Build Coastguard Worker        with self.assertRaises(subprocess.CalledProcessError):
331*800a58d9SAndroid Build Coastguard Worker            cvd_utils.CleanUpRemoteCvd(mock_ssh, "dir", raise_error=True)
332*800a58d9SAndroid Build Coastguard Worker
333*800a58d9SAndroid Build Coastguard Worker        mock_ssh.reset_mock()
334*800a58d9SAndroid Build Coastguard Worker        mock_ssh.Run.side_effect = [
335*800a58d9SAndroid Build Coastguard Worker            "",
336*800a58d9SAndroid Build Coastguard Worker            subprocess.CalledProcessError(cmd="should ignore", returncode=1),
337*800a58d9SAndroid Build Coastguard Worker            None]
338*800a58d9SAndroid Build Coastguard Worker        cvd_utils.CleanUpRemoteCvd(mock_ssh, "dir", raise_error=False)
339*800a58d9SAndroid Build Coastguard Worker        mock_ssh.Run.assert_any_call("'HOME=$HOME/dir dir/bin/stop_cvd'",
340*800a58d9SAndroid Build Coastguard Worker                                     retry=0)
341*800a58d9SAndroid Build Coastguard Worker        mock_ssh.Run.assert_any_call("'rm -rf dir/*'")
342*800a58d9SAndroid Build Coastguard Worker
343*800a58d9SAndroid Build Coastguard Worker    def testGetRemoteHostBaseDir(self):
344*800a58d9SAndroid Build Coastguard Worker        """Test GetRemoteHostBaseDir."""
345*800a58d9SAndroid Build Coastguard Worker        self.assertEqual("acloud_cf_1", cvd_utils.GetRemoteHostBaseDir(None))
346*800a58d9SAndroid Build Coastguard Worker        self.assertEqual("acloud_cf_2", cvd_utils.GetRemoteHostBaseDir(2))
347*800a58d9SAndroid Build Coastguard Worker
348*800a58d9SAndroid Build Coastguard Worker    def testFormatRemoteHostInstanceName(self):
349*800a58d9SAndroid Build Coastguard Worker        """Test FormatRemoteHostInstanceName."""
350*800a58d9SAndroid Build Coastguard Worker        name = cvd_utils.FormatRemoteHostInstanceName(
351*800a58d9SAndroid Build Coastguard Worker            self._REMOTE_HOSTNAME_1, None, self._BUILD_ID, self._PRODUCT_NAME)
352*800a58d9SAndroid Build Coastguard Worker        self.assertEqual(name, self._REMOTE_HOST_INSTANCE_NAME_1)
353*800a58d9SAndroid Build Coastguard Worker
354*800a58d9SAndroid Build Coastguard Worker        name = cvd_utils.FormatRemoteHostInstanceName(
355*800a58d9SAndroid Build Coastguard Worker            self._REMOTE_HOSTNAME_2, 2, self._BUILD_ID, self._PRODUCT_NAME)
356*800a58d9SAndroid Build Coastguard Worker        self.assertEqual(name, self._REMOTE_HOST_INSTANCE_NAME_2)
357*800a58d9SAndroid Build Coastguard Worker
358*800a58d9SAndroid Build Coastguard Worker    def testParseRemoteHostAddress(self):
359*800a58d9SAndroid Build Coastguard Worker        """Test ParseRemoteHostAddress."""
360*800a58d9SAndroid Build Coastguard Worker        result = cvd_utils.ParseRemoteHostAddress(
361*800a58d9SAndroid Build Coastguard Worker            self._REMOTE_HOST_INSTANCE_NAME_1)
362*800a58d9SAndroid Build Coastguard Worker        self.assertEqual(result, (self._REMOTE_HOSTNAME_1, "acloud_cf_1"))
363*800a58d9SAndroid Build Coastguard Worker
364*800a58d9SAndroid Build Coastguard Worker        result = cvd_utils.ParseRemoteHostAddress(
365*800a58d9SAndroid Build Coastguard Worker            self._REMOTE_HOST_INSTANCE_NAME_2)
366*800a58d9SAndroid Build Coastguard Worker        self.assertEqual(result, (self._REMOTE_HOSTNAME_2, "acloud_cf_2"))
367*800a58d9SAndroid Build Coastguard Worker
368*800a58d9SAndroid Build Coastguard Worker        result = cvd_utils.ParseRemoteHostAddress(
369*800a58d9SAndroid Build Coastguard Worker            "host-goldfish-192.0.2.1-5554-123456-sdk_x86_64-sdk")
370*800a58d9SAndroid Build Coastguard Worker        self.assertIsNone(result)
371*800a58d9SAndroid Build Coastguard Worker
372*800a58d9SAndroid Build Coastguard Worker    # pylint: disable=protected-access
373*800a58d9SAndroid Build Coastguard Worker    def testRemoteImageDirLink(self):
374*800a58d9SAndroid Build Coastguard Worker        """Test PrepareRemoteImageDirLink and _DeleteRemoteImageDirLink."""
375*800a58d9SAndroid Build Coastguard Worker        self.assertEqual(os.path, cvd_utils.remote_path)
376*800a58d9SAndroid Build Coastguard Worker        with tempfile.TemporaryDirectory(prefix="cvd_utils") as temp_dir:
377*800a58d9SAndroid Build Coastguard Worker            env = os.environ.copy()
378*800a58d9SAndroid Build Coastguard Worker            env["HOME"] = temp_dir
379*800a58d9SAndroid Build Coastguard Worker            # Execute the commands locally.
380*800a58d9SAndroid Build Coastguard Worker            mock_ssh = mock.Mock()
381*800a58d9SAndroid Build Coastguard Worker            mock_ssh.Run.side_effect = lambda cmd: subprocess.check_output(
382*800a58d9SAndroid Build Coastguard Worker                "sh -c " + cmd, shell=True, cwd=temp_dir, env=env
383*800a58d9SAndroid Build Coastguard Worker            ).decode("utf-8")
384*800a58d9SAndroid Build Coastguard Worker            # Relative paths under temp_dir.
385*800a58d9SAndroid Build Coastguard Worker            base_dir_name_1 = "acloud_cf_1"
386*800a58d9SAndroid Build Coastguard Worker            base_dir_name_2 = "acloud_cf_2"
387*800a58d9SAndroid Build Coastguard Worker            image_dir_name = "test/img"
388*800a58d9SAndroid Build Coastguard Worker            rel_ref_cnt_path = "test/img.lock"
389*800a58d9SAndroid Build Coastguard Worker            # Absolute paths.
390*800a58d9SAndroid Build Coastguard Worker            image_dir = os.path.join(temp_dir, image_dir_name)
391*800a58d9SAndroid Build Coastguard Worker            ref_cnt_path = os.path.join(temp_dir, rel_ref_cnt_path)
392*800a58d9SAndroid Build Coastguard Worker            link_path_1 = os.path.join(temp_dir, base_dir_name_1,
393*800a58d9SAndroid Build Coastguard Worker                                       "image_dir_link")
394*800a58d9SAndroid Build Coastguard Worker            link_path_2 = os.path.join(temp_dir, base_dir_name_2,
395*800a58d9SAndroid Build Coastguard Worker                                       "image_dir_link")
396*800a58d9SAndroid Build Coastguard Worker            # Delete non-existing directories.
397*800a58d9SAndroid Build Coastguard Worker            cvd_utils._DeleteRemoteImageDirLink(mock_ssh, base_dir_name_1)
398*800a58d9SAndroid Build Coastguard Worker            mock_ssh.Run.assert_called_with(
399*800a58d9SAndroid Build Coastguard Worker                f"'readlink -n -e {base_dir_name_1}/image_dir_link || true'")
400*800a58d9SAndroid Build Coastguard Worker            self.assertFalse(
401*800a58d9SAndroid Build Coastguard Worker                os.path.exists(os.path.join(temp_dir, base_dir_name_1)))
402*800a58d9SAndroid Build Coastguard Worker            self.assertFalse(os.path.exists(image_dir))
403*800a58d9SAndroid Build Coastguard Worker            self.assertFalse(os.path.exists(ref_cnt_path))
404*800a58d9SAndroid Build Coastguard Worker            # Prepare the first base dir.
405*800a58d9SAndroid Build Coastguard Worker            cvd_utils.PrepareRemoteImageDirLink(mock_ssh, base_dir_name_1,
406*800a58d9SAndroid Build Coastguard Worker                                                image_dir_name)
407*800a58d9SAndroid Build Coastguard Worker            mock_ssh.Run.assert_called_with(
408*800a58d9SAndroid Build Coastguard Worker                f"'mkdir -p {image_dir_name} && flock {rel_ref_cnt_path} -c "
409*800a58d9SAndroid Build Coastguard Worker                f"'\"'\"'mkdir -p {base_dir_name_1} {image_dir_name} && "
410*800a58d9SAndroid Build Coastguard Worker                f"ln -s -r {image_dir_name} "
411*800a58d9SAndroid Build Coastguard Worker                f"{base_dir_name_1}/image_dir_link && "
412*800a58d9SAndroid Build Coastguard Worker                f"expr $(test -s {rel_ref_cnt_path} && "
413*800a58d9SAndroid Build Coastguard Worker                f"cat {rel_ref_cnt_path} || echo 0) + 1 > "
414*800a58d9SAndroid Build Coastguard Worker                f"{rel_ref_cnt_path}'\"'\"''")
415*800a58d9SAndroid Build Coastguard Worker            self.assertTrue(os.path.islink(link_path_1))
416*800a58d9SAndroid Build Coastguard Worker            self.assertEqual("../test/img", os.readlink(link_path_1))
417*800a58d9SAndroid Build Coastguard Worker            self.assertTrue(os.path.isfile(ref_cnt_path))
418*800a58d9SAndroid Build Coastguard Worker            with open(ref_cnt_path, "r", encoding="utf-8") as ref_cnt_file:
419*800a58d9SAndroid Build Coastguard Worker                self.assertEqual("1\n", ref_cnt_file.read())
420*800a58d9SAndroid Build Coastguard Worker            # Prepare the second base dir.
421*800a58d9SAndroid Build Coastguard Worker            cvd_utils.PrepareRemoteImageDirLink(mock_ssh, base_dir_name_2,
422*800a58d9SAndroid Build Coastguard Worker                                                image_dir_name)
423*800a58d9SAndroid Build Coastguard Worker            self.assertTrue(os.path.islink(link_path_2))
424*800a58d9SAndroid Build Coastguard Worker            self.assertEqual("../test/img", os.readlink(link_path_2))
425*800a58d9SAndroid Build Coastguard Worker            self.assertTrue(os.path.isfile(ref_cnt_path))
426*800a58d9SAndroid Build Coastguard Worker            with open(ref_cnt_path, "r", encoding="utf-8") as ref_cnt_file:
427*800a58d9SAndroid Build Coastguard Worker                self.assertEqual("2\n", ref_cnt_file.read())
428*800a58d9SAndroid Build Coastguard Worker            # Delete the first base dir.
429*800a58d9SAndroid Build Coastguard Worker            cvd_utils._DeleteRemoteImageDirLink(mock_ssh, base_dir_name_1)
430*800a58d9SAndroid Build Coastguard Worker            self.assertFalse(os.path.lexists(link_path_1))
431*800a58d9SAndroid Build Coastguard Worker            self.assertTrue(os.path.isfile(ref_cnt_path))
432*800a58d9SAndroid Build Coastguard Worker            with open(ref_cnt_path, "r", encoding="utf-8") as ref_cnt_file:
433*800a58d9SAndroid Build Coastguard Worker                self.assertEqual("1\n", ref_cnt_file.read())
434*800a58d9SAndroid Build Coastguard Worker            # Delete the second base dir.
435*800a58d9SAndroid Build Coastguard Worker            cvd_utils._DeleteRemoteImageDirLink(mock_ssh, base_dir_name_2)
436*800a58d9SAndroid Build Coastguard Worker            self.assertFalse(os.path.lexists(link_path_2))
437*800a58d9SAndroid Build Coastguard Worker            self.assertFalse(os.path.exists(image_dir))
438*800a58d9SAndroid Build Coastguard Worker            self.assertFalse(os.path.exists(ref_cnt_path))
439*800a58d9SAndroid Build Coastguard Worker
440*800a58d9SAndroid Build Coastguard Worker    @mock.patch("acloud.internal.lib.cvd_utils.utils.PollAndWait")
441*800a58d9SAndroid Build Coastguard Worker    @mock.patch("acloud.internal.lib.cvd_utils.utils.time.time",
442*800a58d9SAndroid Build Coastguard Worker                return_value=90.0)
443*800a58d9SAndroid Build Coastguard Worker    def testLoadRemoteImageArgs(self, _mock_time, mock_poll_and_wait):
444*800a58d9SAndroid Build Coastguard Worker        """Test LoadRemoteImageArgs."""
445*800a58d9SAndroid Build Coastguard Worker        deadline = 99.9
446*800a58d9SAndroid Build Coastguard Worker        self.assertEqual(os.path, cvd_utils.remote_path)
447*800a58d9SAndroid Build Coastguard Worker
448*800a58d9SAndroid Build Coastguard Worker        with tempfile.TemporaryDirectory(prefix="cvd_utils") as temp_dir:
449*800a58d9SAndroid Build Coastguard Worker            env = os.environ.copy()
450*800a58d9SAndroid Build Coastguard Worker            env["HOME"] = temp_dir
451*800a58d9SAndroid Build Coastguard Worker            # Execute the commands locally.
452*800a58d9SAndroid Build Coastguard Worker            mock_ssh = mock.Mock()
453*800a58d9SAndroid Build Coastguard Worker            mock_ssh.Run.side_effect = lambda cmd: subprocess.check_output(
454*800a58d9SAndroid Build Coastguard Worker                "sh -c " + cmd, shell=True, cwd=temp_dir, env=env, text=True)
455*800a58d9SAndroid Build Coastguard Worker            mock_poll_and_wait.side_effect = lambda func, **kwargs: func()
456*800a58d9SAndroid Build Coastguard Worker
457*800a58d9SAndroid Build Coastguard Worker            timestamp_path = os.path.join(temp_dir, "timestamp.txt")
458*800a58d9SAndroid Build Coastguard Worker            args_path = os.path.join(temp_dir, "args.txt")
459*800a58d9SAndroid Build Coastguard Worker
460*800a58d9SAndroid Build Coastguard Worker            # Test with an uninitialized directory.
461*800a58d9SAndroid Build Coastguard Worker            args = cvd_utils.LoadRemoteImageArgs(
462*800a58d9SAndroid Build Coastguard Worker                mock_ssh, timestamp_path, args_path, deadline)
463*800a58d9SAndroid Build Coastguard Worker
464*800a58d9SAndroid Build Coastguard Worker            self.assertIsNone(args)
465*800a58d9SAndroid Build Coastguard Worker            mock_ssh.Run.assert_called_once()
466*800a58d9SAndroid Build Coastguard Worker            with open(timestamp_path, "r", encoding="utf-8") as timestamp_file:
467*800a58d9SAndroid Build Coastguard Worker                timestamp = timestamp_file.read().strip()
468*800a58d9SAndroid Build Coastguard Worker                self.assertRegex(timestamp, r"\d+",
469*800a58d9SAndroid Build Coastguard Worker                                 f"Invalid timestamp: {timestamp}")
470*800a58d9SAndroid Build Coastguard Worker            self.assertFalse(os.path.exists(args_path))
471*800a58d9SAndroid Build Coastguard Worker
472*800a58d9SAndroid Build Coastguard Worker            # Test with an initialized directory and the uploader times out.
473*800a58d9SAndroid Build Coastguard Worker            mock_ssh.Run.reset_mock()
474*800a58d9SAndroid Build Coastguard Worker
475*800a58d9SAndroid Build Coastguard Worker            with self.assertRaises(errors.CreateError):
476*800a58d9SAndroid Build Coastguard Worker                cvd_utils.LoadRemoteImageArgs(
477*800a58d9SAndroid Build Coastguard Worker                    mock_ssh, timestamp_path, args_path, deadline)
478*800a58d9SAndroid Build Coastguard Worker
479*800a58d9SAndroid Build Coastguard Worker            mock_ssh.Run.assert_has_calls([
480*800a58d9SAndroid Build Coastguard Worker                mock.call(f"'flock {timestamp_path} -c '\"'\"'"
481*800a58d9SAndroid Build Coastguard Worker                          f"test -s {timestamp_path} && "
482*800a58d9SAndroid Build Coastguard Worker                          f"cat {timestamp_path} || "
483*800a58d9SAndroid Build Coastguard Worker                          f"expr $(date +%s) + 9 > {timestamp_path}'\"'\"''"),
484*800a58d9SAndroid Build Coastguard Worker                mock.call(f"'flock {args_path} -c '\"'\"'"
485*800a58d9SAndroid Build Coastguard Worker                          f"test -s {args_path} -o "
486*800a58d9SAndroid Build Coastguard Worker                          f"{timestamp} -le $(date +%s) || "
487*800a58d9SAndroid Build Coastguard Worker                          "echo wait...'\"'\"''"),
488*800a58d9SAndroid Build Coastguard Worker                mock.call(f"'flock {args_path} -c '\"'\"'"
489*800a58d9SAndroid Build Coastguard Worker                          f"cat {args_path}'\"'\"''")
490*800a58d9SAndroid Build Coastguard Worker            ])
491*800a58d9SAndroid Build Coastguard Worker            with open(timestamp_path, "r", encoding="utf-8") as timestamp_file:
492*800a58d9SAndroid Build Coastguard Worker                self.assertEqual(timestamp_file.read().strip(), timestamp)
493*800a58d9SAndroid Build Coastguard Worker            self.assertEqual(os.path.getsize(args_path), 0)
494*800a58d9SAndroid Build Coastguard Worker
495*800a58d9SAndroid Build Coastguard Worker            # Test with an initialized directory.
496*800a58d9SAndroid Build Coastguard Worker            mock_ssh.Run.reset_mock()
497*800a58d9SAndroid Build Coastguard Worker            self.CreateFile(args_path, b'[["arg", "1"]]')
498*800a58d9SAndroid Build Coastguard Worker
499*800a58d9SAndroid Build Coastguard Worker            args = cvd_utils.LoadRemoteImageArgs(
500*800a58d9SAndroid Build Coastguard Worker                mock_ssh, timestamp_path, args_path, deadline)
501*800a58d9SAndroid Build Coastguard Worker
502*800a58d9SAndroid Build Coastguard Worker            self.assertEqual(args, [["arg", "1"]])
503*800a58d9SAndroid Build Coastguard Worker            self.assertEqual(mock_ssh.Run.call_count, 3)
504*800a58d9SAndroid Build Coastguard Worker
505*800a58d9SAndroid Build Coastguard Worker    def testSaveRemoteImageArgs(self):
506*800a58d9SAndroid Build Coastguard Worker        """Test SaveRemoteImageArgs."""
507*800a58d9SAndroid Build Coastguard Worker        with tempfile.TemporaryDirectory(prefix="cvd_utils") as temp_dir:
508*800a58d9SAndroid Build Coastguard Worker            env = os.environ.copy()
509*800a58d9SAndroid Build Coastguard Worker            env["HOME"] = temp_dir
510*800a58d9SAndroid Build Coastguard Worker            mock_ssh = mock.Mock()
511*800a58d9SAndroid Build Coastguard Worker            mock_ssh.Run.side_effect = lambda cmd: subprocess.check_call(
512*800a58d9SAndroid Build Coastguard Worker                "sh -c " + cmd, shell=True, cwd=temp_dir, env=env, text=True)
513*800a58d9SAndroid Build Coastguard Worker            args_path = os.path.join(temp_dir, "args.txt")
514*800a58d9SAndroid Build Coastguard Worker
515*800a58d9SAndroid Build Coastguard Worker            cvd_utils.SaveRemoteImageArgs(mock_ssh, args_path, [("arg", "1")])
516*800a58d9SAndroid Build Coastguard Worker
517*800a58d9SAndroid Build Coastguard Worker            mock_ssh.Run.assert_called_with(
518*800a58d9SAndroid Build Coastguard Worker                f"'flock {args_path} -c '\"'\"'"
519*800a58d9SAndroid Build Coastguard Worker                f"""echo '"'"'"'"'"'"'"'"'[["arg", "1"]]'"'"'"'"'"'"'"'"' > """
520*800a58d9SAndroid Build Coastguard Worker                f"{args_path}'\"'\"''")
521*800a58d9SAndroid Build Coastguard Worker            with open(args_path, "r", encoding="utf-8") as args_file:
522*800a58d9SAndroid Build Coastguard Worker                self.assertEqual(args_file.read().strip(), '[["arg", "1"]]')
523*800a58d9SAndroid Build Coastguard Worker
524*800a58d9SAndroid Build Coastguard Worker    def testGetConfigFromRemoteAndroidInfo(self):
525*800a58d9SAndroid Build Coastguard Worker        """Test GetConfigFromRemoteAndroidInfo."""
526*800a58d9SAndroid Build Coastguard Worker        mock_ssh = mock.Mock()
527*800a58d9SAndroid Build Coastguard Worker        mock_ssh.GetCmdOutput.return_value = "require board=vsoc_x86_64\n"
528*800a58d9SAndroid Build Coastguard Worker        config = cvd_utils.GetConfigFromRemoteAndroidInfo(mock_ssh, ".")
529*800a58d9SAndroid Build Coastguard Worker        mock_ssh.GetCmdOutput.assert_called_with("cat ./android-info.txt")
530*800a58d9SAndroid Build Coastguard Worker        self.assertIsNone(config)
531*800a58d9SAndroid Build Coastguard Worker
532*800a58d9SAndroid Build Coastguard Worker        mock_ssh.GetCmdOutput.return_value += "config=phone\n"
533*800a58d9SAndroid Build Coastguard Worker        config = cvd_utils.GetConfigFromRemoteAndroidInfo(mock_ssh, ".")
534*800a58d9SAndroid Build Coastguard Worker        self.assertEqual(config, "phone")
535*800a58d9SAndroid Build Coastguard Worker
536*800a58d9SAndroid Build Coastguard Worker    def testGetRemoteLaunchCvdCmd(self):
537*800a58d9SAndroid Build Coastguard Worker        """Test GetRemoteLaunchCvdCmd."""
538*800a58d9SAndroid Build Coastguard Worker        # Minimum arguments
539*800a58d9SAndroid Build Coastguard Worker        mock_cfg = mock.Mock(extra_data_disk_size_gb=0)
540*800a58d9SAndroid Build Coastguard Worker        hw_property = {
541*800a58d9SAndroid Build Coastguard Worker            constants.HW_X_RES: "1080",
542*800a58d9SAndroid Build Coastguard Worker            constants.HW_Y_RES: "1920",
543*800a58d9SAndroid Build Coastguard Worker            constants.HW_ALIAS_DPI: "240"}
544*800a58d9SAndroid Build Coastguard Worker        mock_avd_spec = mock.Mock(
545*800a58d9SAndroid Build Coastguard Worker            spec=[],
546*800a58d9SAndroid Build Coastguard Worker            cfg=mock_cfg,
547*800a58d9SAndroid Build Coastguard Worker            hw_customize=False,
548*800a58d9SAndroid Build Coastguard Worker            hw_property=hw_property,
549*800a58d9SAndroid Build Coastguard Worker            connect_webrtc=False,
550*800a58d9SAndroid Build Coastguard Worker            connect_vnc=False,
551*800a58d9SAndroid Build Coastguard Worker            openwrt=False,
552*800a58d9SAndroid Build Coastguard Worker            num_avds_per_instance=1,
553*800a58d9SAndroid Build Coastguard Worker            base_instance_num=0,
554*800a58d9SAndroid Build Coastguard Worker            launch_args="")
555*800a58d9SAndroid Build Coastguard Worker        expected_cmd = (
556*800a58d9SAndroid Build Coastguard Worker            "HOME=$HOME/dir dir/bin/launch_cvd -daemon "
557*800a58d9SAndroid Build Coastguard Worker            "-x_res=1080 -y_res=1920 -dpi=240 "
558*800a58d9SAndroid Build Coastguard Worker            "-undefok=report_anonymous_usage_stats,config "
559*800a58d9SAndroid Build Coastguard Worker            "-report_anonymous_usage_stats=y")
560*800a58d9SAndroid Build Coastguard Worker        cmd = cvd_utils.GetRemoteLaunchCvdCmd("dir", mock_avd_spec,
561*800a58d9SAndroid Build Coastguard Worker                                              config=None, extra_args=())
562*800a58d9SAndroid Build Coastguard Worker        self.assertEqual(cmd, expected_cmd)
563*800a58d9SAndroid Build Coastguard Worker
564*800a58d9SAndroid Build Coastguard Worker        # All arguments.
565*800a58d9SAndroid Build Coastguard Worker        mock_cfg = mock.Mock(extra_data_disk_size_gb=20)
566*800a58d9SAndroid Build Coastguard Worker        hw_property = {
567*800a58d9SAndroid Build Coastguard Worker            constants.HW_X_RES: "1080",
568*800a58d9SAndroid Build Coastguard Worker            constants.HW_Y_RES: "1920",
569*800a58d9SAndroid Build Coastguard Worker            constants.HW_ALIAS_DPI: "240",
570*800a58d9SAndroid Build Coastguard Worker            constants.HW_ALIAS_DISK: "10240",
571*800a58d9SAndroid Build Coastguard Worker            constants.HW_ALIAS_CPUS: "2",
572*800a58d9SAndroid Build Coastguard Worker            constants.HW_ALIAS_MEMORY: "4096"}
573*800a58d9SAndroid Build Coastguard Worker        mock_avd_spec = mock.Mock(
574*800a58d9SAndroid Build Coastguard Worker            spec=[],
575*800a58d9SAndroid Build Coastguard Worker            cfg=mock_cfg,
576*800a58d9SAndroid Build Coastguard Worker            hw_customize=True,
577*800a58d9SAndroid Build Coastguard Worker            hw_property=hw_property,
578*800a58d9SAndroid Build Coastguard Worker            connect_webrtc=True,
579*800a58d9SAndroid Build Coastguard Worker            webrtc_device_id="pet-name",
580*800a58d9SAndroid Build Coastguard Worker            connect_vnc=True,
581*800a58d9SAndroid Build Coastguard Worker            openwrt=True,
582*800a58d9SAndroid Build Coastguard Worker            num_avds_per_instance=2,
583*800a58d9SAndroid Build Coastguard Worker            base_instance_num=3,
584*800a58d9SAndroid Build Coastguard Worker            launch_args="--setupwizard_mode=REQUIRED")
585*800a58d9SAndroid Build Coastguard Worker        expected_cmd = (
586*800a58d9SAndroid Build Coastguard Worker            "HOME=$HOME/dir dir/bin/launch_cvd -daemon --extra args "
587*800a58d9SAndroid Build Coastguard Worker            "-data_policy=create_if_missing -blank_data_image_mb=20480 "
588*800a58d9SAndroid Build Coastguard Worker            "-config=phone -x_res=1080 -y_res=1920 -dpi=240 "
589*800a58d9SAndroid Build Coastguard Worker            "-data_policy=always_create -blank_data_image_mb=10240 "
590*800a58d9SAndroid Build Coastguard Worker            "-cpus=2 -memory_mb=4096 "
591*800a58d9SAndroid Build Coastguard Worker            "--start_webrtc --vm_manager=crosvm "
592*800a58d9SAndroid Build Coastguard Worker            "--webrtc_device_id=pet-name "
593*800a58d9SAndroid Build Coastguard Worker            "--start_vnc_server=true "
594*800a58d9SAndroid Build Coastguard Worker            "-console=true "
595*800a58d9SAndroid Build Coastguard Worker            "-num_instances=2 --base_instance_num=3 "
596*800a58d9SAndroid Build Coastguard Worker            "--setupwizard_mode=REQUIRED "
597*800a58d9SAndroid Build Coastguard Worker            "-undefok=report_anonymous_usage_stats,config "
598*800a58d9SAndroid Build Coastguard Worker            "-report_anonymous_usage_stats=y")
599*800a58d9SAndroid Build Coastguard Worker        cmd = cvd_utils.GetRemoteLaunchCvdCmd(
600*800a58d9SAndroid Build Coastguard Worker            "dir", mock_avd_spec, "phone", ("--extra", "args"))
601*800a58d9SAndroid Build Coastguard Worker        self.assertEqual(cmd, expected_cmd)
602*800a58d9SAndroid Build Coastguard Worker
603*800a58d9SAndroid Build Coastguard Worker    def testExecuteRemoteLaunchCvd(self):
604*800a58d9SAndroid Build Coastguard Worker        """Test ExecuteRemoteLaunchCvd."""
605*800a58d9SAndroid Build Coastguard Worker        mock_ssh = mock.Mock()
606*800a58d9SAndroid Build Coastguard Worker        error_msg = cvd_utils.ExecuteRemoteLaunchCvd(mock_ssh, "launch_cvd", 1)
607*800a58d9SAndroid Build Coastguard Worker        self.assertFalse(error_msg)
608*800a58d9SAndroid Build Coastguard Worker        mock_ssh.Run.assert_called()
609*800a58d9SAndroid Build Coastguard Worker
610*800a58d9SAndroid Build Coastguard Worker        mock_ssh.Run.side_effect = errors.LaunchCVDFail(
611*800a58d9SAndroid Build Coastguard Worker            "Test unknown command line flag 'start_vnc_server'.")
612*800a58d9SAndroid Build Coastguard Worker        error_msg = cvd_utils.ExecuteRemoteLaunchCvd(mock_ssh, "launch_cvd", 1)
613*800a58d9SAndroid Build Coastguard Worker        self.assertIn("VNC is not supported in the current build.", error_msg)
614*800a58d9SAndroid Build Coastguard Worker
615*800a58d9SAndroid Build Coastguard Worker    def testGetRemoteFetcherConfigJson(self):
616*800a58d9SAndroid Build Coastguard Worker        """Test GetRemoteFetcherConfigJson."""
617*800a58d9SAndroid Build Coastguard Worker        expected_log = {"path": "dir/fetcher_config.json",
618*800a58d9SAndroid Build Coastguard Worker                        "type": constants.LOG_TYPE_CUTTLEFISH_LOG}
619*800a58d9SAndroid Build Coastguard Worker        self.assertEqual(expected_log,
620*800a58d9SAndroid Build Coastguard Worker                         cvd_utils.GetRemoteFetcherConfigJson("dir"))
621*800a58d9SAndroid Build Coastguard Worker
622*800a58d9SAndroid Build Coastguard Worker    @mock.patch("acloud.internal.lib.cvd_utils.utils")
623*800a58d9SAndroid Build Coastguard Worker    def testFindRemoteLogs(self, mock_utils):
624*800a58d9SAndroid Build Coastguard Worker        """Test FindRemoteLogs with the runtime directories in Android 13."""
625*800a58d9SAndroid Build Coastguard Worker        mock_ssh = mock.Mock()
626*800a58d9SAndroid Build Coastguard Worker        mock_utils.FindRemoteFiles.return_value = [
627*800a58d9SAndroid Build Coastguard Worker            "/kernel.log", "/logcat", "/launcher.log", "/access-kregistry",
628*800a58d9SAndroid Build Coastguard Worker            "/cuttlefish_config.json"]
629*800a58d9SAndroid Build Coastguard Worker
630*800a58d9SAndroid Build Coastguard Worker        logs = cvd_utils.FindRemoteLogs(mock_ssh, "dir", None, None)
631*800a58d9SAndroid Build Coastguard Worker        mock_ssh.Run.assert_called_with(
632*800a58d9SAndroid Build Coastguard Worker            "test -d dir/cuttlefish/instances/cvd-1", retry=0)
633*800a58d9SAndroid Build Coastguard Worker        mock_utils.FindRemoteFiles.assert_called_with(
634*800a58d9SAndroid Build Coastguard Worker            mock_ssh, ["dir/cuttlefish/instances/cvd-1"])
635*800a58d9SAndroid Build Coastguard Worker        expected_logs = [
636*800a58d9SAndroid Build Coastguard Worker            {
637*800a58d9SAndroid Build Coastguard Worker                "path": "/kernel.log",
638*800a58d9SAndroid Build Coastguard Worker                "type": constants.LOG_TYPE_KERNEL_LOG,
639*800a58d9SAndroid Build Coastguard Worker                "name": "kernel.log"
640*800a58d9SAndroid Build Coastguard Worker            },
641*800a58d9SAndroid Build Coastguard Worker            {
642*800a58d9SAndroid Build Coastguard Worker                "path": "/logcat",
643*800a58d9SAndroid Build Coastguard Worker                "type": constants.LOG_TYPE_LOGCAT,
644*800a58d9SAndroid Build Coastguard Worker                "name": "full_gce_logcat"
645*800a58d9SAndroid Build Coastguard Worker            },
646*800a58d9SAndroid Build Coastguard Worker            {
647*800a58d9SAndroid Build Coastguard Worker                "path": "/launcher.log",
648*800a58d9SAndroid Build Coastguard Worker                "type": constants.LOG_TYPE_CUTTLEFISH_LOG,
649*800a58d9SAndroid Build Coastguard Worker                "name": "launcher.log"
650*800a58d9SAndroid Build Coastguard Worker            },
651*800a58d9SAndroid Build Coastguard Worker            {
652*800a58d9SAndroid Build Coastguard Worker                "path": "/cuttlefish_config.json",
653*800a58d9SAndroid Build Coastguard Worker                "type": constants.LOG_TYPE_CUTTLEFISH_LOG,
654*800a58d9SAndroid Build Coastguard Worker                "name": "cuttlefish_config.json"
655*800a58d9SAndroid Build Coastguard Worker            },
656*800a58d9SAndroid Build Coastguard Worker            {
657*800a58d9SAndroid Build Coastguard Worker                "path": "dir/cuttlefish/instances/cvd-1/tombstones",
658*800a58d9SAndroid Build Coastguard Worker                "type": constants.LOG_TYPE_DIR,
659*800a58d9SAndroid Build Coastguard Worker                "name": "tombstones-zip"
660*800a58d9SAndroid Build Coastguard Worker            },
661*800a58d9SAndroid Build Coastguard Worker        ]
662*800a58d9SAndroid Build Coastguard Worker        self.assertEqual(expected_logs, logs)
663*800a58d9SAndroid Build Coastguard Worker
664*800a58d9SAndroid Build Coastguard Worker    @mock.patch("acloud.internal.lib.cvd_utils.utils")
665*800a58d9SAndroid Build Coastguard Worker    def testFindRemoteLogsWithLegacyDirs(self, mock_utils):
666*800a58d9SAndroid Build Coastguard Worker        """Test FindRemoteLogs with the runtime directories in Android 11."""
667*800a58d9SAndroid Build Coastguard Worker        mock_ssh = mock.Mock()
668*800a58d9SAndroid Build Coastguard Worker        mock_ssh.Run.side_effect = subprocess.CalledProcessError(
669*800a58d9SAndroid Build Coastguard Worker            cmd="test", returncode=1)
670*800a58d9SAndroid Build Coastguard Worker        mock_utils.FindRemoteFiles.return_value = [
671*800a58d9SAndroid Build Coastguard Worker            "dir/cuttlefish_runtime/kernel.log",
672*800a58d9SAndroid Build Coastguard Worker            "dir/cuttlefish_runtime.4/kernel.log",
673*800a58d9SAndroid Build Coastguard Worker        ]
674*800a58d9SAndroid Build Coastguard Worker
675*800a58d9SAndroid Build Coastguard Worker        logs = cvd_utils.FindRemoteLogs(mock_ssh, "dir", 3, 2)
676*800a58d9SAndroid Build Coastguard Worker        mock_ssh.Run.assert_called_with(
677*800a58d9SAndroid Build Coastguard Worker            "test -d dir/cuttlefish/instances/cvd-3", retry=0)
678*800a58d9SAndroid Build Coastguard Worker        mock_utils.FindRemoteFiles.assert_called_with(
679*800a58d9SAndroid Build Coastguard Worker            mock_ssh, ["dir/cuttlefish_runtime", "dir/cuttlefish_runtime.4"])
680*800a58d9SAndroid Build Coastguard Worker        expected_logs = [
681*800a58d9SAndroid Build Coastguard Worker            {
682*800a58d9SAndroid Build Coastguard Worker                "path": "dir/cuttlefish_runtime/kernel.log",
683*800a58d9SAndroid Build Coastguard Worker                "type": constants.LOG_TYPE_KERNEL_LOG,
684*800a58d9SAndroid Build Coastguard Worker                "name": "kernel.log"
685*800a58d9SAndroid Build Coastguard Worker            },
686*800a58d9SAndroid Build Coastguard Worker            {
687*800a58d9SAndroid Build Coastguard Worker                "path": "dir/cuttlefish_runtime.4/kernel.log",
688*800a58d9SAndroid Build Coastguard Worker                "type": constants.LOG_TYPE_KERNEL_LOG,
689*800a58d9SAndroid Build Coastguard Worker                "name": "kernel.1.log"
690*800a58d9SAndroid Build Coastguard Worker            },
691*800a58d9SAndroid Build Coastguard Worker            {
692*800a58d9SAndroid Build Coastguard Worker                "path": "dir/cuttlefish_runtime/tombstones",
693*800a58d9SAndroid Build Coastguard Worker                "type": constants.LOG_TYPE_DIR,
694*800a58d9SAndroid Build Coastguard Worker                "name": "tombstones-zip"
695*800a58d9SAndroid Build Coastguard Worker            },
696*800a58d9SAndroid Build Coastguard Worker            {
697*800a58d9SAndroid Build Coastguard Worker                "path": "dir/cuttlefish_runtime.4/tombstones",
698*800a58d9SAndroid Build Coastguard Worker                "type": constants.LOG_TYPE_DIR,
699*800a58d9SAndroid Build Coastguard Worker                "name": "tombstones-zip.1"
700*800a58d9SAndroid Build Coastguard Worker            },
701*800a58d9SAndroid Build Coastguard Worker        ]
702*800a58d9SAndroid Build Coastguard Worker        self.assertEqual(expected_logs, logs)
703*800a58d9SAndroid Build Coastguard Worker
704*800a58d9SAndroid Build Coastguard Worker    def testFindLocalLogs(self):
705*800a58d9SAndroid Build Coastguard Worker        """Test FindLocalLogs with the runtime directory in Android 13."""
706*800a58d9SAndroid Build Coastguard Worker        with tempfile.TemporaryDirectory() as temp_dir:
707*800a58d9SAndroid Build Coastguard Worker            log_dir = os.path.join(temp_dir, "instances", "cvd-2", "logs")
708*800a58d9SAndroid Build Coastguard Worker            kernel_log = os.path.join(os.path.join(log_dir, "kernel.log"))
709*800a58d9SAndroid Build Coastguard Worker            launcher_log = os.path.join(os.path.join(log_dir, "launcher.log"))
710*800a58d9SAndroid Build Coastguard Worker            logcat = os.path.join(os.path.join(log_dir, "logcat"))
711*800a58d9SAndroid Build Coastguard Worker            self.CreateFile(kernel_log)
712*800a58d9SAndroid Build Coastguard Worker            self.CreateFile(launcher_log)
713*800a58d9SAndroid Build Coastguard Worker            self.CreateFile(logcat)
714*800a58d9SAndroid Build Coastguard Worker            self.CreateFile(os.path.join(temp_dir, "legacy.log"))
715*800a58d9SAndroid Build Coastguard Worker            self.CreateFile(os.path.join(log_dir, "log.txt"))
716*800a58d9SAndroid Build Coastguard Worker            os.symlink(os.path.join(log_dir, "launcher.log"),
717*800a58d9SAndroid Build Coastguard Worker                       os.path.join(log_dir, "link.log"))
718*800a58d9SAndroid Build Coastguard Worker
719*800a58d9SAndroid Build Coastguard Worker            logs = cvd_utils.FindLocalLogs(temp_dir, 2)
720*800a58d9SAndroid Build Coastguard Worker            expected_logs = [
721*800a58d9SAndroid Build Coastguard Worker                {
722*800a58d9SAndroid Build Coastguard Worker                    "path": kernel_log,
723*800a58d9SAndroid Build Coastguard Worker                    "type": constants.LOG_TYPE_KERNEL_LOG,
724*800a58d9SAndroid Build Coastguard Worker                },
725*800a58d9SAndroid Build Coastguard Worker                {
726*800a58d9SAndroid Build Coastguard Worker                    "path": launcher_log,
727*800a58d9SAndroid Build Coastguard Worker                    "type": constants.LOG_TYPE_CUTTLEFISH_LOG,
728*800a58d9SAndroid Build Coastguard Worker                },
729*800a58d9SAndroid Build Coastguard Worker                {
730*800a58d9SAndroid Build Coastguard Worker                    "path": logcat,
731*800a58d9SAndroid Build Coastguard Worker                    "type": constants.LOG_TYPE_LOGCAT,
732*800a58d9SAndroid Build Coastguard Worker                },
733*800a58d9SAndroid Build Coastguard Worker            ]
734*800a58d9SAndroid Build Coastguard Worker            self.assertEqual(expected_logs,
735*800a58d9SAndroid Build Coastguard Worker                             sorted(logs, key=lambda log: log["path"]))
736*800a58d9SAndroid Build Coastguard Worker
737*800a58d9SAndroid Build Coastguard Worker    def testFindLocalLogsWithLegacyDir(self):
738*800a58d9SAndroid Build Coastguard Worker        """Test FindLocalLogs with the runtime directory in Android 11."""
739*800a58d9SAndroid Build Coastguard Worker        with tempfile.TemporaryDirectory() as temp_dir:
740*800a58d9SAndroid Build Coastguard Worker            log_dir = os.path.join(temp_dir, "cuttlefish_runtime.2")
741*800a58d9SAndroid Build Coastguard Worker            log_dir_link = os.path.join(temp_dir, "cuttlefish_runtime")
742*800a58d9SAndroid Build Coastguard Worker            os.mkdir(log_dir)
743*800a58d9SAndroid Build Coastguard Worker            os.symlink(log_dir, log_dir_link, target_is_directory=True)
744*800a58d9SAndroid Build Coastguard Worker            launcher_log = os.path.join(log_dir_link, "launcher.log")
745*800a58d9SAndroid Build Coastguard Worker            self.CreateFile(launcher_log)
746*800a58d9SAndroid Build Coastguard Worker
747*800a58d9SAndroid Build Coastguard Worker            logs = cvd_utils.FindLocalLogs(log_dir_link, 2)
748*800a58d9SAndroid Build Coastguard Worker            expected_logs = [
749*800a58d9SAndroid Build Coastguard Worker                {
750*800a58d9SAndroid Build Coastguard Worker                    "path": launcher_log,
751*800a58d9SAndroid Build Coastguard Worker                    "type": constants.LOG_TYPE_CUTTLEFISH_LOG,
752*800a58d9SAndroid Build Coastguard Worker                },
753*800a58d9SAndroid Build Coastguard Worker            ]
754*800a58d9SAndroid Build Coastguard Worker            self.assertEqual(expected_logs, logs)
755*800a58d9SAndroid Build Coastguard Worker
756*800a58d9SAndroid Build Coastguard Worker    def testGetOpenWrtInfoDict(self):
757*800a58d9SAndroid Build Coastguard Worker        """Test GetOpenWrtInfoDict."""
758*800a58d9SAndroid Build Coastguard Worker        mock_ssh = mock.Mock()
759*800a58d9SAndroid Build Coastguard Worker        mock_ssh.GetBaseCmd.return_value = "/mock/ssh"
760*800a58d9SAndroid Build Coastguard Worker        openwrt_info = {
761*800a58d9SAndroid Build Coastguard Worker            "ssh_command": "/mock/ssh",
762*800a58d9SAndroid Build Coastguard Worker            "screen_command": "screen ./cuttlefish_runtime/console"}
763*800a58d9SAndroid Build Coastguard Worker        self.assertDictEqual(openwrt_info,
764*800a58d9SAndroid Build Coastguard Worker                             cvd_utils.GetOpenWrtInfoDict(mock_ssh, "."))
765*800a58d9SAndroid Build Coastguard Worker        mock_ssh.GetBaseCmd.assert_called_with("ssh")
766*800a58d9SAndroid Build Coastguard Worker
767*800a58d9SAndroid Build Coastguard Worker    def testGetRemoteBuildInfoDict(self):
768*800a58d9SAndroid Build Coastguard Worker        """Test GetRemoteBuildInfoDict."""
769*800a58d9SAndroid Build Coastguard Worker        remote_image = {
770*800a58d9SAndroid Build Coastguard Worker            "branch": "aosp-android-12-gsi",
771*800a58d9SAndroid Build Coastguard Worker            "build_id": "100000",
772*800a58d9SAndroid Build Coastguard Worker            "build_target": "aosp_cf_x86_64_phone-userdebug"}
773*800a58d9SAndroid Build Coastguard Worker        mock_avd_spec = mock.Mock(
774*800a58d9SAndroid Build Coastguard Worker            spec=[],
775*800a58d9SAndroid Build Coastguard Worker            remote_image=remote_image,
776*800a58d9SAndroid Build Coastguard Worker            kernel_build_info={"build_target": "kernel"},
777*800a58d9SAndroid Build Coastguard Worker            system_build_info={},
778*800a58d9SAndroid Build Coastguard Worker            bootloader_build_info={},
779*800a58d9SAndroid Build Coastguard Worker            android_efi_loader_build_info = {})
780*800a58d9SAndroid Build Coastguard Worker        self.assertEqual(remote_image,
781*800a58d9SAndroid Build Coastguard Worker                         cvd_utils.GetRemoteBuildInfoDict(mock_avd_spec))
782*800a58d9SAndroid Build Coastguard Worker
783*800a58d9SAndroid Build Coastguard Worker        kernel_build_info = {
784*800a58d9SAndroid Build Coastguard Worker            "branch": "aosp_kernel-common-android12-5.10",
785*800a58d9SAndroid Build Coastguard Worker            "build_id": "200000",
786*800a58d9SAndroid Build Coastguard Worker            "build_target": "kernel_virt_x86_64"}
787*800a58d9SAndroid Build Coastguard Worker        system_build_info = {
788*800a58d9SAndroid Build Coastguard Worker            "branch": "aosp-android-12-gsi",
789*800a58d9SAndroid Build Coastguard Worker            "build_id": "300000",
790*800a58d9SAndroid Build Coastguard Worker            "build_target": "aosp_x86_64-userdebug"}
791*800a58d9SAndroid Build Coastguard Worker        bootloader_build_info = {
792*800a58d9SAndroid Build Coastguard Worker            "branch": "aosp_u-boot-mainline",
793*800a58d9SAndroid Build Coastguard Worker            "build_id": "400000",
794*800a58d9SAndroid Build Coastguard Worker            "build_target": "u-boot_crosvm_x86_64"}
795*800a58d9SAndroid Build Coastguard Worker        android_efi_loader_build_info = {
796*800a58d9SAndroid Build Coastguard Worker            "build_id": "500000",
797*800a58d9SAndroid Build Coastguard Worker            "artifact": "gbl_aarch64.efi"
798*800a58d9SAndroid Build Coastguard Worker        }
799*800a58d9SAndroid Build Coastguard Worker        all_build_info = {
800*800a58d9SAndroid Build Coastguard Worker            "kernel_branch": "aosp_kernel-common-android12-5.10",
801*800a58d9SAndroid Build Coastguard Worker            "kernel_build_id": "200000",
802*800a58d9SAndroid Build Coastguard Worker            "kernel_build_target": "kernel_virt_x86_64",
803*800a58d9SAndroid Build Coastguard Worker            "system_branch": "aosp-android-12-gsi",
804*800a58d9SAndroid Build Coastguard Worker            "system_build_id": "300000",
805*800a58d9SAndroid Build Coastguard Worker            "system_build_target": "aosp_x86_64-userdebug",
806*800a58d9SAndroid Build Coastguard Worker            "bootloader_branch": "aosp_u-boot-mainline",
807*800a58d9SAndroid Build Coastguard Worker            "bootloader_build_id": "400000",
808*800a58d9SAndroid Build Coastguard Worker            "bootloader_build_target": "u-boot_crosvm_x86_64",
809*800a58d9SAndroid Build Coastguard Worker            "android_efi_loader_build_id": "500000",
810*800a58d9SAndroid Build Coastguard Worker            "android_efi_loader_artifact": "gbl_aarch64.efi"
811*800a58d9SAndroid Build Coastguard Worker        }
812*800a58d9SAndroid Build Coastguard Worker        all_build_info.update(remote_image)
813*800a58d9SAndroid Build Coastguard Worker        mock_avd_spec = mock.Mock(
814*800a58d9SAndroid Build Coastguard Worker            spec=[],
815*800a58d9SAndroid Build Coastguard Worker            remote_image=remote_image,
816*800a58d9SAndroid Build Coastguard Worker            kernel_build_info=kernel_build_info,
817*800a58d9SAndroid Build Coastguard Worker            system_build_info=system_build_info,
818*800a58d9SAndroid Build Coastguard Worker            bootloader_build_info=bootloader_build_info,
819*800a58d9SAndroid Build Coastguard Worker            android_efi_loader_build_info=android_efi_loader_build_info)
820*800a58d9SAndroid Build Coastguard Worker        self.assertEqual(all_build_info,
821*800a58d9SAndroid Build Coastguard Worker                         cvd_utils.GetRemoteBuildInfoDict(mock_avd_spec))
822*800a58d9SAndroid Build Coastguard Worker
823*800a58d9SAndroid Build Coastguard Worker    def testFindMiscInfo(self):
824*800a58d9SAndroid Build Coastguard Worker        """Test FindMiscInfo."""
825*800a58d9SAndroid Build Coastguard Worker        with tempfile.TemporaryDirectory() as temp_dir:
826*800a58d9SAndroid Build Coastguard Worker            with self.assertRaises(errors.CheckPathError):
827*800a58d9SAndroid Build Coastguard Worker                cvd_utils.FindMiscInfo(temp_dir)
828*800a58d9SAndroid Build Coastguard Worker            misc_info_path = os.path.join(temp_dir, "META", "misc_info.txt")
829*800a58d9SAndroid Build Coastguard Worker            self.CreateFile(misc_info_path, b"key=value")
830*800a58d9SAndroid Build Coastguard Worker            self.assertEqual(misc_info_path, cvd_utils.FindMiscInfo(temp_dir))
831*800a58d9SAndroid Build Coastguard Worker
832*800a58d9SAndroid Build Coastguard Worker    def testFindImageDir(self):
833*800a58d9SAndroid Build Coastguard Worker        """Test FindImageDir."""
834*800a58d9SAndroid Build Coastguard Worker        with tempfile.TemporaryDirectory() as temp_dir:
835*800a58d9SAndroid Build Coastguard Worker            with self.assertRaises(errors.GetLocalImageError):
836*800a58d9SAndroid Build Coastguard Worker                cvd_utils.FindImageDir(temp_dir)
837*800a58d9SAndroid Build Coastguard Worker            image_dir = os.path.join(temp_dir, "IMAGES")
838*800a58d9SAndroid Build Coastguard Worker            self.CreateFile(os.path.join(image_dir, "super.img"))
839*800a58d9SAndroid Build Coastguard Worker            self.assertEqual(image_dir, cvd_utils.FindImageDir(temp_dir))
840*800a58d9SAndroid Build Coastguard Worker
841*800a58d9SAndroid Build Coastguard Worker
842*800a58d9SAndroid Build Coastguard Workerif __name__ == "__main__":
843*800a58d9SAndroid Build Coastguard Worker    unittest.main()
844