blob: f03c7ccaa98f10cb3e19ab7e25c23c7a80a2d517 [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
Artom Lifshitzdf0d6d72018-05-11 11:31:11 -040058
59class TestInterfaceWaiters(base.TestCase):
Artom Lifshitzdf0d6d72018-05-11 11:31:11 -040060
Federico Ressi8827d382018-06-12 23:27:00 +020061 build_timeout = 1.
62 build_interval = 1
63 port_down = {'interfaceAttachment': {'port_state': 'DOWN'}}
64 port_active = {'interfaceAttachment': {'port_state': 'ACTIVE'}}
Artom Lifshitzdf0d6d72018-05-11 11:31:11 -040065
Federico Ressi8827d382018-06-12 23:27:00 +020066 def mock_client(self, **kwargs):
67 return mock.MagicMock(
68 build_timeout=self.build_timeout,
69 build_interval=self.build_interval,
70 **kwargs)
Artom Lifshitzdf0d6d72018-05-11 11:31:11 -040071
72 def test_wait_for_interface_status(self):
Federico Ressi8827d382018-06-12 23:27:00 +020073 show_interface = mock.Mock(
74 side_effect=[self.port_down, self.port_active])
75 client = self.mock_client(show_interface=show_interface)
76 self.patch('time.time', return_value=0.)
77 sleep = self.patch('time.sleep')
78
79 result = waiters.wait_for_interface_status(
80 client, 'server_id', 'port_id', 'ACTIVE')
81
82 self.assertIs(self.port_active['interfaceAttachment'], result)
83 show_interface.assert_has_calls([mock.call('server_id', 'port_id'),
84 mock.call('server_id', 'port_id')])
85 sleep.assert_called_once_with(client.build_interval)
Artom Lifshitzdf0d6d72018-05-11 11:31:11 -040086
87 def test_wait_for_interface_status_timeout(self):
Federico Ressi8827d382018-06-12 23:27:00 +020088 show_interface = mock.MagicMock(return_value=self.port_down)
89 client = self.mock_client(show_interface=show_interface)
90 self.patch('time.time', side_effect=[0., client.build_timeout + 1.])
91 sleep = self.patch('time.sleep')
Artom Lifshitzdf0d6d72018-05-11 11:31:11 -040092
Artom Lifshitzdf0d6d72018-05-11 11:31:11 -040093 self.assertRaises(lib_exc.TimeoutException,
94 waiters.wait_for_interface_status,
Federico Ressi8827d382018-06-12 23:27:00 +020095 client, 'server_id', 'port_id', 'ACTIVE')
Artom Lifshitz3306d422018-03-22 12:20:54 -040096
Federico Ressi8827d382018-06-12 23:27:00 +020097 show_interface.assert_has_calls([mock.call('server_id', 'port_id'),
98 mock.call('server_id', 'port_id')])
99 sleep.assert_called_once_with(client.build_interval)
Artom Lifshitz3306d422018-03-22 12:20:54 -0400100
Federico Ressi8827d382018-06-12 23:27:00 +0200101 one_interface = {'interfaceAttachments': [{'port_id': 'port_one'}]}
102 two_interfaces = {'interfaceAttachments': [{'port_id': 'port_one'},
103 {'port_id': 'port_two'}]}
Artom Lifshitz3306d422018-03-22 12:20:54 -0400104
105 def test_wait_for_interface_detach(self):
Federico Ressi8827d382018-06-12 23:27:00 +0200106 list_interfaces = mock.MagicMock(
107 side_effect=[self.two_interfaces, self.one_interface])
108 client = self.mock_client(list_interfaces=list_interfaces)
109 self.patch('time.time', return_value=0.)
110 sleep = self.patch('time.sleep')
111
112 result = waiters.wait_for_interface_detach(
113 client, 'server_id', 'port_two')
114
115 self.assertIs(self.one_interface['interfaceAttachments'], result)
116 list_interfaces.assert_has_calls([mock.call('server_id'),
117 mock.call('server_id')])
118 sleep.assert_called_once_with(client.build_interval)
Artom Lifshitz3306d422018-03-22 12:20:54 -0400119
120 def test_wait_for_interface_detach_timeout(self):
Federico Ressi8827d382018-06-12 23:27:00 +0200121 list_interfaces = mock.MagicMock(return_value=self.one_interface)
122 client = self.mock_client(list_interfaces=list_interfaces)
123 self.patch('time.time', side_effect=[0., client.build_timeout + 1.])
124 sleep = self.patch('time.sleep')
Artom Lifshitz3306d422018-03-22 12:20:54 -0400125
Artom Lifshitz3306d422018-03-22 12:20:54 -0400126 self.assertRaises(lib_exc.TimeoutException,
127 waiters.wait_for_interface_detach,
Federico Ressi8827d382018-06-12 23:27:00 +0200128 client, 'server_id', 'port_one')
129
130 list_interfaces.assert_has_calls([mock.call('server_id'),
131 mock.call('server_id')])
132 sleep.assert_called_once_with(client.build_interval)
Lee Yarwoode5597402019-02-15 20:17:00 +0000133
Slawek Kaplonskie3405ba2020-11-09 17:24:13 +0100134 def test_wait_for_guest_os_boot(self):
135 get_console_output = mock.Mock(
136 side_effect=[
137 {'output': 'os not ready yet\n'},
138 {'output': 'login:\n'}
139 ])
140 client = self.mock_client(get_console_output=get_console_output)
141 self.patch('time.time', return_value=0.)
142 sleep = self.patch('time.sleep')
143
144 with mock.patch.object(waiters.LOG, "info") as log_info:
145 waiters.wait_for_guest_os_boot(client, 'server_id')
146
147 get_console_output.assert_has_calls([
148 mock.call('server_id'), mock.call('server_id')])
149 sleep.assert_called_once_with(client.build_interval)
150 log_info.assert_not_called()
151
152 def test_wait_for_guest_os_boot_timeout(self):
153 get_console_output = mock.Mock(
154 return_value={'output': 'os not ready yet\n'})
155 client = self.mock_client(get_console_output=get_console_output)
156 self.patch('time.time', side_effect=[0., client.build_timeout + 1.])
157 self.patch('time.sleep')
158
159 with mock.patch.object(waiters.LOG, "info") as log_info:
160 waiters.wait_for_guest_os_boot(client, 'server_id')
161
162 log_info.assert_called_once()
163
Lee Yarwoode5597402019-02-15 20:17:00 +0000164
165class TestVolumeWaiters(base.TestCase):
166 vol_migrating_src_host = {
167 'volume': {'migration_status': 'migrating',
168 'os-vol-host-attr:host': 'src_host@backend#type'}}
169 vol_migrating_dst_host = {
170 'volume': {'migration_status': 'migrating',
171 'os-vol-host-attr:host': 'dst_host@backend#type'}}
172 vol_migration_success = {
173 'volume': {'migration_status': 'success',
174 'os-vol-host-attr:host': 'dst_host@backend#type'}}
175 vol_migration_error = {
176 'volume': {'migration_status': 'error',
177 'os-vol-host-attr:host': 'src_host@backend#type'}}
178
179 def test_wait_for_volume_migration_timeout(self):
180 show_volume = mock.MagicMock(return_value=self.vol_migrating_src_host)
181 client = mock.Mock(spec=volumes_client.VolumesClient,
182 resource_type="volume",
183 build_interval=1,
184 build_timeout=1,
185 show_volume=show_volume)
186 self.patch('time.time', side_effect=[0., client.build_timeout + 1.])
187 self.patch('time.sleep')
188 self.assertRaises(lib_exc.TimeoutException,
189 waiters.wait_for_volume_migration,
190 client, mock.sentinel.volume_id, 'dst_host')
191
192 def test_wait_for_volume_migration_error(self):
193 show_volume = mock.MagicMock(side_effect=[
194 self.vol_migrating_src_host,
195 self.vol_migrating_src_host,
196 self.vol_migration_error])
197 client = mock.Mock(spec=volumes_client.VolumesClient,
198 resource_type="volume",
199 build_interval=1,
200 build_timeout=1,
201 show_volume=show_volume)
202 self.patch('time.time', return_value=0.)
203 self.patch('time.sleep')
204 self.assertRaises(lib_exc.TempestException,
205 waiters.wait_for_volume_migration,
206 client, mock.sentinel.volume_id, 'dst_host')
207
208 def test_wait_for_volume_migration_success_and_dst(self):
209 show_volume = mock.MagicMock(side_effect=[
210 self.vol_migrating_src_host,
211 self.vol_migrating_dst_host,
212 self.vol_migration_success])
213 client = mock.Mock(spec=volumes_client.VolumesClient,
214 resource_type="volume",
215 build_interval=1,
216 build_timeout=1,
217 show_volume=show_volume)
218 self.patch('time.time', return_value=0.)
219 self.patch('time.sleep')
220 waiters.wait_for_volume_migration(
221 client, mock.sentinel.volume_id, 'dst_host')
222
223 # Assert that we wait until migration_status is success and dst_host is
224 # part of the returned os-vol-host-attr:host.
225 show_volume.assert_has_calls([mock.call(mock.sentinel.volume_id),
226 mock.call(mock.sentinel.volume_id),
227 mock.call(mock.sentinel.volume_id)])
Lee Yarwood9e202d82020-01-08 16:41:32 +0000228
229 @mock.patch.object(time, 'sleep')
230 def test_wait_for_volume_status_error_restoring(self, mock_sleep):
231 # Tests that the wait method raises VolumeRestoreErrorException if
232 # the volume status is 'error_restoring'.
233 client = mock.Mock(spec=volumes_client.VolumesClient,
234 resource_type="volume",
235 build_interval=1)
236 volume1 = {'volume': {'status': 'restoring-backup'}}
237 volume2 = {'volume': {'status': 'error_restoring'}}
238 mock_show = mock.Mock(side_effect=(volume1, volume2))
239 client.show_volume = mock_show
240 volume_id = '7532b91e-aa0a-4e06-b3e5-20c0c5ee1caa'
241 self.assertRaises(exceptions.VolumeRestoreErrorException,
242 waiters.wait_for_volume_resource_status,
243 client, volume_id, 'available')
244 mock_show.assert_has_calls([mock.call(volume_id),
245 mock.call(volume_id)])
246 mock_sleep.assert_called_once_with(1)
247
248 @mock.patch.object(time, 'sleep')
249 def test_wait_for_volume_status_error_extending(self, mock_sleep):
250 # Tests that the wait method raises VolumeExtendErrorException if
251 # the volume status is 'error_extending'.
252 client = mock.Mock(spec=volumes_client.VolumesClient,
253 resource_type="volume",
254 build_interval=1)
255 volume1 = {'volume': {'status': 'extending'}}
256 volume2 = {'volume': {'status': 'error_extending'}}
257 mock_show = mock.Mock(side_effect=(volume1, volume2))
258 client.show_volume = mock_show
259 volume_id = '7532b91e-aa0a-4e06-b3e5-20c0c5ee1caa'
260 self.assertRaises(exceptions.VolumeExtendErrorException,
261 waiters.wait_for_volume_resource_status,
262 client, volume_id, 'available')
263 mock_show.assert_has_calls([mock.call(volume_id),
264 mock.call(volume_id)])
265 mock_sleep.assert_called_once_with(1)
Lee Yarwoodc1b2a4a2020-01-08 17:02:49 +0000266
Peter Penchev5c243a92020-09-06 02:26:03 +0300267 def test_wait_for_volume_attachment_create(self):
268 vol_detached = {'volume': {'attachments': []}}
269 vol_attached = {'volume': {'attachments': [
270 {'id': uuids.volume_id,
271 'attachment_id': uuids.attachment_id,
272 'server_id': uuids.server_id,
273 'volume_id': uuids.volume_id}]}}
274 show_volume = mock.MagicMock(side_effect=[
275 vol_detached, vol_detached, vol_attached])
276 client = mock.Mock(spec=volumes_client.VolumesClient,
277 build_interval=1,
278 build_timeout=5,
279 show_volume=show_volume)
280 self.patch('time.time')
281 self.patch('time.sleep')
282 att = waiters.wait_for_volume_attachment_create(
283 client, uuids.volume_id, uuids.server_id)
284 assert att == vol_attached['volume']['attachments'][0]
285 # Assert that show volume is called until the attachment is removed.
286 show_volume.assert_has_calls([mock.call(uuids.volume_id),
287 mock.call(uuids.volume_id),
288 mock.call(uuids.volume_id)])
289
Lee Yarwoodc1b2a4a2020-01-08 17:02:49 +0000290 def test_wait_for_volume_attachment(self):
291 vol_detached = {'volume': {'attachments': []}}
292 vol_attached = {'volume': {'attachments': [
293 {'attachment_id': uuids.attachment_id}]}}
294 show_volume = mock.MagicMock(side_effect=[
295 vol_attached, vol_attached, vol_detached])
296 client = mock.Mock(spec=volumes_client.VolumesClient,
297 build_interval=1,
298 build_timeout=5,
299 show_volume=show_volume)
300 self.patch('time.time')
301 self.patch('time.sleep')
302 waiters.wait_for_volume_attachment_remove(client, uuids.volume_id,
303 uuids.attachment_id)
304 # Assert that show volume is called until the attachment is removed.
Peter Penchevdc4ceae2020-09-09 00:47:50 +0300305 show_volume.assert_has_calls([mock.call(uuids.volume_id),
306 mock.call(uuids.volume_id),
307 mock.call(uuids.volume_id)])
Lee Yarwoodc1b2a4a2020-01-08 17:02:49 +0000308
309 def test_wait_for_volume_attachment_timeout(self):
310 show_volume = mock.MagicMock(return_value={
311 'volume': {'attachments': [
312 {'attachment_id': uuids.attachment_id}]}})
313 client = mock.Mock(spec=volumes_client.VolumesClient,
314 build_interval=1,
315 build_timeout=1,
316 show_volume=show_volume)
317 self.patch('time.time', side_effect=[0., client.build_timeout + 1.])
318 self.patch('time.sleep')
319 # Assert that a timeout is raised if the attachment remains.
320 self.assertRaises(lib_exc.TimeoutException,
321 waiters.wait_for_volume_attachment_remove,
322 client, uuids.volume_id, uuids.attachment_id)
323
324 def test_wait_for_volume_attachment_not_present(self):
325 show_volume = mock.MagicMock(return_value={
326 'volume': {'attachments': []}})
327 client = mock.Mock(spec=volumes_client.VolumesClient,
328 build_interval=1,
329 build_timeout=1,
330 show_volume=show_volume)
331 self.patch('time.time', side_effect=[0., client.build_timeout + 1.])
332 self.patch('time.sleep')
333 waiters.wait_for_volume_attachment_remove(client, uuids.volume_id,
334 uuids.attachment_id)
335 # Assert that show volume is only called once before we return
336 show_volume.assert_called_once_with(uuids.volume_id)