blob: f45eec000c62e87719623c19f51e704b110b499f [file] [log] [blame]
Matthew Treinish7b015822014-01-21 18:15:39 +00001# Copyright 2014 IBM Corp.
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# 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, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
14
15import time
Sean McGinniseed80742020-04-18 12:01:03 -050016from unittest import mock
Matthew Treinish7b015822014-01-21 18:15:39 +000017
Lee Yarwoodc1b2a4a2020-01-08 17:02:49 +000018from oslo_utils.fixture import uuidsentinel as uuids
Matthew Treinish7b015822014-01-21 18:15:39 +000019
20from tempest.common import waiters
21from tempest import exceptions
guo yunxianebb15f22016-11-01 21:03:35 +080022from tempest.lib import exceptions as lib_exc
lkuchlanf53947e2016-09-15 10:37:57 +030023from tempest.lib.services.volume.v2 import volumes_client
Matthew Treinishffad78a2016-04-16 14:39:52 -040024from tempest.tests import base
Jordan Pittier0e53b612016-03-03 14:23:17 +010025import tempest.tests.utils as utils
Matthew Treinish7b015822014-01-21 18:15:39 +000026
27
28class TestImageWaiters(base.TestCase):
29 def setUp(self):
30 super(TestImageWaiters, self).setUp()
31 self.client = mock.MagicMock()
32 self.client.build_timeout = 1
33 self.client.build_interval = 1
34
35 def test_wait_for_image_status(self):
Ken'ichi Ohmichi5d410762015-05-22 01:10:03 +000036 self.client.show_image.return_value = ({'status': 'active'})
Matthew Treinish7b015822014-01-21 18:15:39 +000037 start_time = int(time.time())
38 waiters.wait_for_image_status(self.client, 'fake_image_id', 'active')
39 end_time = int(time.time())
40 # Ensure waiter returns before build_timeout
Béla Vancsics64862f72016-11-08 09:12:31 +010041 self.assertLess((end_time - start_time), 10)
Matthew Treinish7b015822014-01-21 18:15:39 +000042
Yaroslav Lobankov2fea4052016-04-19 15:05:57 +030043 def test_wait_for_image_status_timeout(self):
Jordan Pittier0e53b612016-03-03 14:23:17 +010044 time_mock = self.patch('time.time')
45 time_mock.side_effect = utils.generate_timeout_series(1)
46
Ken'ichi Ohmichi5d410762015-05-22 01:10:03 +000047 self.client.show_image.return_value = ({'status': 'saving'})
guo yunxianebb15f22016-11-01 21:03:35 +080048 self.assertRaises(lib_exc.TimeoutException,
Matthew Treinish7b015822014-01-21 18:15:39 +000049 waiters.wait_for_image_status,
50 self.client, 'fake_image_id', 'active')
51
Yaroslav Lobankov2fea4052016-04-19 15:05:57 +030052 def test_wait_for_image_status_error_on_image_create(self):
Ken'ichi Ohmichi5d410762015-05-22 01:10:03 +000053 self.client.show_image.return_value = ({'status': 'ERROR'})
Matthew Treinish7b015822014-01-21 18:15:39 +000054 self.assertRaises(exceptions.AddImageException,
55 waiters.wait_for_image_status,
56 self.client, 'fake_image_id', 'active')
Matt Riedemannf77e7dc2015-08-10 16:39:39 -070057
zhufl414ffba2020-11-19 16:57:06 +080058 def test_wait_for_image_imported_to_stores(self):
59 self.client.show_image.return_value = ({'status': 'active',
60 'stores': 'fake_store'})
61 start_time = int(time.time())
62 waiters.wait_for_image_imported_to_stores(
63 self.client, 'fake_image_id', 'fake_store')
64 end_time = int(time.time())
65 # Ensure waiter returns before build_timeout
66 self.assertLess((end_time - start_time), 10)
67
68 def test_wait_for_image_imported_to_stores_timeout(self):
69 time_mock = self.patch('time.time')
70 client = mock.MagicMock()
71 client.build_timeout = 2
72 self.patch('time.time', side_effect=[0., 1., 2.])
73 time_mock.side_effect = utils.generate_timeout_series(1)
74
75 client.show_image.return_value = ({
76 'status': 'saving',
77 'stores': 'fake_store',
78 'os_glance_failed_import': 'fake_os_glance_failed_import'})
79 self.assertRaises(lib_exc.TimeoutException,
80 waiters.wait_for_image_imported_to_stores,
81 client, 'fake_image_id', 'fake_store')
82
83 def test_wait_for_image_copied_to_stores(self):
84 self.client.show_image.return_value = ({
85 'status': 'active',
86 'os_glance_importing_to_stores': '',
87 'os_glance_failed_import': 'fake_os_glance_failed_import'})
88 start_time = int(time.time())
89 waiters.wait_for_image_copied_to_stores(
90 self.client, 'fake_image_id')
91 end_time = int(time.time())
92 # Ensure waiter returns before build_timeout
93 self.assertLess((end_time - start_time), 10)
94
95 def test_wait_for_image_copied_to_stores_timeout(self):
96 time_mock = self.patch('time.time')
97 self.patch('time.time', side_effect=[0., 1.])
98 time_mock.side_effect = utils.generate_timeout_series(1)
99
100 self.client.show_image.return_value = ({
101 'status': 'active',
102 'os_glance_importing_to_stores': 'processing',
103 'os_glance_failed_import': 'fake_os_glance_failed_import'})
104 self.assertRaises(lib_exc.TimeoutException,
105 waiters.wait_for_image_copied_to_stores,
106 self.client, 'fake_image_id')
107
Artom Lifshitzdf0d6d72018-05-11 11:31:11 -0400108
109class TestInterfaceWaiters(base.TestCase):
Artom Lifshitzdf0d6d72018-05-11 11:31:11 -0400110
Federico Ressi8827d382018-06-12 23:27:00 +0200111 build_timeout = 1.
112 build_interval = 1
113 port_down = {'interfaceAttachment': {'port_state': 'DOWN'}}
114 port_active = {'interfaceAttachment': {'port_state': 'ACTIVE'}}
Artom Lifshitzdf0d6d72018-05-11 11:31:11 -0400115
Federico Ressi8827d382018-06-12 23:27:00 +0200116 def mock_client(self, **kwargs):
117 return mock.MagicMock(
118 build_timeout=self.build_timeout,
119 build_interval=self.build_interval,
120 **kwargs)
Artom Lifshitzdf0d6d72018-05-11 11:31:11 -0400121
122 def test_wait_for_interface_status(self):
Federico Ressi8827d382018-06-12 23:27:00 +0200123 show_interface = mock.Mock(
124 side_effect=[self.port_down, self.port_active])
125 client = self.mock_client(show_interface=show_interface)
126 self.patch('time.time', return_value=0.)
127 sleep = self.patch('time.sleep')
128
129 result = waiters.wait_for_interface_status(
130 client, 'server_id', 'port_id', 'ACTIVE')
131
132 self.assertIs(self.port_active['interfaceAttachment'], result)
133 show_interface.assert_has_calls([mock.call('server_id', 'port_id'),
134 mock.call('server_id', 'port_id')])
135 sleep.assert_called_once_with(client.build_interval)
Artom Lifshitzdf0d6d72018-05-11 11:31:11 -0400136
137 def test_wait_for_interface_status_timeout(self):
Federico Ressi8827d382018-06-12 23:27:00 +0200138 show_interface = mock.MagicMock(return_value=self.port_down)
139 client = self.mock_client(show_interface=show_interface)
140 self.patch('time.time', side_effect=[0., client.build_timeout + 1.])
141 sleep = self.patch('time.sleep')
Artom Lifshitzdf0d6d72018-05-11 11:31:11 -0400142
Artom Lifshitzdf0d6d72018-05-11 11:31:11 -0400143 self.assertRaises(lib_exc.TimeoutException,
144 waiters.wait_for_interface_status,
Federico Ressi8827d382018-06-12 23:27:00 +0200145 client, 'server_id', 'port_id', 'ACTIVE')
Artom Lifshitz3306d422018-03-22 12:20:54 -0400146
Federico Ressi8827d382018-06-12 23:27:00 +0200147 show_interface.assert_has_calls([mock.call('server_id', 'port_id'),
148 mock.call('server_id', 'port_id')])
149 sleep.assert_called_once_with(client.build_interval)
Artom Lifshitz3306d422018-03-22 12:20:54 -0400150
Federico Ressi8827d382018-06-12 23:27:00 +0200151 one_interface = {'interfaceAttachments': [{'port_id': 'port_one'}]}
152 two_interfaces = {'interfaceAttachments': [{'port_id': 'port_one'},
153 {'port_id': 'port_two'}]}
Artom Lifshitz3306d422018-03-22 12:20:54 -0400154
155 def test_wait_for_interface_detach(self):
Federico Ressi8827d382018-06-12 23:27:00 +0200156 list_interfaces = mock.MagicMock(
157 side_effect=[self.two_interfaces, self.one_interface])
158 client = self.mock_client(list_interfaces=list_interfaces)
159 self.patch('time.time', return_value=0.)
160 sleep = self.patch('time.sleep')
161
162 result = waiters.wait_for_interface_detach(
163 client, 'server_id', 'port_two')
164
165 self.assertIs(self.one_interface['interfaceAttachments'], result)
166 list_interfaces.assert_has_calls([mock.call('server_id'),
167 mock.call('server_id')])
168 sleep.assert_called_once_with(client.build_interval)
Artom Lifshitz3306d422018-03-22 12:20:54 -0400169
170 def test_wait_for_interface_detach_timeout(self):
Federico Ressi8827d382018-06-12 23:27:00 +0200171 list_interfaces = mock.MagicMock(return_value=self.one_interface)
172 client = self.mock_client(list_interfaces=list_interfaces)
173 self.patch('time.time', side_effect=[0., client.build_timeout + 1.])
174 sleep = self.patch('time.sleep')
Artom Lifshitz3306d422018-03-22 12:20:54 -0400175
Artom Lifshitz3306d422018-03-22 12:20:54 -0400176 self.assertRaises(lib_exc.TimeoutException,
177 waiters.wait_for_interface_detach,
Federico Ressi8827d382018-06-12 23:27:00 +0200178 client, 'server_id', 'port_one')
179
180 list_interfaces.assert_has_calls([mock.call('server_id'),
181 mock.call('server_id')])
182 sleep.assert_called_once_with(client.build_interval)
Lee Yarwoode5597402019-02-15 20:17:00 +0000183
Slawek Kaplonskie3405ba2020-11-09 17:24:13 +0100184 def test_wait_for_guest_os_boot(self):
185 get_console_output = mock.Mock(
186 side_effect=[
187 {'output': 'os not ready yet\n'},
188 {'output': 'login:\n'}
189 ])
190 client = self.mock_client(get_console_output=get_console_output)
191 self.patch('time.time', return_value=0.)
192 sleep = self.patch('time.sleep')
193
194 with mock.patch.object(waiters.LOG, "info") as log_info:
195 waiters.wait_for_guest_os_boot(client, 'server_id')
196
197 get_console_output.assert_has_calls([
198 mock.call('server_id'), mock.call('server_id')])
199 sleep.assert_called_once_with(client.build_interval)
200 log_info.assert_not_called()
201
202 def test_wait_for_guest_os_boot_timeout(self):
203 get_console_output = mock.Mock(
204 return_value={'output': 'os not ready yet\n'})
205 client = self.mock_client(get_console_output=get_console_output)
206 self.patch('time.time', side_effect=[0., client.build_timeout + 1.])
207 self.patch('time.sleep')
208
209 with mock.patch.object(waiters.LOG, "info") as log_info:
210 waiters.wait_for_guest_os_boot(client, 'server_id')
211
212 log_info.assert_called_once()
213
Lee Yarwoode5597402019-02-15 20:17:00 +0000214
215class TestVolumeWaiters(base.TestCase):
216 vol_migrating_src_host = {
217 'volume': {'migration_status': 'migrating',
218 'os-vol-host-attr:host': 'src_host@backend#type'}}
219 vol_migrating_dst_host = {
220 'volume': {'migration_status': 'migrating',
221 'os-vol-host-attr:host': 'dst_host@backend#type'}}
222 vol_migration_success = {
223 'volume': {'migration_status': 'success',
224 'os-vol-host-attr:host': 'dst_host@backend#type'}}
225 vol_migration_error = {
226 'volume': {'migration_status': 'error',
227 'os-vol-host-attr:host': 'src_host@backend#type'}}
228
229 def test_wait_for_volume_migration_timeout(self):
230 show_volume = mock.MagicMock(return_value=self.vol_migrating_src_host)
231 client = mock.Mock(spec=volumes_client.VolumesClient,
232 resource_type="volume",
233 build_interval=1,
234 build_timeout=1,
235 show_volume=show_volume)
236 self.patch('time.time', side_effect=[0., client.build_timeout + 1.])
237 self.patch('time.sleep')
238 self.assertRaises(lib_exc.TimeoutException,
239 waiters.wait_for_volume_migration,
240 client, mock.sentinel.volume_id, 'dst_host')
241
242 def test_wait_for_volume_migration_error(self):
243 show_volume = mock.MagicMock(side_effect=[
244 self.vol_migrating_src_host,
245 self.vol_migrating_src_host,
246 self.vol_migration_error])
247 client = mock.Mock(spec=volumes_client.VolumesClient,
248 resource_type="volume",
249 build_interval=1,
250 build_timeout=1,
251 show_volume=show_volume)
252 self.patch('time.time', return_value=0.)
253 self.patch('time.sleep')
254 self.assertRaises(lib_exc.TempestException,
255 waiters.wait_for_volume_migration,
256 client, mock.sentinel.volume_id, 'dst_host')
257
258 def test_wait_for_volume_migration_success_and_dst(self):
259 show_volume = mock.MagicMock(side_effect=[
260 self.vol_migrating_src_host,
261 self.vol_migrating_dst_host,
262 self.vol_migration_success])
263 client = mock.Mock(spec=volumes_client.VolumesClient,
264 resource_type="volume",
265 build_interval=1,
266 build_timeout=1,
267 show_volume=show_volume)
268 self.patch('time.time', return_value=0.)
269 self.patch('time.sleep')
270 waiters.wait_for_volume_migration(
271 client, mock.sentinel.volume_id, 'dst_host')
272
273 # Assert that we wait until migration_status is success and dst_host is
274 # part of the returned os-vol-host-attr:host.
275 show_volume.assert_has_calls([mock.call(mock.sentinel.volume_id),
276 mock.call(mock.sentinel.volume_id),
277 mock.call(mock.sentinel.volume_id)])
Lee Yarwood9e202d82020-01-08 16:41:32 +0000278
279 @mock.patch.object(time, 'sleep')
280 def test_wait_for_volume_status_error_restoring(self, mock_sleep):
281 # Tests that the wait method raises VolumeRestoreErrorException if
282 # the volume status is 'error_restoring'.
283 client = mock.Mock(spec=volumes_client.VolumesClient,
284 resource_type="volume",
285 build_interval=1)
286 volume1 = {'volume': {'status': 'restoring-backup'}}
287 volume2 = {'volume': {'status': 'error_restoring'}}
288 mock_show = mock.Mock(side_effect=(volume1, volume2))
289 client.show_volume = mock_show
290 volume_id = '7532b91e-aa0a-4e06-b3e5-20c0c5ee1caa'
291 self.assertRaises(exceptions.VolumeRestoreErrorException,
292 waiters.wait_for_volume_resource_status,
293 client, volume_id, 'available')
294 mock_show.assert_has_calls([mock.call(volume_id),
295 mock.call(volume_id)])
296 mock_sleep.assert_called_once_with(1)
297
298 @mock.patch.object(time, 'sleep')
299 def test_wait_for_volume_status_error_extending(self, mock_sleep):
300 # Tests that the wait method raises VolumeExtendErrorException if
301 # the volume status is 'error_extending'.
302 client = mock.Mock(spec=volumes_client.VolumesClient,
303 resource_type="volume",
304 build_interval=1)
305 volume1 = {'volume': {'status': 'extending'}}
306 volume2 = {'volume': {'status': 'error_extending'}}
307 mock_show = mock.Mock(side_effect=(volume1, volume2))
308 client.show_volume = mock_show
309 volume_id = '7532b91e-aa0a-4e06-b3e5-20c0c5ee1caa'
310 self.assertRaises(exceptions.VolumeExtendErrorException,
311 waiters.wait_for_volume_resource_status,
312 client, volume_id, 'available')
313 mock_show.assert_has_calls([mock.call(volume_id),
314 mock.call(volume_id)])
315 mock_sleep.assert_called_once_with(1)
Lee Yarwoodc1b2a4a2020-01-08 17:02:49 +0000316
Peter Penchev5c243a92020-09-06 02:26:03 +0300317 def test_wait_for_volume_attachment_create(self):
318 vol_detached = {'volume': {'attachments': []}}
319 vol_attached = {'volume': {'attachments': [
320 {'id': uuids.volume_id,
321 'attachment_id': uuids.attachment_id,
322 'server_id': uuids.server_id,
323 'volume_id': uuids.volume_id}]}}
324 show_volume = mock.MagicMock(side_effect=[
325 vol_detached, vol_detached, vol_attached])
326 client = mock.Mock(spec=volumes_client.VolumesClient,
327 build_interval=1,
328 build_timeout=5,
329 show_volume=show_volume)
330 self.patch('time.time')
331 self.patch('time.sleep')
332 att = waiters.wait_for_volume_attachment_create(
333 client, uuids.volume_id, uuids.server_id)
334 assert att == vol_attached['volume']['attachments'][0]
335 # Assert that show volume is called until the attachment is removed.
336 show_volume.assert_has_calls([mock.call(uuids.volume_id),
337 mock.call(uuids.volume_id),
338 mock.call(uuids.volume_id)])
339
Lee Yarwoodc1b2a4a2020-01-08 17:02:49 +0000340 def test_wait_for_volume_attachment(self):
341 vol_detached = {'volume': {'attachments': []}}
342 vol_attached = {'volume': {'attachments': [
343 {'attachment_id': uuids.attachment_id}]}}
344 show_volume = mock.MagicMock(side_effect=[
345 vol_attached, vol_attached, vol_detached])
346 client = mock.Mock(spec=volumes_client.VolumesClient,
347 build_interval=1,
348 build_timeout=5,
349 show_volume=show_volume)
350 self.patch('time.time')
351 self.patch('time.sleep')
352 waiters.wait_for_volume_attachment_remove(client, uuids.volume_id,
353 uuids.attachment_id)
354 # Assert that show volume is called until the attachment is removed.
Peter Penchevdc4ceae2020-09-09 00:47:50 +0300355 show_volume.assert_has_calls([mock.call(uuids.volume_id),
356 mock.call(uuids.volume_id),
357 mock.call(uuids.volume_id)])
Lee Yarwoodc1b2a4a2020-01-08 17:02:49 +0000358
359 def test_wait_for_volume_attachment_timeout(self):
360 show_volume = mock.MagicMock(return_value={
361 'volume': {'attachments': [
362 {'attachment_id': uuids.attachment_id}]}})
363 client = mock.Mock(spec=volumes_client.VolumesClient,
364 build_interval=1,
365 build_timeout=1,
366 show_volume=show_volume)
367 self.patch('time.time', side_effect=[0., client.build_timeout + 1.])
368 self.patch('time.sleep')
369 # Assert that a timeout is raised if the attachment remains.
370 self.assertRaises(lib_exc.TimeoutException,
371 waiters.wait_for_volume_attachment_remove,
372 client, uuids.volume_id, uuids.attachment_id)
373
374 def test_wait_for_volume_attachment_not_present(self):
375 show_volume = mock.MagicMock(return_value={
376 'volume': {'attachments': []}})
377 client = mock.Mock(spec=volumes_client.VolumesClient,
378 build_interval=1,
379 build_timeout=1,
380 show_volume=show_volume)
381 self.patch('time.time', side_effect=[0., client.build_timeout + 1.])
382 self.patch('time.sleep')
383 waiters.wait_for_volume_attachment_remove(client, uuids.volume_id,
384 uuids.attachment_id)
385 # Assert that show volume is only called once before we return
386 show_volume.assert_called_once_with(uuids.volume_id)