xref: /aosp_15_r20/tools/acloud/create/goldfish_local_image_local_instance_test.py (revision 800a58d989c669b8eb8a71d8df53b1ba3d411444)
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 GoldfishLocalImageLocalInstance."""
15
16import os
17import shutil
18import tempfile
19import unittest
20
21from unittest import mock
22
23from acloud import errors
24import acloud.create.goldfish_local_image_local_instance as instance_module
25from acloud.internal.lib import driver_test_lib
26
27
28class GoldfishLocalImageLocalInstance(driver_test_lib.BaseDriverTest):
29    """Test GoldfishLocalImageLocalInstance methods."""
30
31    def setUp(self):
32        self._goldfish = instance_module.GoldfishLocalImageLocalInstance()
33        self._temp_dir = tempfile.mkdtemp()
34        self._image_dir = os.path.join(self._temp_dir, "images")
35        self._tool_dir = os.path.join(self._temp_dir, "tool")
36        self._instance_dir = os.path.join(self._temp_dir, "instance")
37        self._emulator_is_running = False
38        self._mock_lock = mock.Mock()
39        self._mock_lock.Lock.return_value = True
40        self._mock_lock.LockIfNotInUse.side_effect = (False, True)
41        self._mock_proc = mock.Mock()
42        self._mock_proc.poll.side_effect = (
43            lambda: None if self._emulator_is_running else 0)
44
45        os.mkdir(self._image_dir)
46        os.mkdir(self._tool_dir)
47
48        # Create emulator binary
49        self._emulator_path = os.path.join(self._tool_dir, "emulator",
50                                           "emulator")
51        self._CreateEmptyFile(self._emulator_path)
52
53    def tearDown(self):
54        shutil.rmtree(self._temp_dir, ignore_errors=True)
55
56    @staticmethod
57    def _CreateEmptyFile(path):
58        parent_dir = os.path.dirname(path)
59        if not os.path.exists(parent_dir):
60            os.makedirs(parent_dir)
61        with open(path, "w") as _:
62            pass
63
64    def _MockMixDiskImage(self, output_dir, *_args):
65        """Mock goldfish_utils.MixDiskImage."""
66        self.assertEqual(os.path.join(self._instance_dir, "mix_disk"),
67                         output_dir)
68        output_path = os.path.join(output_dir, "mixed_disk.img")
69        self._CreateEmptyFile(output_path)
70        return output_path
71
72    def _MockMixWithBootImage(self, output_dir, *_args):
73        """Mock goldfish_utils.MixWithBootImage."""
74        self.assertEqual(os.path.join(self._instance_dir, "mix_kernel"),
75                         output_dir)
76        return (os.path.join(output_dir, "kernel"),
77                os.path.join(output_dir, "ramdisk"))
78
79    def _MockPopen(self, *_args, **_kwargs):
80        self._emulator_is_running = True
81        return self._mock_proc
82
83    def _MockEmuCommand(self, *args):
84        if not self._emulator_is_running:
85            # Connection refused
86            return 1
87
88        if args == ("kill",):
89            self._emulator_is_running = False
90            return 0
91
92        if args == ():
93            return 0
94
95        raise ValueError("Unexpected arguments " + str(args))
96
97    def _SetUpMocks(self, mock_popen, mock_utils, mock_instance,
98                    mock_gf_utils):
99        mock_utils.IsSupportedPlatform.return_value = True
100
101        mock_adb_tools = mock.Mock(side_effect=self._MockEmuCommand)
102
103        mock_instance_object = mock.Mock(ip="127.0.0.1",
104                                         adb_port=5555,
105                                         console_port="5554",
106                                         device_serial="unittest",
107                                         instance_dir=self._instance_dir,
108                                         adb=mock_adb_tools)
109        # name is a positional argument of Mock().
110        mock_instance_object.name = "local-goldfish-instance"
111
112        mock_instance.return_value = mock_instance_object
113        mock_instance.GetLockById.return_value = self._mock_lock
114        mock_instance.GetMaxNumberOfInstances.return_value = 2
115
116        mock_popen.side_effect = self._MockPopen
117
118        mock_gf_utils.SYSTEM_QEMU_IMAGE_NAME = "system-qemu.img"
119        mock_gf_utils.VERIFIED_BOOT_PARAMS_FILE_NAME = (
120            "VerifiedBootParams.textproto")
121        mock_gf_utils.MixDiskImage.side_effect = self._MockMixDiskImage
122        mock_gf_utils.MixWithBootImage.side_effect = self._MockMixWithBootImage
123        mock_gf_utils.ConvertAvdSpecToArgs.return_value = ["-gpu", "auto"]
124
125    def _CreateMockAvdSpec(self, local_instance_id, autoconnect=True,
126                           boot_timeout_secs=None,
127                           local_instance_dir=None, local_kernel_image=None,
128                           local_system_image=None, local_tool_dirs=None):
129        """Return a mock avd_spec.AvdSpec with needed attributes."""
130        attr_dict = {
131            "autoconnect": autoconnect,
132            "boot_timeout_secs": boot_timeout_secs,
133            "flavor": "phone",
134            "local_image_dir": self._image_dir,
135            "local_instance_id": local_instance_id,
136            "local_instance_dir": local_instance_dir,
137            "local_kernel_image": local_kernel_image,
138            "local_system_image": local_system_image,
139            "local_tool_dirs": local_tool_dirs or [],
140        }
141        mock_avd_spec = mock.Mock(spec=list(attr_dict), **attr_dict)
142        return mock_avd_spec
143
144    def _GetExpectedEmulatorArgs(self, *extra_args):
145        cmd = [
146            self._emulator_path, "-verbose", "-show-kernel", "-read-only",
147            "-ports", "5554,5555",
148            "-logcat-output",
149            os.path.join(self._instance_dir, "logcat.txt"),
150            "-stdouterr-file",
151            os.path.join(self._instance_dir, "kernel.log"),
152            "-gpu", "auto"
153        ]
154        cmd.extend(extra_args)
155        return cmd
156
157    def _GetExpectedDevicesInReport(self):
158        logcat_path = os.path.join(self._instance_dir, "logcat.txt")
159        stdouterr_path = os.path.join(self._instance_dir, "kernel.log")
160        return [
161            {
162                "instance_name": "local-goldfish-instance",
163                "ip": "127.0.0.1:5555",
164                "adb_port": 5555,
165                "device_serial": "unittest",
166                "logs": [
167                    {"path": logcat_path, "type": "LOGCAT"},
168                    {"path": stdouterr_path, "type": "KERNEL_LOG"}
169                ]
170            }
171        ]
172
173    # pylint: disable=protected-access
174    @mock.patch("acloud.create.goldfish_local_image_local_instance.instance."
175                "LocalGoldfishInstance")
176    @mock.patch("acloud.create.goldfish_local_image_local_instance.utils")
177    @mock.patch("acloud.create.goldfish_local_image_local_instance."
178                "subprocess.Popen")
179    @mock.patch("acloud.create.goldfish_local_image_local_instance."
180                "goldfish_utils")
181    def testCreateAVDInBuildEnvironment(self, mock_gf_utils, mock_popen,
182                                        mock_utils, mock_instance):
183        """Test _CreateAVD with build environment variables and files."""
184        self._SetUpMocks(mock_popen, mock_utils, mock_instance, mock_gf_utils)
185
186        self._CreateEmptyFile(os.path.join(self._image_dir,
187                                           "system-qemu.img"))
188        self._CreateEmptyFile(os.path.join(self._image_dir, "system",
189                                           "build.prop"))
190
191        mock_environ = {"ANDROID_EMULATOR_PREBUILTS":
192                        os.path.join(self._tool_dir, "emulator")}
193
194        mock_avd_spec = self._CreateMockAvdSpec(local_instance_id=1,
195                                                boot_timeout_secs=100)
196
197        # Test deleting an existing instance.
198        self._emulator_is_running = True
199
200        with mock.patch.dict("acloud.create."
201                             "goldfish_local_image_local_instance.os.environ",
202                             mock_environ, clear=True):
203            report = self._goldfish._CreateAVD(mock_avd_spec, no_prompts=False)
204
205        self.assertEqual(report.data.get("devices"),
206                         self._GetExpectedDevicesInReport())
207
208        self._mock_lock.Lock.assert_called_once()
209        self._mock_lock.SetInUse.assert_called_once_with(True)
210        self._mock_lock.Unlock.assert_called_once()
211
212        mock_instance.assert_called_once_with(1, avd_flavor="phone")
213
214        self.assertTrue(os.path.isdir(self._instance_dir))
215
216        mock_utils.SetExecutable.assert_called_with(self._emulator_path)
217        mock_popen.assert_called_once()
218        self.assertEqual(mock_popen.call_args[0][0],
219                         self._GetExpectedEmulatorArgs())
220        self._mock_proc.poll.assert_called()
221
222    # pylint: disable=protected-access
223    @mock.patch("acloud.create.goldfish_local_image_local_instance.instance."
224                "LocalGoldfishInstance")
225    @mock.patch("acloud.create.goldfish_local_image_local_instance.utils")
226    @mock.patch("acloud.create.goldfish_local_image_local_instance."
227                "subprocess.Popen")
228    @mock.patch("acloud.create.goldfish_local_image_local_instance."
229                "goldfish_utils")
230    def testCreateAVDFromSdkRepository(self, mock_gf_utils, mock_popen,
231                                       mock_utils, mock_instance):
232        """Test _CreateAVD with SDK repository files."""
233        self._SetUpMocks(mock_popen, mock_utils, mock_instance, mock_gf_utils)
234
235        self._CreateEmptyFile(os.path.join(self._image_dir, "x86",
236                                           "system.img"))
237        self._CreateEmptyFile(os.path.join(self._image_dir, "x86",
238                                           "build.prop"))
239
240        instance_dir = os.path.join(self._temp_dir, "local_instance_dir")
241        os.mkdir(instance_dir)
242
243        mock_avd_spec = self._CreateMockAvdSpec(
244            local_instance_id=2,
245            local_instance_dir=instance_dir,
246            local_tool_dirs=[self._tool_dir])
247
248        with mock.patch.dict("acloud.create."
249                             "goldfish_local_image_local_instance.os.environ",
250                             dict(), clear=True):
251            report = self._goldfish._CreateAVD(mock_avd_spec, no_prompts=True)
252
253        self.assertEqual(report.data.get("devices"),
254                         self._GetExpectedDevicesInReport())
255
256        self._mock_lock.Lock.assert_called_once()
257        self._mock_lock.SetInUse.assert_called_once_with(True)
258        self._mock_lock.Unlock.assert_called_once()
259
260        mock_instance.assert_called_once_with(2, avd_flavor="phone")
261
262        self.assertTrue(os.path.isdir(self._instance_dir) and
263                        os.path.islink(self._instance_dir))
264
265        mock_utils.SetExecutable.assert_called_with(self._emulator_path)
266        mock_popen.assert_called_once()
267        self.assertEqual(mock_popen.call_args[0][0],
268                         self._GetExpectedEmulatorArgs())
269        self._mock_proc.poll.assert_called()
270
271        self.assertTrue(os.path.isfile(
272            os.path.join(self._image_dir, "x86", "system", "build.prop")))
273
274    # pylint: disable=protected-access
275    @mock.patch("acloud.create.goldfish_local_image_local_instance.instance."
276                "LocalGoldfishInstance")
277    @mock.patch("acloud.create.goldfish_local_image_local_instance.utils")
278    @mock.patch("acloud.create.goldfish_local_image_local_instance."
279                "subprocess.Popen")
280    @mock.patch("acloud.create.goldfish_local_image_local_instance."
281                "goldfish_utils")
282    def testCreateAVDTimeout(self, mock_gf_utils, mock_popen, mock_utils, mock_instance):
283        """Test _CreateAVD with SDK repository files and timeout error."""
284        self._SetUpMocks(mock_popen, mock_utils, mock_instance, mock_gf_utils)
285        mock_utils.PollAndWait.side_effect = errors.DeviceBootTimeoutError(
286            "timeout")
287
288        self._CreateEmptyFile(os.path.join(self._image_dir, "system.img"))
289        self._CreateEmptyFile(os.path.join(self._image_dir, "build.prop"))
290
291        mock_avd_spec = self._CreateMockAvdSpec(
292            local_instance_id=2,
293            local_tool_dirs=[self._tool_dir])
294
295        with mock.patch.dict("acloud.create."
296                             "goldfish_local_image_local_instance.os.environ",
297                             dict(), clear=True):
298            report = self._goldfish._CreateAVD(mock_avd_spec, no_prompts=True)
299
300        self._mock_lock.Lock.assert_called_once()
301        self._mock_lock.SetInUse.assert_called_once_with(True)
302        self._mock_lock.Unlock.assert_called_once()
303
304        self.assertEqual(report.data.get("devices_failing_boot"),
305                         self._GetExpectedDevicesInReport())
306        self.assertEqual(report.errors, ["timeout"])
307
308    # pylint: disable=protected-access
309    @mock.patch("acloud.create.goldfish_local_image_local_instance.instance."
310                "LocalGoldfishInstance")
311    @mock.patch("acloud.create.goldfish_local_image_local_instance.utils")
312    @mock.patch("acloud.create.goldfish_local_image_local_instance."
313                "subprocess.Popen")
314    @mock.patch("acloud.create.goldfish_local_image_local_instance."
315                "goldfish_utils")
316    def testCreateAVDWithoutReport(self, mock_gf_utils, mock_popen, mock_utils,
317                                   mock_instance):
318        """Test _CreateAVD with SDK repository files and no report."""
319        self._SetUpMocks(mock_popen, mock_utils, mock_instance, mock_gf_utils)
320
321        mock_avd_spec = self._CreateMockAvdSpec(
322            local_instance_id=0,
323            local_tool_dirs=[self._tool_dir])
324
325        with mock.patch.dict("acloud.create."
326                             "goldfish_local_image_local_instance.os.environ",
327                             dict(), clear=True):
328            with self.assertRaises(errors.GetLocalImageError):
329                self._goldfish._CreateAVD(mock_avd_spec, no_prompts=True)
330
331        self._mock_lock.Lock.assert_not_called()
332        self.assertEqual(2, self._mock_lock.LockIfNotInUse.call_count)
333        self._mock_lock.SetInUse.assert_not_called()
334        self._mock_lock.Unlock.assert_called_once()
335
336    # pylint: disable=protected-access
337    @mock.patch("acloud.create.goldfish_local_image_local_instance.instance."
338                "LocalGoldfishInstance")
339    @mock.patch("acloud.create.goldfish_local_image_local_instance.utils")
340    @mock.patch("acloud.create.goldfish_local_image_local_instance."
341                "subprocess.Popen")
342    @mock.patch("acloud.create.goldfish_local_image_local_instance.ota_tools")
343    @mock.patch("acloud.create.goldfish_local_image_local_instance."
344                "goldfish_utils")
345    def testCreateAVDWithMixedImages(self, mock_gf_utils, mock_ota_tools,
346                                     mock_popen, mock_utils, mock_instance):
347        """Test _CreateAVD with mixed images and SDK repository files."""
348        self._SetUpMocks(mock_popen, mock_utils, mock_instance, mock_gf_utils)
349
350        system_image_path = os.path.join(self._image_dir, "x86", "system.img")
351        self._CreateEmptyFile(system_image_path)
352        self._CreateEmptyFile(os.path.join(self._image_dir, "x86", "system",
353                                           "build.prop"))
354        params_path = os.path.join(self._image_dir, "x86",
355                                   "VerifiedBootParams.textproto")
356        self._CreateEmptyFile(params_path)
357
358        mock_avd_spec = self._CreateMockAvdSpec(
359            local_instance_id=3,
360            autoconnect=False,
361            local_system_image=system_image_path,
362            local_tool_dirs=[self._tool_dir])
363
364        with mock.patch.dict("acloud.create."
365                             "goldfish_local_image_local_instance.os.environ",
366                             dict(), clear=True):
367            report = self._goldfish._CreateAVD(mock_avd_spec, no_prompts=True)
368
369        self.assertEqual(report.data.get("devices"),
370                         self._GetExpectedDevicesInReport())
371
372        mock_instance.assert_called_once_with(3, avd_flavor="phone")
373
374        self.assertTrue(os.path.isdir(self._instance_dir))
375
376        mock_ota_tools.FindOtaTools.assert_called_once_with([self._tool_dir])
377
378        mock_gf_utils.MixDiskImage.assert_called_once_with(
379            mock.ANY, os.path.join(self._image_dir, "x86"), system_image_path,
380            None, mock_ota_tools.FindOtaTools.return_value)
381        self.assertTrue(os.path.isfile(params_path + ".bak-non-mixed"))
382        with open(params_path, "r", encoding="utf-8") as params_file:
383            self.assertEqual(
384                params_file.read(),
385                '\nparam: "androidboot.verifiedbootstate=orange"\n')
386
387        mock_utils.SetExecutable.assert_called_with(self._emulator_path)
388        mock_popen.assert_called_once()
389        self.assertEqual(mock_popen.call_args[0][0],
390                         self._GetExpectedEmulatorArgs("-no-window"))
391        self._mock_proc.poll.assert_called()
392
393    # pylint: disable=protected-access
394    @mock.patch("acloud.create.goldfish_local_image_local_instance.instance."
395                "LocalGoldfishInstance")
396    @mock.patch("acloud.create.goldfish_local_image_local_instance.utils")
397    @mock.patch("acloud.create.goldfish_local_image_local_instance."
398                "subprocess.Popen")
399    @mock.patch("acloud.create.goldfish_local_image_local_instance.ota_tools")
400    @mock.patch("acloud.create.goldfish_local_image_local_instance."
401                "goldfish_utils")
402    def testCreateAVDWithBootImage(self, mock_gf_utils, mock_ota_tools,
403                                   mock_popen, mock_utils, mock_instance):
404        """Test _CreateAVD with a boot image and SDK repository files."""
405        self._SetUpMocks(mock_popen, mock_utils, mock_instance, mock_gf_utils)
406
407        image_subdir = os.path.join(self._image_dir, "x86")
408        boot_image_path = os.path.join(self._temp_dir, "kernel_images",
409                                       "boot-5.10.img")
410        self.CreateFile(boot_image_path, b"ANDROID!")
411        self._CreateEmptyFile(os.path.join(image_subdir, "system.img"))
412        self._CreateEmptyFile(os.path.join(image_subdir, "build.prop"))
413
414        mock_avd_spec = self._CreateMockAvdSpec(
415            local_instance_id=3,
416            local_kernel_image=os.path.dirname(boot_image_path),
417            local_tool_dirs=[self._tool_dir])
418
419        with mock.patch.dict("acloud.create."
420                             "goldfish_local_image_local_instance.os.environ",
421                             dict(), clear=True):
422            report = self._goldfish._CreateAVD(mock_avd_spec, no_prompts=True)
423
424        self.assertEqual(report.data.get("devices"),
425                         self._GetExpectedDevicesInReport())
426
427        mock_gf_utils.MixWithBootImage.assert_called_once_with(
428            mock.ANY, os.path.join(image_subdir), boot_image_path,
429            mock_ota_tools.FindOtaTools.return_value)
430
431        mock_popen.assert_called_once()
432        self.assertEqual(
433            mock_popen.call_args[0][0],
434            self._GetExpectedEmulatorArgs(
435                "-kernel",
436                os.path.join(self._instance_dir, "mix_kernel", "kernel"),
437                "-ramdisk",
438                os.path.join(self._instance_dir, "mix_kernel", "ramdisk")))
439
440    # pylint: disable=protected-access
441    @mock.patch("acloud.create.goldfish_local_image_local_instance.instance."
442                "LocalGoldfishInstance")
443    @mock.patch("acloud.create.goldfish_local_image_local_instance.utils")
444    @mock.patch("acloud.create.goldfish_local_image_local_instance."
445                "subprocess.Popen")
446    @mock.patch("acloud.create.goldfish_local_image_local_instance.ota_tools")
447    @mock.patch("acloud.create.goldfish_local_image_local_instance."
448                "goldfish_utils")
449    def testCreateAVDWithKernelImages(self, mock_gf_utils, mock_ota_tools,
450                                      mock_popen, mock_utils, mock_instance):
451        """Test _CreateAVD with kernel images and SDK repository files."""
452        self._SetUpMocks(mock_popen, mock_utils, mock_instance, mock_gf_utils)
453
454        kernel_subdir = os.path.join(self._temp_dir, "kernel_images", "x86")
455        kernel_image_path = os.path.join(kernel_subdir, "kernel-ranchu")
456        ramdisk_image_path = os.path.join(kernel_subdir, "ramdisk.img")
457        mock_gf_utils.FindKernelImages.return_value = (kernel_image_path,
458                                                       ramdisk_image_path)
459
460        os.makedirs(kernel_subdir)
461        self._CreateEmptyFile(os.path.join(self._image_dir, "x86",
462                                           "system.img"))
463        self._CreateEmptyFile(os.path.join(self._image_dir, "x86",
464                                           "build.prop"))
465
466        mock_avd_spec = self._CreateMockAvdSpec(
467            local_instance_id=3,
468            local_kernel_image=os.path.dirname(kernel_subdir),
469            local_tool_dirs=[self._tool_dir])
470
471        with mock.patch.dict("acloud.create."
472                             "goldfish_local_image_local_instance.os.environ",
473                             dict(), clear=True):
474            report = self._goldfish._CreateAVD(mock_avd_spec, no_prompts=True)
475
476        self.assertEqual(report.data.get("devices"),
477                         self._GetExpectedDevicesInReport())
478
479        mock_ota_tools.FindOtaTools.assert_not_called()
480        mock_gf_utils.FindKernelImages.assert_called_once_with(kernel_subdir)
481
482        mock_popen.assert_called_once()
483        self.assertEqual(
484            mock_popen.call_args[0][0],
485            self._GetExpectedEmulatorArgs(
486                "-kernel", kernel_image_path,
487                "-ramdisk", ramdisk_image_path))
488
489    # pylint: disable=protected-access
490    @mock.patch("acloud.create.goldfish_local_image_local_instance.instance."
491                "LocalGoldfishInstance")
492    @mock.patch("acloud.create.goldfish_local_image_local_instance.utils")
493    @mock.patch("acloud.create.goldfish_local_image_local_instance."
494                "subprocess.Popen")
495    @mock.patch("acloud.create.goldfish_local_image_local_instance.ota_tools")
496    @mock.patch("acloud.create.goldfish_local_image_local_instance."
497                "goldfish_utils")
498    def testCreateAVDWithMixedImageDirs(self, mock_gf_utils, mock_ota_tools,
499                                        mock_popen, mock_utils, mock_instance):
500        """Test _CreateAVD with mixed images in build environment."""
501        self._SetUpMocks(mock_popen, mock_utils, mock_instance, mock_gf_utils)
502
503        system_image_path = os.path.join(self._image_dir, "system.img")
504        self._CreateEmptyFile(system_image_path)
505        disk_image_path = os.path.join(self._image_dir, "system-qemu.img")
506        self._CreateEmptyFile(disk_image_path)
507        self._CreateEmptyFile(os.path.join(self._image_dir, "system",
508                                           "build.prop"))
509        params_path = os.path.join(self._image_dir,
510                                   "VerifiedBootParams.textproto")
511        self._CreateEmptyFile(params_path)
512
513        mock_environ = {"ANDROID_EMULATOR_PREBUILTS":
514                        os.path.join(self._tool_dir, "emulator"),
515                        "ANDROID_HOST_OUT":
516                        os.path.join(self._tool_dir, "host"),
517                        "ANDROID_SOONG_HOST_OUT":
518                        os.path.join(self._tool_dir, "soong")}
519
520        mock_avd_spec = self._CreateMockAvdSpec(
521            local_instance_id=3,
522            autoconnect=False,
523            local_system_image=self._image_dir)
524
525        with mock.patch.dict("acloud.create."
526                             "goldfish_local_image_local_instance.os.environ",
527                             mock_environ, clear=True):
528            report = self._goldfish._CreateAVD(mock_avd_spec, no_prompts=True)
529
530        self.assertEqual(report.data.get("devices"),
531                         self._GetExpectedDevicesInReport())
532
533        mock_instance.assert_called_once_with(3, avd_flavor="phone")
534
535        self.assertTrue(os.path.isdir(self._instance_dir))
536
537        mock_ota_tools.FindOtaTools.assert_called_once_with([
538            os.path.join(self._tool_dir, "soong"),
539            os.path.join(self._tool_dir, "host")])
540
541        mock_gf_utils.MixDiskImage.assert_called_once_with(
542            mock.ANY, self._image_dir, system_image_path, None,
543            mock_ota_tools.FindOtaTools.return_value)
544        self.assertTrue(os.path.isfile(disk_image_path + ".bak-non-mixed"))
545        self.assertTrue(os.path.isfile(params_path + ".bak-non-mixed"))
546        with open(params_path, "r", encoding="utf-8") as params_file:
547            self.assertEqual(
548                params_file.read(),
549                '\nparam: "androidboot.verifiedbootstate=orange"\n')
550
551        mock_utils.SetExecutable.assert_called_with(self._emulator_path)
552        mock_popen.assert_called_once()
553        self.assertEqual(mock_popen.call_args[0][0],
554                         self._GetExpectedEmulatorArgs("-no-window"))
555        self._mock_proc.poll.assert_called()
556
557
558if __name__ == "__main__":
559    unittest.main()
560