• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2019 - The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14"""Tests for remote_instance_cf_device_factory."""
15
16import glob
17import os
18import shutil
19import subprocess
20import tempfile
21import unittest
22import uuid
23
24from unittest import mock
25
26import six
27
28from acloud.create import avd_spec
29from acloud.internal import constants
30from acloud.internal.lib import android_build_client
31from acloud.internal.lib import auth
32from acloud.internal.lib import cvd_compute_client_multi_stage
33from acloud.internal.lib import driver_test_lib
34from acloud.internal.lib import ssh
35from acloud.internal.lib import utils
36from acloud.list import list as list_instances
37from acloud.public.actions import remote_instance_cf_device_factory
38
39
40class RemoteInstanceDeviceFactoryTest(driver_test_lib.BaseDriverTest):
41    """Test RemoteInstanceDeviceFactory method."""
42
43    def setUp(self):
44        """Set up the test."""
45        super().setUp()
46        self.Patch(auth, "CreateCredentials", return_value=mock.MagicMock())
47        self.Patch(android_build_client.AndroidBuildClient, "InitResourceHandle")
48        self.Patch(cvd_compute_client_multi_stage.CvdComputeClient, "InitResourceHandle")
49        self.Patch(list_instances, "GetInstancesFromInstanceNames", return_value=mock.MagicMock())
50        self.Patch(list_instances, "ChooseOneRemoteInstance", return_value=mock.MagicMock())
51        self.Patch(utils, "GetBuildEnvironmentVariable",
52                   return_value="test_env_cf_arm")
53        self.Patch(glob, "glob", return_vale=["fake.img"])
54
55    # pylint: disable=protected-access
56    @mock.patch.object(remote_instance_cf_device_factory.RemoteInstanceDeviceFactory,
57                       "_FetchBuild")
58    @mock.patch.object(remote_instance_cf_device_factory.RemoteInstanceDeviceFactory,
59                       "_UploadLocalImageArtifacts")
60    def testProcessArtifacts(self, mock_upload, mock_download):
61        """test ProcessArtifacts."""
62        # Test image source type is local.
63        args = mock.MagicMock()
64        args.config_file = ""
65        args.avd_type = constants.TYPE_CF
66        args.flavor = "phone"
67        args.local_image = constants.FIND_IN_BUILD_ENV
68        args.local_system_image = None
69        args.launch_args = None
70        avd_spec_local_img = avd_spec.AVDSpec(args)
71        fake_image_name = "/fake/aosp_cf_x86_phone-img-eng.username.zip"
72        fake_host_package_name = "/fake/host_package.tar.gz"
73        factory_local_img = remote_instance_cf_device_factory.RemoteInstanceDeviceFactory(
74            avd_spec_local_img,
75            fake_image_name,
76            fake_host_package_name)
77        factory_local_img._ProcessArtifacts(constants.IMAGE_SRC_LOCAL)
78        self.assertEqual(mock_upload.call_count, 1)
79
80        # Test image source type is remote.
81        args.local_image = None
82        args.build_id = "1234"
83        args.branch = "fake_branch"
84        args.build_target = "fake_target"
85        args.system_build_id = "2345"
86        args.system_branch = "sys_branch"
87        args.system_build_target = "sys_target"
88        args.kernel_build_id = "3456"
89        args.kernel_branch = "kernel_branch"
90        args.kernel_build_target = "kernel_target"
91        avd_spec_remote_img = avd_spec.AVDSpec(args)
92        self.Patch(cvd_compute_client_multi_stage.CvdComputeClient, "UpdateFetchCvd")
93        factory_remote_img = remote_instance_cf_device_factory.RemoteInstanceDeviceFactory(
94            avd_spec_remote_img)
95        factory_remote_img._ProcessArtifacts(constants.IMAGE_SRC_REMOTE)
96        self.assertEqual(mock_download.call_count, 1)
97
98    # pylint: disable=protected-access
99    @mock.patch.dict(os.environ, {constants.ENV_BUILD_TARGET:'fake-target'})
100    def testCreateGceInstanceNameMultiStage(self):
101        """test create gce instance."""
102        # Mock uuid
103        args = mock.MagicMock()
104        args.config_file = ""
105        args.avd_type = constants.TYPE_CF
106        args.flavor = "phone"
107        args.local_image = constants.FIND_IN_BUILD_ENV
108        args.local_system_image = None
109        args.adb_port = None
110        args.launch_args = None
111        fake_avd_spec = avd_spec.AVDSpec(args)
112        fake_avd_spec.cfg.enable_multi_stage = True
113        fake_avd_spec._instance_name_to_reuse = None
114
115        fake_uuid = mock.MagicMock(hex="1234")
116        self.Patch(uuid, "uuid4", return_value=fake_uuid)
117        self.Patch(cvd_compute_client_multi_stage.CvdComputeClient, "CreateInstance")
118        self.Patch(cvd_compute_client_multi_stage.CvdComputeClient,
119                   "GetHostImageName", return_value="fake_image")
120        fake_host_package_name = "/fake/host_package.tar.gz"
121        fake_image_name = "/fake/aosp_cf_x86_phone-img-eng.username.zip"
122
123        factory = remote_instance_cf_device_factory.RemoteInstanceDeviceFactory(
124            fake_avd_spec,
125            fake_image_name,
126            fake_host_package_name)
127        self.assertEqual(factory._CreateGceInstance(), "ins-1234-userbuild-aosp-cf-x86-phone")
128
129        # Can't get target name from zip file name.
130        fake_image_name = "/fake/aosp_cf_x86_phone.username.zip"
131        factory = remote_instance_cf_device_factory.RemoteInstanceDeviceFactory(
132            fake_avd_spec,
133            fake_image_name,
134            fake_host_package_name)
135        self.assertEqual(factory._CreateGceInstance(), "ins-1234-userbuild-fake-target")
136
137        # No image zip path, it uses local build images.
138        fake_image_name = ""
139        factory = remote_instance_cf_device_factory.RemoteInstanceDeviceFactory(
140            fake_avd_spec,
141            fake_image_name,
142            fake_host_package_name)
143        self.assertEqual(factory._CreateGceInstance(), "ins-1234-userbuild-fake-target")
144
145    @mock.patch.dict(os.environ, {constants.ENV_BUILD_TARGET:'fake-target'})
146    def testRemoteHostInstanceName(self):
147        """Test Remote host instance name."""
148        args = mock.MagicMock()
149        args.config_file = ""
150        args.avd_type = constants.TYPE_CF
151        args.flavor = "phone"
152        args.remote_host = "1.1.1.1"
153        args.local_image = constants.FIND_IN_BUILD_ENV
154        args.local_system_image = None
155        args.adb_port = None
156        args.launch_args = None
157        fake_avd_spec = avd_spec.AVDSpec(args)
158        fake_avd_spec.cfg.enable_multi_stage = True
159        fake_avd_spec._instance_name_to_reuse = None
160        fake_uuid = mock.MagicMock(hex="1234")
161        self.Patch(uuid, "uuid4", return_value=fake_uuid)
162        self.Patch(cvd_compute_client_multi_stage.CvdComputeClient, "CreateInstance")
163        self.Patch(cvd_compute_client_multi_stage.CvdComputeClient, "InitRemoteHost")
164        fake_host_package_name = "/fake/host_package.tar.gz"
165
166        fake_image_name = "/fake/aosp_cf_x86_phone-img-eng.username.zip"
167        factory = remote_instance_cf_device_factory.RemoteInstanceDeviceFactory(
168            fake_avd_spec,
169            fake_image_name,
170            fake_host_package_name)
171        self.assertEqual(factory._InitRemotehost(), "host-1.1.1.1-userbuild-aosp_cf_x86_phone")
172
173        # No image zip path, it uses local build images.
174        fake_image_name = ""
175        factory = remote_instance_cf_device_factory.RemoteInstanceDeviceFactory(
176            fake_avd_spec,
177            fake_image_name,
178            fake_host_package_name)
179        self.assertEqual(factory._InitRemotehost(), "host-1.1.1.1-userbuild-fake-target")
180
181    def testReuseInstanceNameMultiStage(self):
182        """Test reuse instance name."""
183        args = mock.MagicMock()
184        args.config_file = ""
185        args.avd_type = constants.TYPE_CF
186        args.flavor = "phone"
187        args.local_image = constants.FIND_IN_BUILD_ENV
188        args.local_system_image = None
189        args.adb_port = None
190        args.launch_args = None
191        fake_avd_spec = avd_spec.AVDSpec(args)
192        fake_avd_spec.cfg.enable_multi_stage = True
193        fake_avd_spec._instance_name_to_reuse = "fake-1234-userbuild-fake-target"
194        fake_uuid = mock.MagicMock(hex="1234")
195        self.Patch(uuid, "uuid4", return_value=fake_uuid)
196        self.Patch(cvd_compute_client_multi_stage.CvdComputeClient, "CreateInstance")
197        self.Patch(cvd_compute_client_multi_stage.CvdComputeClient,
198                   "GetHostImageName", return_value="fake_image")
199        fake_host_package_name = "/fake/host_package.tar.gz"
200        fake_image_name = "/fake/aosp_cf_x86_phone-img-eng.username.zip"
201        factory = remote_instance_cf_device_factory.RemoteInstanceDeviceFactory(
202            fake_avd_spec,
203            fake_image_name,
204            fake_host_package_name)
205        self.assertEqual(factory._CreateGceInstance(), "fake-1234-userbuild-fake-target")
206
207    def testGetBuildInfoDict(self):
208        """Test GetBuildInfoDict."""
209        fake_host_package_name = "/fake/host_package.tar.gz"
210        fake_image_name = "/fake/aosp_cf_x86_phone-img-eng.username.zip"
211        args = mock.MagicMock()
212        # Test image source type is local.
213        args.config_file = ""
214        args.avd_type = constants.TYPE_CF
215        args.flavor = "phone"
216        args.local_image = "fake_local_image"
217        args.local_system_image = None
218        args.adb_port = None
219        args.cheeps_betty_image = None
220        args.launch_args = None
221        avd_spec_local_image = avd_spec.AVDSpec(args)
222        factory = remote_instance_cf_device_factory.RemoteInstanceDeviceFactory(
223            avd_spec_local_image,
224            fake_image_name,
225            fake_host_package_name)
226        self.assertEqual(factory.GetBuildInfoDict(), None)
227
228        # Test image source type is remote.
229        args.local_image = None
230        args.build_id = "123"
231        args.branch = "fake_branch"
232        args.build_target = "fake_target"
233        args.system_build_id = "234"
234        args.system_branch = "sys_branch"
235        args.system_build_target = "sys_target"
236        args.kernel_build_id = "345"
237        args.kernel_branch = "kernel_branch"
238        args.kernel_build_target = "kernel_target"
239        args.bootloader_build_id = "456"
240        args.bootloader_branch = "bootloader_branch"
241        args.bootloader_build_target = "bootloader_target"
242        avd_spec_remote_image = avd_spec.AVDSpec(args)
243        factory = remote_instance_cf_device_factory.RemoteInstanceDeviceFactory(
244            avd_spec_remote_image,
245            fake_image_name,
246            fake_host_package_name)
247        expected_build_info = {
248            "build_id": "123",
249            "branch": "fake_branch",
250            "build_target": "fake_target",
251            "system_build_id": "234",
252            "system_branch": "sys_branch",
253            "system_build_target": "sys_target",
254            "kernel_build_id": "345",
255            "kernel_branch": "kernel_branch",
256            "kernel_build_target": "kernel_target",
257            "bootloader_build_id": "456",
258            "bootloader_branch": "bootloader_branch",
259            "bootloader_build_target": "bootloader_target"
260        }
261        self.assertEqual(factory.GetBuildInfoDict(), expected_build_info)
262
263    @mock.patch.object(ssh, "ShellCmdWithRetry")
264    @mock.patch.object(ssh.Ssh, "Run")
265    def testUploadArtifacts(self, mock_ssh_run, mock_shell):
266        """Test UploadArtifacts."""
267        fake_host_package = "/fake/host_package.tar.gz"
268        fake_image = "/fake/aosp_cf_x86_phone-img-eng.username.zip"
269        fake_local_image_dir = "/fake_image"
270        fake_ip = ssh.IP(external="1.1.1.1", internal="10.1.1.1")
271        args = mock.MagicMock()
272        # Test local image extract from image zip case.
273        args.config_file = ""
274        args.avd_type = constants.TYPE_CF
275        args.flavor = "phone"
276        args.local_image = "fake_local_image"
277        args.local_system_image = None
278        args.adb_port = None
279        args.launch_args = None
280        avd_spec_local_image = avd_spec.AVDSpec(args)
281        factory = remote_instance_cf_device_factory.RemoteInstanceDeviceFactory(
282            avd_spec_local_image,
283            fake_image,
284            fake_host_package)
285        factory._ssh = ssh.Ssh(ip=fake_ip,
286                               user=constants.GCE_USER,
287                               ssh_private_key_path="/fake/acloud_rea")
288        factory._UploadLocalImageArtifacts(fake_image,
289                                           fake_host_package,
290                                           fake_local_image_dir)
291        expected_cmd1 = ("/usr/bin/install_zip.sh . < %s" % fake_image)
292        expected_cmd2 = ("tar -x -z -f - < %s" % fake_host_package)
293        mock_ssh_run.assert_has_calls([
294            mock.call(expected_cmd1),
295            mock.call(expected_cmd2)])
296
297        # Test local image get from local folder case.
298        fake_image = None
299        self.Patch(glob, "glob", side_effect=[["fake.img"], ["bootloader"], ["kernel"]])
300        factory._UploadLocalImageArtifacts(fake_image,
301                                           fake_host_package,
302                                           fake_local_image_dir)
303        expected_cmd = (
304            "tar -cf - --lzop -S -C %s fake.img bootloader kernel | "
305            "%s -- tar -xf - --lzop -S" %
306            (fake_local_image_dir, factory._ssh.GetBaseCmd(constants.SSH_BIN)))
307        mock_shell.assert_called_once_with(expected_cmd)
308
309        mock_shell.reset_mock()
310        required_images = mock.mock_open(read_data=(
311            "boot.img\n"
312            "cache.img\n"
313            "super.img\n"
314            "userdata.img\n"
315            "bootloader\n"))
316        with mock.patch.object(six.moves.builtins, "open", required_images):
317            factory._UploadLocalImageArtifacts(fake_image,
318                                               fake_host_package,
319                                               fake_local_image_dir)
320            expected_cmd = (
321                "tar -cf - --lzop -S -C %s boot.img cache.img super.img userdata.img bootloader | "
322                "%s -- tar -xf - --lzop -S" %
323                (fake_local_image_dir, factory._ssh.GetBaseCmd(constants.SSH_BIN)))
324            mock_shell.assert_called_once_with(expected_cmd)
325
326    @mock.patch.object(ssh, "ShellCmdWithRetry")
327    def testUploadRemoteImageArtifacts(self, mock_shell):
328        """Test UploadRemoteImageArtifacts."""
329        fake_host_package = "/fake/host_package.tar.gz"
330        fake_image_zip = None
331        fake_local_image_dir = "/fake_image"
332        fake_ip = ssh.IP(external="1.1.1.1", internal="10.1.1.1")
333        args = mock.MagicMock()
334        # Test local image extract from image zip case.
335        args.config_file = ""
336        args.avd_type = constants.TYPE_CF
337        args.flavor = "phone"
338        args.local_image = "fake_local_image"
339        args.local_system_image = None
340        args.adb_port = None
341        args.launch_args = None
342        avd_spec_local_image = avd_spec.AVDSpec(args)
343        factory = remote_instance_cf_device_factory.RemoteInstanceDeviceFactory(
344            avd_spec_local_image,
345            fake_image_zip,
346            fake_host_package)
347        factory._ssh = ssh.Ssh(ip=fake_ip,
348                               user=constants.GCE_USER,
349                               ssh_private_key_path="/fake/acloud_rea")
350
351        self.Patch(glob, "glob", return_value=["fake.img", "bootloader", "kernel"])
352        factory._UploadRemoteImageArtifacts(fake_local_image_dir)
353
354        expected_cmd = (
355            "tar -cf - --lzop -S -C %s fake.img bootloader kernel | "
356            "%s -- tar -xf - --lzop -S" %
357            (fake_local_image_dir, factory._ssh.GetBaseCmd(constants.SSH_BIN)))
358        mock_shell.assert_called_once_with(expected_cmd)
359
360    @mock.patch.object(remote_instance_cf_device_factory.RemoteInstanceDeviceFactory,
361                       "_InitRemotehost")
362    @mock.patch.object(remote_instance_cf_device_factory.RemoteInstanceDeviceFactory,
363                       "_UploadLocalImageArtifacts")
364    @mock.patch.object(remote_instance_cf_device_factory.RemoteInstanceDeviceFactory,
365                       "_LaunchCvd")
366    def testLocalImageRemoteHost(self, mock_launchcvd, mock_upload, mock_init_remote_host):
367        """Test local image with remote host."""
368        self.Patch(
369            cvd_compute_client_multi_stage,
370            "CvdComputeClient",
371            return_value=mock.MagicMock())
372        fake_avd_spec = mock.MagicMock()
373        fake_avd_spec.instance_type = constants.INSTANCE_TYPE_HOST
374        fake_avd_spec.image_source = constants.IMAGE_SRC_LOCAL
375        fake_avd_spec._instance_name_to_reuse = None
376        fake_host_package_name = "/fake/host_package.tar.gz"
377        fake_image_name = ""
378        factory = remote_instance_cf_device_factory.RemoteInstanceDeviceFactory(
379            fake_avd_spec,
380            fake_image_name,
381            fake_host_package_name)
382        factory.CreateInstance()
383        self.assertEqual(mock_init_remote_host.call_count, 1)
384        self.assertEqual(mock_upload.call_count, 1)
385        self.assertEqual(mock_launchcvd.call_count, 1)
386
387    @mock.patch.object(remote_instance_cf_device_factory.RemoteInstanceDeviceFactory,
388                       "_CreateGceInstance")
389    @mock.patch.object(remote_instance_cf_device_factory.RemoteInstanceDeviceFactory,
390                       "_UploadLocalImageArtifacts")
391    @mock.patch.object(remote_instance_cf_device_factory.RemoteInstanceDeviceFactory,
392                       "_LaunchCvd")
393    def testLocalImageCreateInstance(self, mock_launchcvd, mock_upload, mock_create_gce_instance):
394        """Test local image with create instance."""
395        self.Patch(
396            cvd_compute_client_multi_stage,
397            "CvdComputeClient",
398            return_value=mock.MagicMock())
399        fake_avd_spec = mock.MagicMock()
400        fake_avd_spec.instance_type = constants.INSTANCE_TYPE_REMOTE
401        fake_avd_spec.image_source = constants.IMAGE_SRC_LOCAL
402        fake_avd_spec._instance_name_to_reuse = None
403        fake_host_package_name = "/fake/host_package.tar.gz"
404        fake_image_name = ""
405        factory = remote_instance_cf_device_factory.RemoteInstanceDeviceFactory(
406            fake_avd_spec,
407            fake_image_name,
408            fake_host_package_name)
409        factory.CreateInstance()
410        self.assertEqual(mock_create_gce_instance.call_count, 1)
411        self.assertEqual(mock_upload.call_count, 1)
412        self.assertEqual(mock_launchcvd.call_count, 1)
413
414    # pylint: disable=no-member
415    @mock.patch.object(subprocess, "check_call")
416    def testDownloadArtifacts(self, mock_check_call):
417        """Test process remote cuttlefish image."""
418        extract_path = "/tmp/1111/"
419        fake_remote_image = {"build_target" : "aosp_cf_x86_phone-userdebug",
420                             "branch" : "aosp-master",
421                             "build_id": "1234"}
422        self.Patch(
423            cvd_compute_client_multi_stage,
424            "CvdComputeClient",
425            return_value=mock.MagicMock())
426        self.Patch(tempfile, "mkdtemp", return_value="/tmp/1111/")
427        self.Patch(shutil, "rmtree")
428        fake_avd_spec = mock.MagicMock()
429        fake_avd_spec.cfg = mock.MagicMock()
430        fake_avd_spec.cfg.creds_cache_file = "cache.file"
431        fake_avd_spec.remote_image = fake_remote_image
432        fake_avd_spec.image_download_dir = "/tmp"
433        self.Patch(os.path, "exists", return_value=False)
434        self.Patch(os, "makedirs")
435        factory = remote_instance_cf_device_factory.RemoteInstanceDeviceFactory(
436            fake_avd_spec)
437
438        factory._DownloadArtifacts(extract_path)
439        self.assertEqual(mock_check_call.call_count, 1)
440
441    @mock.patch.object(remote_instance_cf_device_factory.RemoteInstanceDeviceFactory,
442                       "_UploadLocalImageArtifacts")
443    @mock.patch.object(remote_instance_cf_device_factory.RemoteInstanceDeviceFactory,
444                       "_UploadRemoteImageArtifacts")
445    def testProcessRemoteHostArtifacts(self,
446                                       mock_upload_remote_image,
447                                       mock_upload_local_image):
448        """Test process remote host artifacts."""
449        self.Patch(
450            cvd_compute_client_multi_stage,
451            "CvdComputeClient",
452            return_value=mock.MagicMock())
453        fake_avd_spec = mock.MagicMock()
454
455        # Test process remote host artifacts with local images.
456        fake_avd_spec.instance_type = constants.INSTANCE_TYPE_HOST
457        fake_avd_spec.image_source = constants.IMAGE_SRC_LOCAL
458        fake_avd_spec._instance_name_to_reuse = None
459        fake_avd_spec.cfg = mock.MagicMock()
460        fake_avd_spec.cfg.creds_cache_file = "cache.file"
461        fake_host_package_name = "/fake/host_package.tar.gz"
462        fake_image_name = ""
463        factory = remote_instance_cf_device_factory.RemoteInstanceDeviceFactory(
464            fake_avd_spec,
465            fake_image_name,
466            fake_host_package_name)
467        factory._ProcessRemoteHostArtifacts()
468        self.assertEqual(mock_upload_local_image.call_count, 1)
469
470        # Test process remote host artifacts with remote images.
471        fake_tmp_folder = "/tmp/1111/"
472        self.Patch(tempfile, "mkdtemp", return_value=fake_tmp_folder)
473        self.Patch(shutil, "rmtree")
474        self.Patch(subprocess, "check_call")
475        fake_avd_spec.instance_type = constants.INSTANCE_TYPE_HOST
476        fake_avd_spec.image_source = constants.IMAGE_SRC_REMOTE
477        fake_avd_spec._instance_name_to_reuse = None
478        factory = remote_instance_cf_device_factory.RemoteInstanceDeviceFactory(
479            fake_avd_spec)
480        factory._ProcessRemoteHostArtifacts()
481        self.assertEqual(mock_upload_remote_image.call_count, 1)
482        shutil.rmtree.assert_called_once_with(fake_tmp_folder)
483
484
485if __name__ == "__main__":
486    unittest.main()
487