1# Copyright 2018 - 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_image_local_instance.""" 15 16import unittest 17from collections import namedtuple 18import os 19import subprocess 20import mock 21 22from acloud import errors 23from acloud.create.remote_image_local_instance import RemoteImageLocalInstance 24from acloud.internal.lib import android_build_client 25from acloud.internal.lib import auth 26from acloud.internal.lib import driver_test_lib 27from acloud.internal.lib import utils 28from acloud.setup import setup_common 29 30 31# pylint: disable=invalid-name, protected-access 32class RemoteImageLocalInstanceTest(driver_test_lib.BaseDriverTest): 33 """Test remote_image_local_instance methods.""" 34 35 def setUp(self): 36 """Initialize remote_image_local_instance.""" 37 super(RemoteImageLocalInstanceTest, self).setUp() 38 self.build_client = mock.MagicMock() 39 self.Patch( 40 android_build_client, 41 "AndroidBuildClient", 42 return_value=self.build_client) 43 self.Patch(auth, "CreateCredentials", return_value=mock.MagicMock()) 44 self.RemoteImageLocalInstance = RemoteImageLocalInstance() 45 self._fake_remote_image = {"build_target" : "aosp_cf_x86_phone-userdebug", 46 "build_id": "1234"} 47 self._extract_path = "/tmp/acloud_image_artifacts/1234" 48 49 @mock.patch.object(RemoteImageLocalInstance, "_DownloadAndProcessImageFiles") 50 def testGetImageArtifactsPath(self, mock_proc): 51 """Test get image artifacts path.""" 52 avd_spec = mock.MagicMock() 53 # raise errors.NoCuttlefishCommonInstalled 54 self.Patch(setup_common, "PackageInstalled", return_value=False) 55 self.assertRaises(errors.NoCuttlefishCommonInstalled, 56 self.RemoteImageLocalInstance.GetImageArtifactsPath, 57 avd_spec) 58 59 # Valid _DownloadAndProcessImageFiles run. 60 self.Patch(setup_common, "PackageInstalled", return_value=True) 61 self.Patch(self.RemoteImageLocalInstance, 62 "_ConfirmDownloadRemoteImageDir", return_value="/tmp") 63 self.Patch(os.path, "exists", return_value=True) 64 self.RemoteImageLocalInstance.GetImageArtifactsPath(avd_spec) 65 mock_proc.assert_called_once_with(avd_spec) 66 67 @mock.patch.object(RemoteImageLocalInstance, "_AclCfImageFiles") 68 @mock.patch.object(RemoteImageLocalInstance, "_UnpackBootImage") 69 @mock.patch.object(RemoteImageLocalInstance, "_DownloadRemoteImage") 70 def testDownloadAndProcessImageFiles(self, mock_download, mock_unpack, mock_acl): 71 """Test process remote cuttlefish image.""" 72 avd_spec = mock.MagicMock() 73 avd_spec.cfg = mock.MagicMock() 74 avd_spec.remote_image = self._fake_remote_image 75 avd_spec.image_download_dir = "/tmp" 76 self.Patch(os.path, "exists", return_value=False) 77 self.Patch(os, "makedirs") 78 self.RemoteImageLocalInstance._DownloadAndProcessImageFiles(avd_spec) 79 80 # To make sure each function execute once. 81 mock_download.assert_called_once_with( 82 avd_spec.cfg, 83 avd_spec.remote_image["build_target"], 84 avd_spec.remote_image["build_id"], 85 self._extract_path) 86 mock_unpack.assert_called_once_with(self._extract_path) 87 mock_acl.assert_called_once_with(self._extract_path) 88 89 @mock.patch.object(utils, "Decompress") 90 def testDownloadRemoteImage(self, mock_decompress): 91 """Test Download cuttlefish package.""" 92 avd_spec = mock.MagicMock() 93 avd_spec.cfg = mock.MagicMock() 94 avd_spec.remote_image = self._fake_remote_image 95 build_id = "1234" 96 build_target = "aosp_cf_x86_phone-userdebug" 97 checkfile1 = "aosp_cf_x86_phone-img-1234.zip" 98 checkfile2 = "cvd-host_package.tar.gz" 99 100 self.RemoteImageLocalInstance._DownloadRemoteImage( 101 avd_spec.cfg, 102 avd_spec.remote_image["build_target"], 103 avd_spec.remote_image["build_id"], 104 self._extract_path) 105 106 # To validate DownloadArtifact runs twice. 107 self.assertEqual(self.build_client.DownloadArtifact.call_count, 2) 108 # To validate DownloadArtifact arguments correct. 109 self.build_client.DownloadArtifact.assert_has_calls([ 110 mock.call(build_target, build_id, checkfile1, 111 "%s/%s" % (self._extract_path, checkfile1)), 112 mock.call(build_target, build_id, checkfile2, 113 "%s/%s" % (self._extract_path, checkfile2))], 114 any_order=True) 115 # To validate Decompress runs twice. 116 self.assertEqual(mock_decompress.call_count, 2) 117 118 @mock.patch.object(subprocess, "check_call") 119 def testUnpackBootImage(self, mock_call): 120 """Test Unpack boot image.""" 121 self.Patch(os.path, "exists", side_effect=[True, False]) 122 self.RemoteImageLocalInstance._UnpackBootImage(self._extract_path) 123 # check_call run once when boot.img exist. 124 self.assertEqual(mock_call.call_count, 1) 125 # raise errors.BootImgDoesNotExist when boot.img doesn't exist. 126 self.assertRaises(errors.BootImgDoesNotExist, 127 self.RemoteImageLocalInstance._UnpackBootImage, 128 self._extract_path) 129 130 def testConfirmDownloadRemoteImageDir(self): 131 """Test confirm download remote image dir""" 132 self.Patch(os.path, "exists", return_value=True) 133 self.Patch(os, "makedirs") 134 # Default minimum avail space should be more than 10G 135 # then return download_dir directly. 136 self.Patch(os, "statvfs", return_value=namedtuple( 137 "statvfs", "f_bavail, f_bsize")(11, 1073741824)) 138 download_dir = "/tmp" 139 self.assertEqual( 140 self.RemoteImageLocalInstance._ConfirmDownloadRemoteImageDir( 141 download_dir), "/tmp") 142 143 # Test when insuficient disk space and input 'q' to exit. 144 self.Patch(os, "statvfs", return_value=namedtuple( 145 "statvfs", "f_bavail, f_bsize")(9, 1073741824)) 146 self.Patch(utils, "InteractWithQuestion", return_value="q") 147 self.assertRaises(SystemExit, 148 self.RemoteImageLocalInstance._ConfirmDownloadRemoteImageDir, 149 download_dir) 150 151 # If avail space detect as 9GB, and 2nd input 7GB both less than 10GB 152 # 3rd input over 10GB, so return path should be "/tmp3". 153 self.Patch(os, "statvfs", side_effect=[ 154 namedtuple("statvfs", "f_bavail, f_bsize")(9, 1073741824), 155 namedtuple("statvfs", "f_bavail, f_bsize")(7, 1073741824), 156 namedtuple("statvfs", "f_bavail, f_bsize")(11, 1073741824)]) 157 self.Patch(utils, "InteractWithQuestion", side_effect=["/tmp2", 158 "/tmp3"]) 159 self.assertEqual( 160 self.RemoteImageLocalInstance._ConfirmDownloadRemoteImageDir( 161 download_dir), "/tmp3") 162 163 # Test when path not exist, define --image-download-dir 164 # enter anything else to exit out. 165 download_dir = "/image_download_dir1" 166 self.Patch(os.path, "exists", return_value=False) 167 self.Patch(utils, "InteractWithQuestion", return_value="") 168 self.assertRaises(SystemExit, 169 self.RemoteImageLocalInstance._ConfirmDownloadRemoteImageDir, 170 download_dir) 171 172 # Test using --image-dowload-dir and makedirs. 173 # enter 'y' to create it. 174 self.Patch(utils, "InteractWithQuestion", return_value="y") 175 self.Patch(os, "statvfs", return_value=namedtuple( 176 "statvfs", "f_bavail, f_bsize")(10, 1073741824)) 177 self.assertEqual( 178 self.RemoteImageLocalInstance._ConfirmDownloadRemoteImageDir( 179 download_dir), "/image_download_dir1") 180 181 # Test when 1st check fails for insufficient disk space, user inputs an 182 # alternate dir but it doesn't exist and the user choose to exit. 183 self.Patch(os, "statvfs", side_effect=[ 184 namedtuple("statvfs", "f_bavail, f_bsize")(9, 1073741824), 185 namedtuple("statvfs", "f_bavail, f_bsize")(11, 1073741824)]) 186 self.Patch(os.path, "exists", side_effect=[True, False]) 187 self.Patch(utils, "InteractWithQuestion", 188 side_effect=["~/nopath", "not_y"]) 189 self.assertRaises( 190 SystemExit, 191 self.RemoteImageLocalInstance._ConfirmDownloadRemoteImageDir, 192 download_dir) 193 194 # Test when 1st check fails for insufficient disk space, user inputs an 195 # alternate dir but it doesn't exist and they request to create it. 196 self.Patch(os, "statvfs", side_effect=[ 197 namedtuple("statvfs", "f_bavail, f_bsize")(9, 1073741824), 198 namedtuple("statvfs", "f_bavail, f_bsize")(10, 1073741824)]) 199 self.Patch(os.path, "exists", side_effect=[True, False]) 200 self.Patch(utils, "InteractWithQuestion", side_effect=["~/nopath", "y"]) 201 self.assertEqual( 202 self.RemoteImageLocalInstance._ConfirmDownloadRemoteImageDir( 203 download_dir), os.path.expanduser("~/nopath")) 204 205 206if __name__ == "__main__": 207 unittest.main() 208