1
# Copyright (c) 2014 VMware, Inc.
4
# Licensed under the Apache License, Version 2.0 (the "License"); you may
5
# not use this file except in compliance with the License. You may obtain
6
# a copy of the License at
8
# http://www.apache.org/licenses/LICENSE-2.0
10
# Unless required by applicable law or agreed to in writing, software
11
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
# License for the specific language governing permissions and limitations
17
Unit tests for session management and API invocation classes.
22
from oslo.vmware import api
23
from oslo.vmware import exceptions
24
from oslo.vmware import vim_util
25
from tests import base
28
class RetryDecoratorTest(base.TestCase):
29
"""Tests for retry decorator class."""
35
def func(*args, **kwargs):
38
self.assertEqual(result, func())
40
def func2(*args, **kwargs):
43
retry = api.RetryDecorator()
44
self.assertEqual(result, retry(func2)())
45
self.assertTrue(retry._retry_count == 0)
47
def test_retry_with_expected_exceptions(self):
49
responses = [exceptions.VimSessionOverLoadException(None),
50
exceptions.VimSessionOverLoadException(None),
53
def func(*args, **kwargs):
54
response = responses.pop(0)
55
if isinstance(response, Exception):
61
retry = api.RetryDecorator(10, sleep_time_incr, 10,
62
(exceptions.VimSessionOverLoadException,))
63
self.assertEqual(result, retry(func)())
64
self.assertTrue(retry._retry_count == retry_count)
65
self.assertEqual(retry_count * sleep_time_incr, retry._sleep_time)
67
def test_retry_with_max_retries(self):
68
responses = [exceptions.VimSessionOverLoadException(None),
69
exceptions.VimSessionOverLoadException(None),
70
exceptions.VimSessionOverLoadException(None)]
72
def func(*args, **kwargs):
73
response = responses.pop(0)
74
if isinstance(response, Exception):
78
retry = api.RetryDecorator(2, 0, 0,
79
(exceptions.VimSessionOverLoadException,))
80
self.assertRaises(exceptions.VimSessionOverLoadException, retry(func))
81
self.assertTrue(retry._retry_count == 2)
83
def test_retry_with_unexpected_exception(self):
85
def func(*args, **kwargs):
86
raise exceptions.VimException(None)
88
retry = api.RetryDecorator()
89
self.assertRaises(exceptions.VimException, retry(func))
90
self.assertTrue(retry._retry_count == 0)
93
class VMwareAPISessionTest(base.TestCase):
94
"""Tests for VMwareAPISession."""
96
SERVER_IP = '10.1.2.3'
101
super(VMwareAPISessionTest, self).setUp()
102
patcher = mock.patch('oslo.vmware.vim.Vim')
103
self.addCleanup(patcher.stop)
104
self.VimMock = patcher.start()
105
self.VimMock.side_effect = lambda *args, **kw: mock.Mock()
107
def _create_api_session(self, _create_session, retry_count=10,
108
task_poll_interval=1):
109
return api.VMwareAPISession(VMwareAPISessionTest.SERVER_IP,
110
VMwareAPISessionTest.USERNAME,
111
VMwareAPISessionTest.PASSWORD,
118
api_session = self._create_api_session(False)
120
self.VimMock.assert_called_with(protocol=api_session._scheme,
121
host=VMwareAPISessionTest.SERVER_IP,
122
wsdl_loc=api_session._wsdl_loc)
124
def test_create_session(self):
125
session = mock.Mock()
126
session.key = "12345"
127
api_session = self._create_api_session(False)
128
vim_obj = api_session.vim
129
vim_obj.Login.return_value = session
131
api_session._create_session()
132
session_manager = vim_obj.service_content.sessionManager
133
vim_obj.Login.assert_called_once_with(
134
session_manager, userName=VMwareAPISessionTest.USERNAME,
135
password=VMwareAPISessionTest.PASSWORD)
136
self.assertFalse(vim_obj.TerminateSession.called)
137
self.assertEqual(session.key, api_session._session_id)
139
def test_create_session_with_existing_session(self):
140
old_session_key = '12345'
141
new_session_key = '67890'
142
session = mock.Mock()
143
session.key = new_session_key
144
api_session = self._create_api_session(False)
145
api_session._session_id = old_session_key
146
vim_obj = api_session.vim
147
vim_obj.Login.return_value = session
149
api_session._create_session()
150
session_manager = vim_obj.service_content.sessionManager
151
vim_obj.Login.assert_called_once_with(
152
session_manager, userName=VMwareAPISessionTest.USERNAME,
153
password=VMwareAPISessionTest.PASSWORD)
154
vim_obj.TerminateSession.assert_called_once_with(
155
session_manager, sessionId=[old_session_key])
156
self.assertEqual(new_session_key, api_session._session_id)
158
def test_invoke_api(self):
159
api_session = self._create_api_session(True)
160
response = mock.Mock()
162
def api(*args, **kwargs):
167
ret = api_session.invoke_api(module, 'api')
168
self.assertEqual(response, ret)
170
def test_invoke_api_with_expected_exception(self):
171
api_session = self._create_api_session(True)
173
responses = [exceptions.VimConnectionException(None), ret]
175
def api(*args, **kwargs):
176
response = responses.pop(0)
177
if isinstance(response, Exception):
183
self.assertEqual(ret, api_session.invoke_api(module, 'api'))
185
def test_invoke_api_with_vim_fault_exception(self):
186
api_session = self._create_api_session(True)
188
def api(*args, **kwargs):
189
raise exceptions.VimFaultException([], None)
193
self.assertRaises(exceptions.VimFaultException,
194
lambda: api_session.invoke_api(module, 'api'))
196
def test_invoke_api_with_empty_response(self):
197
api_session = self._create_api_session(True)
198
vim_obj = api_session.vim
199
vim_obj.SessionIsActive.return_value = True
201
def api(*args, **kwargs):
202
raise exceptions.VimFaultException(
203
[exceptions.NOT_AUTHENTICATED], None)
207
ret = api_session.invoke_api(module, 'api')
208
self.assertEqual([], ret)
209
vim_obj.SessionIsActive.assert_called_once_with(
210
vim_obj.service_content.sessionManager,
211
sessionID=api_session._session_id,
212
userName=api_session._session_username)
214
def test_wait_for_task(self):
215
api_session = self._create_api_session(True)
216
task_info_list = [('queued', 0), ('running', 40), ('success', 100)]
217
task_info_list_size = len(task_info_list)
219
def invoke_api_side_effect(module, method, *args, **kwargs):
220
(state, progress) = task_info_list.pop(0)
221
task_info = mock.Mock()
222
task_info.progress = progress
223
task_info.state = state
226
api_session.invoke_api = mock.Mock(side_effect=invoke_api_side_effect)
228
ret = api_session.wait_for_task(task)
229
self.assertEqual('success', ret.state)
230
self.assertEqual(100, ret.progress)
231
api_session.invoke_api.assert_called_with(vim_util,
232
'get_object_property',
233
api_session.vim, task,
235
self.assertEqual(task_info_list_size,
236
api_session.invoke_api.call_count)
238
def test_wait_for_task_with_error_state(self):
239
api_session = self._create_api_session(True)
240
task_info_list = [('queued', 0), ('running', 40), ('error', -1)]
241
task_info_list_size = len(task_info_list)
243
def invoke_api_side_effect(module, method, *args, **kwargs):
244
(state, progress) = task_info_list.pop(0)
245
task_info = mock.Mock()
246
task_info.progress = progress
247
task_info.state = state
250
api_session.invoke_api = mock.Mock(side_effect=invoke_api_side_effect)
252
self.assertRaises(exceptions.VMwareDriverException,
253
lambda: api_session.wait_for_task(task))
254
api_session.invoke_api.assert_called_with(vim_util,
255
'get_object_property',
256
api_session.vim, task,
258
self.assertEqual(task_info_list_size,
259
api_session.invoke_api.call_count)
261
def test_wait_for_task_with_invoke_api_exception(self):
262
api_session = self._create_api_session(True)
263
api_session.invoke_api = mock.Mock(
264
side_effect=exceptions.VimException(None))
266
self.assertRaises(exceptions.VimException,
267
lambda: api_session.wait_for_task(task))
268
api_session.invoke_api.assert_called_once_with(vim_util,
269
'get_object_property',
270
api_session.vim, task,
273
def test_wait_for_lease_ready(self):
274
api_session = self._create_api_session(True)
275
lease_states = ['initializing', 'ready']
276
num_states = len(lease_states)
278
def invoke_api_side_effect(module, method, *args, **kwargs):
279
return lease_states.pop(0)
281
api_session.invoke_api = mock.Mock(side_effect=invoke_api_side_effect)
283
api_session.wait_for_lease_ready(lease)
284
api_session.invoke_api.assert_called_with(vim_util,
285
'get_object_property',
286
api_session.vim, lease,
288
self.assertEqual(num_states, api_session.invoke_api.call_count)
290
def test_wait_for_lease_ready_with_error_state(self):
291
api_session = self._create_api_session(True)
292
responses = ['initializing', 'error', 'error_msg']
294
def invoke_api_side_effect(module, method, *args, **kwargs):
295
return responses.pop(0)
297
api_session.invoke_api = mock.Mock(side_effect=invoke_api_side_effect)
299
self.assertRaises(exceptions.VimException,
300
lambda: api_session.wait_for_lease_ready(lease))
301
exp_calls = [mock.call(vim_util, 'get_object_property',
302
api_session.vim, lease, 'state')] * 2
303
exp_calls.append(mock.call(vim_util, 'get_object_property',
304
api_session.vim, lease, 'error'))
305
self.assertEqual(exp_calls, api_session.invoke_api.call_args_list)
307
def test_wait_for_lease_ready_with_unknown_state(self):
308
api_session = self._create_api_session(True)
310
def invoke_api_side_effect(module, method, *args, **kwargs):
313
api_session.invoke_api = mock.Mock(side_effect=invoke_api_side_effect)
315
self.assertRaises(exceptions.VimException,
316
lambda: api_session.wait_for_lease_ready(lease))
317
api_session.invoke_api.assert_called_once_with(vim_util,
318
'get_object_property',
322
def test_wait_for_lease_ready_with_invoke_api_exception(self):
323
api_session = self._create_api_session(True)
324
api_session.invoke_api = mock.Mock(
325
side_effect=exceptions.VimException(None))
327
self.assertRaises(exceptions.VimException,
328
lambda: api_session.wait_for_lease_ready(lease))
329
api_session.invoke_api.assert_called_once_with(
330
vim_util, 'get_object_property', api_session.vim, lease,
333
def _poll_task_well_known_exceptions(self, fault,
335
api_session = self._create_api_session(False)
337
def fake_invoke_api(self, module, method, *args, **kwargs):
338
task_info = mock.Mock()
339
task_info.progress = -1
340
task_info.state = 'error'
342
error.localizedMessage = "Error message"
343
error_fault = mock.Mock()
344
error_fault.__class__.__name__ = fault
345
error.fault = error_fault
346
task_info.error = error
350
mock.patch.object(api_session, 'invoke_api', fake_invoke_api)
352
self.assertRaises(expected_exception,
353
api_session._poll_task, 'fake-task')
355
def test_poll_task_well_known_exceptions(self):
356
for k, v in exceptions._fault_classes_registry.iteritems():
357
self._poll_task_well_known_exceptions(k, v)
359
def test_poll_task_unknown_exception(self):
360
_unknown_exceptions = {
361
'NoDiskSpace': exceptions.VMwareDriverException,
362
'RuntimeFault': exceptions.VMwareDriverException
365
for k, v in _unknown_exceptions.iteritems():
366
self._poll_task_well_known_exceptions(k, v)