blob: a45093387f7868289d385fb55b5d8cfb7976d203 [file] [log] [blame]
Fang Deng69498c32017-03-02 14:29:30 -08001#!/usr/bin/env python
2#
3# Copyright 2016 - The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17"""Tests for acloud.internal.lib.utils."""
18
Fang Deng26e4dc12018-03-04 19:01:59 -080019import errno
Fang Deng69498c32017-03-02 14:29:30 -080020import getpass
21import os
Fang Deng26e4dc12018-03-04 19:01:59 -080022import shutil
Fang Deng69498c32017-03-02 14:29:30 -080023import subprocess
Fang Deng26e4dc12018-03-04 19:01:59 -080024import tempfile
Fang Dengf24be082018-02-10 10:09:55 -080025import time
Fang Deng69498c32017-03-02 14:29:30 -080026
27import mock
28
29import unittest
30from acloud.internal.lib import driver_test_lib
31from acloud.internal.lib import utils
32
33
34class UtilsTest(driver_test_lib.BaseDriverTest):
35
Fang Deng26e4dc12018-03-04 19:01:59 -080036 def testTempDir_Success(self):
37 """Test create a temp dir."""
38 self.Patch(os, "chmod")
39 self.Patch(tempfile, "mkdtemp", return_value="/tmp/tempdir")
40 self.Patch(shutil, "rmtree")
41 with utils.TempDir():
42 pass
43 # Verify.
44 tempfile.mkdtemp.assert_called_once()
45 shutil.rmtree.assert_called_with("/tmp/tempdir")
46
47 def testTempDir_ExceptionRaised(self):
48 """Test create a temp dir and exception is raised within with-clause."""
49 self.Patch(os, "chmod")
50 self.Patch(tempfile, "mkdtemp", return_value="/tmp/tempdir")
51 self.Patch(shutil, "rmtree")
52
53 class ExpectedException(Exception):
54 pass
55
56 def _Call():
57 with utils.TempDir():
58 raise ExpectedException("Expected exception.")
59 # Verify. ExpectedException should be raised.
60 self.assertRaises(ExpectedException, _Call)
61 tempfile.mkdtemp.assert_called_once()
62 shutil.rmtree.assert_called_with("/tmp/tempdir")
63
64 def testTempDir_WhenDeleteTempDirNoLongerExist(self):
65 """Test create a temp dir and dir no longer exists during deletion."""
66 self.Patch(os, "chmod")
67 self.Patch(tempfile, "mkdtemp", return_value="/tmp/tempdir")
68 expected_error = EnvironmentError()
69 expected_error.errno = errno.ENOENT
70 self.Patch(shutil, "rmtree", side_effect=expected_error)
71 def _Call():
72 with utils.TempDir():
73 pass
74 # Verify no exception should be raised when rmtree raises
75 # EnvironmentError with errno.ENOENT, i.e.
76 # directory no longer exists.
77 _Call()
78 tempfile.mkdtemp.assert_called_once()
79 shutil.rmtree.assert_called_with("/tmp/tempdir")
80
81 def testTempDir_WhenDeleteEncounterError(self):
82 """Test create a temp dir and encoutered error during deletion."""
83 self.Patch(os, "chmod")
84 self.Patch(tempfile, "mkdtemp", return_value="/tmp/tempdir")
85 expected_error = OSError("Expected OS Error")
86 self.Patch(shutil, "rmtree", side_effect=expected_error)
87 def _Call():
88 with utils.TempDir():
89 pass
90
91 # Verify OSError should be raised.
92 self.assertRaises(OSError, _Call)
93 tempfile.mkdtemp.assert_called_once()
94 shutil.rmtree.assert_called_with("/tmp/tempdir")
95
96 def testTempDir_OrininalErrorRaised(self):
97 """Test original error is raised even if tmp dir deletion failed."""
98 self.Patch(os, "chmod")
99 self.Patch(tempfile, "mkdtemp", return_value="/tmp/tempdir")
100 expected_error = OSError("Expected OS Error")
101 self.Patch(shutil, "rmtree", side_effect=expected_error)
102
103 class ExpectedException(Exception):
104 pass
105
106 def _Call():
107 with utils.TempDir():
108 raise ExpectedException("Expected Exception")
109
110 # Verify.
111 # ExpectedException should be raised, and OSError
112 # should not be raised.
113 self.assertRaises(ExpectedException, _Call)
114 tempfile.mkdtemp.assert_called_once()
115 shutil.rmtree.assert_called_with("/tmp/tempdir")
116
Fang Deng69498c32017-03-02 14:29:30 -0800117 def testCreateSshKeyPair_KeyAlreadyExists(self):
118 """Test when the key pair already exists."""
119 public_key = "/fake/public_key"
120 private_key = "/fake/private_key"
121 self.Patch(os.path, "exists", side_effect=lambda path: path == public_key)
122 self.Patch(subprocess, "check_call")
123 utils.CreateSshKeyPairIfNotExist(private_key, public_key)
124 self.assertEqual(subprocess.check_call.call_count, 0)
125
126 def testCreateSshKeyPair_KeyAreCreated(self):
127 """Test when the key pair created."""
128 public_key = "/fake/public_key"
129 private_key = "/fake/private_key"
130 self.Patch(os.path, "exists", return_value=False)
131 self.Patch(subprocess, "check_call")
132 self.Patch(os, "rename")
133 utils.CreateSshKeyPairIfNotExist(private_key, public_key)
134 self.assertEqual(subprocess.check_call.call_count, 1)
135 subprocess.check_call.assert_called_with(
136 utils.SSH_KEYGEN_CMD + ["-C", getpass.getuser(), "-f", private_key],
137 stdout=mock.ANY, stderr=mock.ANY)
138
Fang Dengf24be082018-02-10 10:09:55 -0800139 def testRetryOnException(self):
140 def _IsValueError(exc):
141 return isinstance(exc, ValueError)
142 num_retry = 5
143
144 @utils.RetryOnException(_IsValueError, num_retry)
145 def _RaiseAndRetry(sentinel):
146 sentinel.alert()
147 raise ValueError("Fake error.")
148
149 sentinel = mock.MagicMock()
150 self.assertRaises(ValueError, _RaiseAndRetry, sentinel)
151 self.assertEqual(1 + num_retry, sentinel.alert.call_count)
152
153 def testRetryExceptionType(self):
154 """Test RetryExceptionType function."""
155 def _RaiseAndRetry(sentinel):
156 sentinel.alert()
157 raise ValueError("Fake error.")
158
159 num_retry = 5
160 sentinel = mock.MagicMock()
161 self.assertRaises(ValueError, utils.RetryExceptionType,
162 (KeyError, ValueError), num_retry, _RaiseAndRetry,
163 sentinel=sentinel)
164 self.assertEqual(1 + num_retry, sentinel.alert.call_count)
165
166 def testRetry(self):
167 """Test Retry."""
168 self.Patch(time, "sleep")
169 def _RaiseAndRetry(sentinel):
170 sentinel.alert()
171 raise ValueError("Fake error.")
172
173 num_retry = 5
174 sentinel = mock.MagicMock()
175 self.assertRaises(ValueError, utils.RetryExceptionType,
176 (ValueError, KeyError), num_retry, _RaiseAndRetry,
177 sleep_multiplier=1,
178 retry_backoff_factor=2,
179 sentinel=sentinel)
180
181 self.assertEqual(1 + num_retry, sentinel.alert.call_count)
182 time.sleep.assert_has_calls(
183 [mock.call(1), mock.call(2), mock.call(4), mock.call(8), mock.call(16)])
184
Fang Deng69498c32017-03-02 14:29:30 -0800185
186if __name__ == "__main__":
187 unittest.main()