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 mock
20
21from acloud import errors
22from acloud.create import create_common
23from acloud.create import remote_image_local_instance
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 = remote_image_local_instance.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(remote_image_local_instance, "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(remote_image_local_instance,
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(create_common, "DownloadRemoteArtifact")
68    def testDownloadAndProcessImageFiles(self, mock_download):
69        """Test process remote cuttlefish image."""
70        avd_spec = mock.MagicMock()
71        avd_spec.cfg = mock.MagicMock()
72        avd_spec.remote_image = self._fake_remote_image
73        avd_spec.image_download_dir = "/tmp"
74        self.Patch(os.path, "exists", return_value=False)
75        self.Patch(os, "makedirs")
76        remote_image_local_instance.DownloadAndProcessImageFiles(avd_spec)
77        build_id = "1234"
78        build_target = "aosp_cf_x86_phone-userdebug"
79        checkfile1 = "aosp_cf_x86_phone-img-1234.zip"
80        checkfile2 = "cvd-host_package.tar.gz"
81
82        # To validate DownloadArtifact runs twice.
83        self.assertEqual(mock_download.call_count, 2)
84
85        # To validate DownloadArtifact arguments correct.
86        mock_download.assert_has_calls([
87            mock.call(avd_spec.cfg, build_target, build_id, checkfile1,
88                      self._extract_path, decompress=True),
89            mock.call(avd_spec.cfg, build_target, build_id, checkfile2,
90                      self._extract_path, decompress=True)], any_order=True)
91
92    def testConfirmDownloadRemoteImageDir(self):
93        """Test confirm download remote image dir"""
94        self.Patch(os.path, "exists", return_value=True)
95        self.Patch(os, "makedirs")
96        # Default minimum avail space should be more than 10G
97        # then return download_dir directly.
98        self.Patch(os, "statvfs", return_value=namedtuple(
99            "statvfs", "f_bavail, f_bsize")(11, 1073741824))
100        download_dir = "/tmp"
101        self.assertEqual(
102            remote_image_local_instance.ConfirmDownloadRemoteImageDir(
103                download_dir), "/tmp")
104
105        # Test when insuficient disk space and input 'q' to exit.
106        self.Patch(os, "statvfs", return_value=namedtuple(
107            "statvfs", "f_bavail, f_bsize")(9, 1073741824))
108        self.Patch(utils, "InteractWithQuestion", return_value="q")
109        self.assertRaises(SystemExit,
110                          remote_image_local_instance.ConfirmDownloadRemoteImageDir,
111                          download_dir)
112
113        # If avail space detect as 9GB, and 2nd input 7GB both less than 10GB
114        # 3rd input over 10GB, so return path should be "/tmp3".
115        self.Patch(os, "statvfs", side_effect=[
116            namedtuple("statvfs", "f_bavail, f_bsize")(9, 1073741824),
117            namedtuple("statvfs", "f_bavail, f_bsize")(7, 1073741824),
118            namedtuple("statvfs", "f_bavail, f_bsize")(11, 1073741824)])
119        self.Patch(utils, "InteractWithQuestion", side_effect=["/tmp2",
120                                                               "/tmp3"])
121        self.assertEqual(
122            remote_image_local_instance.ConfirmDownloadRemoteImageDir(
123                download_dir), "/tmp3")
124
125        # Test when path not exist, define --image-download-dir
126        # enter anything else to exit out.
127        download_dir = "/image_download_dir1"
128        self.Patch(os.path, "exists", return_value=False)
129        self.Patch(utils, "InteractWithQuestion", return_value="")
130        self.assertRaises(SystemExit,
131                          remote_image_local_instance.ConfirmDownloadRemoteImageDir,
132                          download_dir)
133
134        # Test using --image-dowload-dir and makedirs.
135        # enter 'y' to create it.
136        self.Patch(utils, "InteractWithQuestion", return_value="y")
137        self.Patch(os, "statvfs", return_value=namedtuple(
138            "statvfs", "f_bavail, f_bsize")(10, 1073741824))
139        self.assertEqual(
140            remote_image_local_instance.ConfirmDownloadRemoteImageDir(
141                download_dir), "/image_download_dir1")
142
143        # Test when 1st check fails for insufficient disk space, user inputs an
144        # alternate dir but it doesn't exist and the user choose to exit.
145        self.Patch(os, "statvfs", side_effect=[
146            namedtuple("statvfs", "f_bavail, f_bsize")(9, 1073741824),
147            namedtuple("statvfs", "f_bavail, f_bsize")(11, 1073741824)])
148        self.Patch(os.path, "exists", side_effect=[True, False])
149        self.Patch(utils, "InteractWithQuestion",
150                   side_effect=["~/nopath", "not_y"])
151        self.assertRaises(
152            SystemExit,
153            remote_image_local_instance.ConfirmDownloadRemoteImageDir,
154            download_dir)
155
156        # Test when 1st check fails for insufficient disk space, user inputs an
157        # alternate dir but it doesn't exist and they request to create it.
158        self.Patch(os, "statvfs", side_effect=[
159            namedtuple("statvfs", "f_bavail, f_bsize")(9, 1073741824),
160            namedtuple("statvfs", "f_bavail, f_bsize")(10, 1073741824)])
161        self.Patch(os.path, "exists", side_effect=[True, False])
162        self.Patch(utils, "InteractWithQuestion", side_effect=["~/nopath", "y"])
163        self.assertEqual(
164            remote_image_local_instance.ConfirmDownloadRemoteImageDir(
165                download_dir), os.path.expanduser("~/nopath"))
166
167
168if __name__ == "__main__":
169    unittest.main()
170