Matthew Treinish | 7b01582 | 2014-01-21 18:15:39 +0000 | [diff] [blame] | 1 | # 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 | |
| 15 | import time |
Sean McGinnis | eed8074 | 2020-04-18 12:01:03 -0500 | [diff] [blame] | 16 | from unittest import mock |
Matthew Treinish | 7b01582 | 2014-01-21 18:15:39 +0000 | [diff] [blame] | 17 | |
Lee Yarwood | c1b2a4a | 2020-01-08 17:02:49 +0000 | [diff] [blame] | 18 | from oslo_utils.fixture import uuidsentinel as uuids |
Matthew Treinish | 7b01582 | 2014-01-21 18:15:39 +0000 | [diff] [blame] | 19 | |
| 20 | from tempest.common import waiters |
| 21 | from tempest import exceptions |
guo yunxian | ebb15f2 | 2016-11-01 21:03:35 +0800 | [diff] [blame] | 22 | from tempest.lib import exceptions as lib_exc |
Balazs Gibizer | 2e515fe | 2020-12-07 15:10:11 +0100 | [diff] [blame] | 23 | from tempest.lib.services.compute import servers_client |
Eliad Cohen | bec2d4d | 2022-09-14 17:52:59 +0000 | [diff] [blame] | 24 | from tempest.lib.services.network import ports_client |
lkuchlan | f53947e | 2016-09-15 10:37:57 +0300 | [diff] [blame] | 25 | from tempest.lib.services.volume.v2 import volumes_client |
Matthew Treinish | ffad78a | 2016-04-16 14:39:52 -0400 | [diff] [blame] | 26 | from tempest.tests import base |
Jordan Pittier | 0e53b61 | 2016-03-03 14:23:17 +0100 | [diff] [blame] | 27 | import tempest.tests.utils as utils |
Matthew Treinish | 7b01582 | 2014-01-21 18:15:39 +0000 | [diff] [blame] | 28 | |
| 29 | |
| 30 | class TestImageWaiters(base.TestCase): |
| 31 | def setUp(self): |
| 32 | super(TestImageWaiters, self).setUp() |
| 33 | self.client = mock.MagicMock() |
| 34 | self.client.build_timeout = 1 |
| 35 | self.client.build_interval = 1 |
| 36 | |
| 37 | def test_wait_for_image_status(self): |
Ken'ichi Ohmichi | 5d41076 | 2015-05-22 01:10:03 +0000 | [diff] [blame] | 38 | self.client.show_image.return_value = ({'status': 'active'}) |
Matthew Treinish | 7b01582 | 2014-01-21 18:15:39 +0000 | [diff] [blame] | 39 | start_time = int(time.time()) |
| 40 | waiters.wait_for_image_status(self.client, 'fake_image_id', 'active') |
| 41 | end_time = int(time.time()) |
| 42 | # Ensure waiter returns before build_timeout |
Béla Vancsics | 64862f7 | 2016-11-08 09:12:31 +0100 | [diff] [blame] | 43 | self.assertLess((end_time - start_time), 10) |
Matthew Treinish | 7b01582 | 2014-01-21 18:15:39 +0000 | [diff] [blame] | 44 | |
Yaroslav Lobankov | 2fea405 | 2016-04-19 15:05:57 +0300 | [diff] [blame] | 45 | def test_wait_for_image_status_timeout(self): |
Jordan Pittier | 0e53b61 | 2016-03-03 14:23:17 +0100 | [diff] [blame] | 46 | time_mock = self.patch('time.time') |
| 47 | time_mock.side_effect = utils.generate_timeout_series(1) |
| 48 | |
Ken'ichi Ohmichi | 5d41076 | 2015-05-22 01:10:03 +0000 | [diff] [blame] | 49 | self.client.show_image.return_value = ({'status': 'saving'}) |
guo yunxian | ebb15f2 | 2016-11-01 21:03:35 +0800 | [diff] [blame] | 50 | self.assertRaises(lib_exc.TimeoutException, |
Matthew Treinish | 7b01582 | 2014-01-21 18:15:39 +0000 | [diff] [blame] | 51 | waiters.wait_for_image_status, |
| 52 | self.client, 'fake_image_id', 'active') |
| 53 | |
Yaroslav Lobankov | 2fea405 | 2016-04-19 15:05:57 +0300 | [diff] [blame] | 54 | def test_wait_for_image_status_error_on_image_create(self): |
Ken'ichi Ohmichi | 5d41076 | 2015-05-22 01:10:03 +0000 | [diff] [blame] | 55 | self.client.show_image.return_value = ({'status': 'ERROR'}) |
Matthew Treinish | 7b01582 | 2014-01-21 18:15:39 +0000 | [diff] [blame] | 56 | self.assertRaises(exceptions.AddImageException, |
| 57 | waiters.wait_for_image_status, |
| 58 | self.client, 'fake_image_id', 'active') |
Matt Riedemann | f77e7dc | 2015-08-10 16:39:39 -0700 | [diff] [blame] | 59 | |
zhufl | 414ffba | 2020-11-19 16:57:06 +0800 | [diff] [blame] | 60 | def test_wait_for_image_imported_to_stores(self): |
| 61 | self.client.show_image.return_value = ({'status': 'active', |
| 62 | 'stores': 'fake_store'}) |
Dan Smith | 466f706 | 2022-10-10 15:25:39 -0700 | [diff] [blame] | 63 | self.client.info_stores.return_value = { |
| 64 | 'stores': [{'id': 'fake_store', |
| 65 | 'description': 'A writable store'}, |
| 66 | {'id': 'another_fake_store', |
| 67 | 'description': 'A read-only store', |
| 68 | 'read-only': 'true'}] |
| 69 | } |
zhufl | 414ffba | 2020-11-19 16:57:06 +0800 | [diff] [blame] | 70 | start_time = int(time.time()) |
| 71 | waiters.wait_for_image_imported_to_stores( |
Dan Smith | 466f706 | 2022-10-10 15:25:39 -0700 | [diff] [blame] | 72 | self.client, 'fake_image_id', 'fake_store,another_fake_store') |
zhufl | 414ffba | 2020-11-19 16:57:06 +0800 | [diff] [blame] | 73 | end_time = int(time.time()) |
Dan Smith | 466f706 | 2022-10-10 15:25:39 -0700 | [diff] [blame] | 74 | # Ensure waiter returns before build_timeout, and did not wait |
| 75 | # for the read-only store |
zhufl | 414ffba | 2020-11-19 16:57:06 +0800 | [diff] [blame] | 76 | self.assertLess((end_time - start_time), 10) |
| 77 | |
Dan Smith | ef8e054 | 2021-02-05 13:05:45 -0800 | [diff] [blame] | 78 | def test_wait_for_image_imported_to_stores_failure(self): |
zhufl | 414ffba | 2020-11-19 16:57:06 +0800 | [diff] [blame] | 79 | time_mock = self.patch('time.time') |
| 80 | client = mock.MagicMock() |
| 81 | client.build_timeout = 2 |
| 82 | self.patch('time.time', side_effect=[0., 1., 2.]) |
| 83 | time_mock.side_effect = utils.generate_timeout_series(1) |
| 84 | |
| 85 | client.show_image.return_value = ({ |
| 86 | 'status': 'saving', |
| 87 | 'stores': 'fake_store', |
| 88 | 'os_glance_failed_import': 'fake_os_glance_failed_import'}) |
Dan Smith | ef8e054 | 2021-02-05 13:05:45 -0800 | [diff] [blame] | 89 | self.assertRaises(lib_exc.OtherRestClientException, |
| 90 | waiters.wait_for_image_imported_to_stores, |
| 91 | client, 'fake_image_id', 'fake_store') |
| 92 | |
| 93 | def test_wait_for_image_imported_to_stores_timeout(self): |
| 94 | time_mock = self.patch('time.time') |
| 95 | client = mock.MagicMock() |
| 96 | client.build_timeout = 2 |
| 97 | self.patch('time.time', side_effect=[0., 1., 2.]) |
| 98 | time_mock.side_effect = utils.generate_timeout_series(1) |
| 99 | |
| 100 | client.show_image.return_value = ({ |
| 101 | 'status': 'saving', |
| 102 | 'stores': 'fake_store'}) |
zhufl | 414ffba | 2020-11-19 16:57:06 +0800 | [diff] [blame] | 103 | self.assertRaises(lib_exc.TimeoutException, |
| 104 | waiters.wait_for_image_imported_to_stores, |
| 105 | client, 'fake_image_id', 'fake_store') |
| 106 | |
Dan Smith | 466f706 | 2022-10-10 15:25:39 -0700 | [diff] [blame] | 107 | def test_wait_for_image_imported_to_stores_no_stores(self): |
| 108 | client = mock.MagicMock() |
| 109 | client.show_image.return_value = ({'status': 'active'}) |
| 110 | client.info_stores.side_effect = lib_exc.NotFound |
| 111 | client.build_timeout = 2 |
| 112 | start_time = time.time() |
| 113 | waiters.wait_for_image_imported_to_stores( |
| 114 | client, 'fake_image_id', None) |
| 115 | end_time = time.time() |
| 116 | self.assertLess(end_time - start_time, 10) |
| 117 | |
| 118 | exc = self.assertRaises(lib_exc.TimeoutException, |
| 119 | waiters.wait_for_image_imported_to_stores, |
| 120 | client, 'fake_image_id', 'foo,bar') |
| 121 | self.assertIn('cowardly', str(exc)) |
| 122 | |
zhufl | 414ffba | 2020-11-19 16:57:06 +0800 | [diff] [blame] | 123 | def test_wait_for_image_copied_to_stores(self): |
| 124 | self.client.show_image.return_value = ({ |
| 125 | 'status': 'active', |
| 126 | 'os_glance_importing_to_stores': '', |
| 127 | 'os_glance_failed_import': 'fake_os_glance_failed_import'}) |
| 128 | start_time = int(time.time()) |
| 129 | waiters.wait_for_image_copied_to_stores( |
| 130 | self.client, 'fake_image_id') |
| 131 | end_time = int(time.time()) |
| 132 | # Ensure waiter returns before build_timeout |
| 133 | self.assertLess((end_time - start_time), 10) |
| 134 | |
| 135 | def test_wait_for_image_copied_to_stores_timeout(self): |
| 136 | time_mock = self.patch('time.time') |
| 137 | self.patch('time.time', side_effect=[0., 1.]) |
| 138 | time_mock.side_effect = utils.generate_timeout_series(1) |
| 139 | |
| 140 | self.client.show_image.return_value = ({ |
| 141 | 'status': 'active', |
| 142 | 'os_glance_importing_to_stores': 'processing', |
| 143 | 'os_glance_failed_import': 'fake_os_glance_failed_import'}) |
| 144 | self.assertRaises(lib_exc.TimeoutException, |
| 145 | waiters.wait_for_image_copied_to_stores, |
| 146 | self.client, 'fake_image_id') |
| 147 | |
Ghanshyam Mann | b15b58e | 2021-04-29 19:45:29 -0500 | [diff] [blame] | 148 | def test_wait_for_image_tasks_status(self): |
| 149 | self.client.show_image_tasks.return_value = ({ |
| 150 | 'tasks': [{'status': 'success'}]}) |
| 151 | start_time = int(time.time()) |
| 152 | waiters.wait_for_image_tasks_status( |
| 153 | self.client, 'fake_image_id', 'success') |
| 154 | end_time = int(time.time()) |
| 155 | # Ensure waiter returns before build_timeout |
| 156 | self.assertLess((end_time - start_time), 10) |
| 157 | |
| 158 | def test_wait_for_image_tasks_status_timeout(self): |
| 159 | time_mock = self.patch('time.time') |
| 160 | self.patch('time.time', side_effect=[0., 1.]) |
| 161 | time_mock.side_effect = utils.generate_timeout_series(1) |
| 162 | |
| 163 | self.client.show_image_tasks.return_value = ({ |
| 164 | 'tasks': [ |
| 165 | {'status': 'success'}, |
| 166 | {'status': 'processing'}]}) |
| 167 | self.assertRaises(lib_exc.TimeoutException, |
| 168 | waiters.wait_for_image_tasks_status, |
| 169 | self.client, 'fake_image_id', 'success') |
| 170 | |
Artom Lifshitz | df0d6d7 | 2018-05-11 11:31:11 -0400 | [diff] [blame] | 171 | |
| 172 | class TestInterfaceWaiters(base.TestCase): |
Artom Lifshitz | df0d6d7 | 2018-05-11 11:31:11 -0400 | [diff] [blame] | 173 | |
Federico Ressi | 8827d38 | 2018-06-12 23:27:00 +0200 | [diff] [blame] | 174 | build_timeout = 1. |
| 175 | build_interval = 1 |
| 176 | port_down = {'interfaceAttachment': {'port_state': 'DOWN'}} |
| 177 | port_active = {'interfaceAttachment': {'port_state': 'ACTIVE'}} |
Artom Lifshitz | df0d6d7 | 2018-05-11 11:31:11 -0400 | [diff] [blame] | 178 | |
Federico Ressi | 8827d38 | 2018-06-12 23:27:00 +0200 | [diff] [blame] | 179 | def mock_client(self, **kwargs): |
| 180 | return mock.MagicMock( |
| 181 | build_timeout=self.build_timeout, |
| 182 | build_interval=self.build_interval, |
| 183 | **kwargs) |
Artom Lifshitz | df0d6d7 | 2018-05-11 11:31:11 -0400 | [diff] [blame] | 184 | |
| 185 | def test_wait_for_interface_status(self): |
Federico Ressi | 8827d38 | 2018-06-12 23:27:00 +0200 | [diff] [blame] | 186 | show_interface = mock.Mock( |
| 187 | side_effect=[self.port_down, self.port_active]) |
| 188 | client = self.mock_client(show_interface=show_interface) |
| 189 | self.patch('time.time', return_value=0.) |
| 190 | sleep = self.patch('time.sleep') |
| 191 | |
| 192 | result = waiters.wait_for_interface_status( |
| 193 | client, 'server_id', 'port_id', 'ACTIVE') |
| 194 | |
| 195 | self.assertIs(self.port_active['interfaceAttachment'], result) |
| 196 | show_interface.assert_has_calls([mock.call('server_id', 'port_id'), |
| 197 | mock.call('server_id', 'port_id')]) |
| 198 | sleep.assert_called_once_with(client.build_interval) |
Artom Lifshitz | df0d6d7 | 2018-05-11 11:31:11 -0400 | [diff] [blame] | 199 | |
| 200 | def test_wait_for_interface_status_timeout(self): |
Federico Ressi | 8827d38 | 2018-06-12 23:27:00 +0200 | [diff] [blame] | 201 | show_interface = mock.MagicMock(return_value=self.port_down) |
| 202 | client = self.mock_client(show_interface=show_interface) |
| 203 | self.patch('time.time', side_effect=[0., client.build_timeout + 1.]) |
| 204 | sleep = self.patch('time.sleep') |
Artom Lifshitz | df0d6d7 | 2018-05-11 11:31:11 -0400 | [diff] [blame] | 205 | |
Artom Lifshitz | df0d6d7 | 2018-05-11 11:31:11 -0400 | [diff] [blame] | 206 | self.assertRaises(lib_exc.TimeoutException, |
| 207 | waiters.wait_for_interface_status, |
Federico Ressi | 8827d38 | 2018-06-12 23:27:00 +0200 | [diff] [blame] | 208 | client, 'server_id', 'port_id', 'ACTIVE') |
Artom Lifshitz | 3306d42 | 2018-03-22 12:20:54 -0400 | [diff] [blame] | 209 | |
Federico Ressi | 8827d38 | 2018-06-12 23:27:00 +0200 | [diff] [blame] | 210 | show_interface.assert_has_calls([mock.call('server_id', 'port_id'), |
| 211 | mock.call('server_id', 'port_id')]) |
| 212 | sleep.assert_called_once_with(client.build_interval) |
Artom Lifshitz | 3306d42 | 2018-03-22 12:20:54 -0400 | [diff] [blame] | 213 | |
Artom Lifshitz | 3306d42 | 2018-03-22 12:20:54 -0400 | [diff] [blame] | 214 | def test_wait_for_interface_detach(self): |
Balazs Gibizer | 5541458 | 2021-10-05 11:22:30 +0200 | [diff] [blame] | 215 | no_event = { |
| 216 | 'instanceAction': { |
| 217 | 'events': [] |
| 218 | } |
| 219 | } |
| 220 | one_event_without_result = { |
| 221 | 'instanceAction': { |
| 222 | 'events': [ |
| 223 | { |
| 224 | 'event': 'compute_detach_interface', |
| 225 | 'result': None |
| 226 | } |
| 227 | |
| 228 | ] |
| 229 | } |
| 230 | } |
| 231 | one_event_successful = { |
| 232 | 'instanceAction': { |
| 233 | 'events': [ |
| 234 | { |
| 235 | 'event': 'compute_detach_interface', |
| 236 | 'result': 'Success' |
| 237 | } |
| 238 | ] |
| 239 | } |
| 240 | } |
| 241 | |
| 242 | show_instance_action = mock.MagicMock( |
| 243 | # there is an extra call to return the result from the waiter |
| 244 | side_effect=[ |
| 245 | no_event, |
| 246 | one_event_without_result, |
| 247 | one_event_successful, |
| 248 | one_event_successful, |
| 249 | ] |
| 250 | ) |
| 251 | client = self.mock_client(show_instance_action=show_instance_action) |
Federico Ressi | 8827d38 | 2018-06-12 23:27:00 +0200 | [diff] [blame] | 252 | self.patch('time.time', return_value=0.) |
| 253 | sleep = self.patch('time.sleep') |
| 254 | |
| 255 | result = waiters.wait_for_interface_detach( |
Balazs Gibizer | 5541458 | 2021-10-05 11:22:30 +0200 | [diff] [blame] | 256 | client, mock.sentinel.server_id, mock.sentinel.port_id, |
| 257 | mock.sentinel.detach_request_id |
| 258 | ) |
Federico Ressi | 8827d38 | 2018-06-12 23:27:00 +0200 | [diff] [blame] | 259 | |
Balazs Gibizer | 5541458 | 2021-10-05 11:22:30 +0200 | [diff] [blame] | 260 | self.assertIs(one_event_successful['instanceAction'], result) |
| 261 | show_instance_action.assert_has_calls( |
| 262 | # there is an extra call to return the result from the waiter |
| 263 | [ |
| 264 | mock.call( |
| 265 | mock.sentinel.server_id, mock.sentinel.detach_request_id) |
| 266 | ] * 4 |
| 267 | ) |
| 268 | sleep.assert_has_calls([mock.call(client.build_interval)] * 2) |
Artom Lifshitz | 3306d42 | 2018-03-22 12:20:54 -0400 | [diff] [blame] | 269 | |
| 270 | def test_wait_for_interface_detach_timeout(self): |
Balazs Gibizer | 5541458 | 2021-10-05 11:22:30 +0200 | [diff] [blame] | 271 | one_event_without_result = { |
| 272 | 'instanceAction': { |
| 273 | 'events': [ |
| 274 | { |
| 275 | 'event': 'compute_detach_interface', |
| 276 | 'result': None |
| 277 | } |
| 278 | |
| 279 | ] |
| 280 | } |
| 281 | } |
| 282 | |
| 283 | show_instance_action = mock.MagicMock( |
| 284 | return_value=one_event_without_result) |
| 285 | client = self.mock_client(show_instance_action=show_instance_action) |
Federico Ressi | 8827d38 | 2018-06-12 23:27:00 +0200 | [diff] [blame] | 286 | self.patch('time.time', side_effect=[0., client.build_timeout + 1.]) |
| 287 | sleep = self.patch('time.sleep') |
Artom Lifshitz | 3306d42 | 2018-03-22 12:20:54 -0400 | [diff] [blame] | 288 | |
Balazs Gibizer | 5541458 | 2021-10-05 11:22:30 +0200 | [diff] [blame] | 289 | self.assertRaises( |
| 290 | lib_exc.TimeoutException, |
| 291 | waiters.wait_for_interface_detach, |
| 292 | client, mock.sentinel.server_id, mock.sentinel.port_id, |
| 293 | mock.sentinel.detach_request_id |
| 294 | ) |
Federico Ressi | 8827d38 | 2018-06-12 23:27:00 +0200 | [diff] [blame] | 295 | |
Balazs Gibizer | 5541458 | 2021-10-05 11:22:30 +0200 | [diff] [blame] | 296 | show_instance_action.assert_has_calls( |
| 297 | [ |
| 298 | mock.call( |
| 299 | mock.sentinel.server_id, mock.sentinel.detach_request_id) |
| 300 | ] * 2 |
| 301 | ) |
Federico Ressi | 8827d38 | 2018-06-12 23:27:00 +0200 | [diff] [blame] | 302 | sleep.assert_called_once_with(client.build_interval) |
Lee Yarwood | e559740 | 2019-02-15 20:17:00 +0000 | [diff] [blame] | 303 | |
| 304 | |
| 305 | class TestVolumeWaiters(base.TestCase): |
| 306 | vol_migrating_src_host = { |
| 307 | 'volume': {'migration_status': 'migrating', |
| 308 | 'os-vol-host-attr:host': 'src_host@backend#type'}} |
| 309 | vol_migrating_dst_host = { |
| 310 | 'volume': {'migration_status': 'migrating', |
| 311 | 'os-vol-host-attr:host': 'dst_host@backend#type'}} |
| 312 | vol_migration_success = { |
| 313 | 'volume': {'migration_status': 'success', |
| 314 | 'os-vol-host-attr:host': 'dst_host@backend#type'}} |
| 315 | vol_migration_error = { |
| 316 | 'volume': {'migration_status': 'error', |
| 317 | 'os-vol-host-attr:host': 'src_host@backend#type'}} |
| 318 | |
| 319 | def test_wait_for_volume_migration_timeout(self): |
| 320 | show_volume = mock.MagicMock(return_value=self.vol_migrating_src_host) |
| 321 | client = mock.Mock(spec=volumes_client.VolumesClient, |
| 322 | resource_type="volume", |
| 323 | build_interval=1, |
| 324 | build_timeout=1, |
| 325 | show_volume=show_volume) |
| 326 | self.patch('time.time', side_effect=[0., client.build_timeout + 1.]) |
| 327 | self.patch('time.sleep') |
| 328 | self.assertRaises(lib_exc.TimeoutException, |
| 329 | waiters.wait_for_volume_migration, |
| 330 | client, mock.sentinel.volume_id, 'dst_host') |
| 331 | |
| 332 | def test_wait_for_volume_migration_error(self): |
| 333 | show_volume = mock.MagicMock(side_effect=[ |
| 334 | self.vol_migrating_src_host, |
| 335 | self.vol_migrating_src_host, |
| 336 | self.vol_migration_error]) |
| 337 | client = mock.Mock(spec=volumes_client.VolumesClient, |
| 338 | resource_type="volume", |
| 339 | build_interval=1, |
| 340 | build_timeout=1, |
| 341 | show_volume=show_volume) |
| 342 | self.patch('time.time', return_value=0.) |
| 343 | self.patch('time.sleep') |
| 344 | self.assertRaises(lib_exc.TempestException, |
| 345 | waiters.wait_for_volume_migration, |
| 346 | client, mock.sentinel.volume_id, 'dst_host') |
| 347 | |
| 348 | def test_wait_for_volume_migration_success_and_dst(self): |
| 349 | show_volume = mock.MagicMock(side_effect=[ |
| 350 | self.vol_migrating_src_host, |
| 351 | self.vol_migrating_dst_host, |
| 352 | self.vol_migration_success]) |
| 353 | client = mock.Mock(spec=volumes_client.VolumesClient, |
| 354 | resource_type="volume", |
| 355 | build_interval=1, |
| 356 | build_timeout=1, |
| 357 | show_volume=show_volume) |
| 358 | self.patch('time.time', return_value=0.) |
| 359 | self.patch('time.sleep') |
| 360 | waiters.wait_for_volume_migration( |
| 361 | client, mock.sentinel.volume_id, 'dst_host') |
| 362 | |
| 363 | # Assert that we wait until migration_status is success and dst_host is |
| 364 | # part of the returned os-vol-host-attr:host. |
| 365 | show_volume.assert_has_calls([mock.call(mock.sentinel.volume_id), |
| 366 | mock.call(mock.sentinel.volume_id), |
| 367 | mock.call(mock.sentinel.volume_id)]) |
Lee Yarwood | 9e202d8 | 2020-01-08 16:41:32 +0000 | [diff] [blame] | 368 | |
| 369 | @mock.patch.object(time, 'sleep') |
| 370 | def test_wait_for_volume_status_error_restoring(self, mock_sleep): |
| 371 | # Tests that the wait method raises VolumeRestoreErrorException if |
| 372 | # the volume status is 'error_restoring'. |
| 373 | client = mock.Mock(spec=volumes_client.VolumesClient, |
| 374 | resource_type="volume", |
| 375 | build_interval=1) |
| 376 | volume1 = {'volume': {'status': 'restoring-backup'}} |
| 377 | volume2 = {'volume': {'status': 'error_restoring'}} |
| 378 | mock_show = mock.Mock(side_effect=(volume1, volume2)) |
| 379 | client.show_volume = mock_show |
| 380 | volume_id = '7532b91e-aa0a-4e06-b3e5-20c0c5ee1caa' |
| 381 | self.assertRaises(exceptions.VolumeRestoreErrorException, |
| 382 | waiters.wait_for_volume_resource_status, |
| 383 | client, volume_id, 'available') |
| 384 | mock_show.assert_has_calls([mock.call(volume_id), |
| 385 | mock.call(volume_id)]) |
| 386 | mock_sleep.assert_called_once_with(1) |
| 387 | |
| 388 | @mock.patch.object(time, 'sleep') |
Dan Smith | aeacd8c | 2023-02-21 13:34:20 -0800 | [diff] [blame] | 389 | def test_wait_for_volume_status_timeout_console(self, mock_sleep): |
| 390 | # Tests that the wait method gets the server console log if the |
| 391 | # timeout is hit. |
| 392 | client = mock.Mock(spec=volumes_client.VolumesClient, |
| 393 | resource_type="volume", |
| 394 | build_interval=1, |
| 395 | build_timeout=1) |
| 396 | servers_client = mock.Mock() |
| 397 | servers_client.get_console_output.return_value = { |
| 398 | 'output': 'console log'} |
| 399 | volume = {'volume': {'status': 'detaching'}} |
| 400 | mock_show = mock.Mock(return_value=volume) |
| 401 | client.show_volume = mock_show |
| 402 | volume_id = '7532b91e-aa0a-4e06-b3e5-20c0c5ee1caa' |
| 403 | self.assertRaises(lib_exc.TimeoutException, |
| 404 | waiters.wait_for_volume_resource_status, |
| 405 | client, volume_id, 'available', |
| 406 | server_id='someserver', |
| 407 | servers_client=servers_client) |
| 408 | servers_client.get_console_output.assert_called_once_with( |
| 409 | 'someserver') |
| 410 | |
| 411 | @mock.patch.object(time, 'sleep') |
Lee Yarwood | 9e202d8 | 2020-01-08 16:41:32 +0000 | [diff] [blame] | 412 | def test_wait_for_volume_status_error_extending(self, mock_sleep): |
| 413 | # Tests that the wait method raises VolumeExtendErrorException if |
| 414 | # the volume status is 'error_extending'. |
| 415 | client = mock.Mock(spec=volumes_client.VolumesClient, |
| 416 | resource_type="volume", |
| 417 | build_interval=1) |
| 418 | volume1 = {'volume': {'status': 'extending'}} |
| 419 | volume2 = {'volume': {'status': 'error_extending'}} |
| 420 | mock_show = mock.Mock(side_effect=(volume1, volume2)) |
| 421 | client.show_volume = mock_show |
| 422 | volume_id = '7532b91e-aa0a-4e06-b3e5-20c0c5ee1caa' |
| 423 | self.assertRaises(exceptions.VolumeExtendErrorException, |
| 424 | waiters.wait_for_volume_resource_status, |
| 425 | client, volume_id, 'available') |
| 426 | mock_show.assert_has_calls([mock.call(volume_id), |
| 427 | mock.call(volume_id)]) |
| 428 | mock_sleep.assert_called_once_with(1) |
Lee Yarwood | c1b2a4a | 2020-01-08 17:02:49 +0000 | [diff] [blame] | 429 | |
Peter Penchev | 5c243a9 | 2020-09-06 02:26:03 +0300 | [diff] [blame] | 430 | def test_wait_for_volume_attachment_create(self): |
| 431 | vol_detached = {'volume': {'attachments': []}} |
| 432 | vol_attached = {'volume': {'attachments': [ |
| 433 | {'id': uuids.volume_id, |
| 434 | 'attachment_id': uuids.attachment_id, |
| 435 | 'server_id': uuids.server_id, |
| 436 | 'volume_id': uuids.volume_id}]}} |
| 437 | show_volume = mock.MagicMock(side_effect=[ |
| 438 | vol_detached, vol_detached, vol_attached]) |
| 439 | client = mock.Mock(spec=volumes_client.VolumesClient, |
| 440 | build_interval=1, |
| 441 | build_timeout=5, |
| 442 | show_volume=show_volume) |
| 443 | self.patch('time.time') |
| 444 | self.patch('time.sleep') |
| 445 | att = waiters.wait_for_volume_attachment_create( |
| 446 | client, uuids.volume_id, uuids.server_id) |
| 447 | assert att == vol_attached['volume']['attachments'][0] |
| 448 | # Assert that show volume is called until the attachment is removed. |
| 449 | show_volume.assert_has_calls([mock.call(uuids.volume_id), |
| 450 | mock.call(uuids.volume_id), |
| 451 | mock.call(uuids.volume_id)]) |
| 452 | |
Lee Yarwood | c1b2a4a | 2020-01-08 17:02:49 +0000 | [diff] [blame] | 453 | def test_wait_for_volume_attachment(self): |
| 454 | vol_detached = {'volume': {'attachments': []}} |
| 455 | vol_attached = {'volume': {'attachments': [ |
| 456 | {'attachment_id': uuids.attachment_id}]}} |
| 457 | show_volume = mock.MagicMock(side_effect=[ |
| 458 | vol_attached, vol_attached, vol_detached]) |
| 459 | client = mock.Mock(spec=volumes_client.VolumesClient, |
| 460 | build_interval=1, |
| 461 | build_timeout=5, |
| 462 | show_volume=show_volume) |
| 463 | self.patch('time.time') |
| 464 | self.patch('time.sleep') |
| 465 | waiters.wait_for_volume_attachment_remove(client, uuids.volume_id, |
| 466 | uuids.attachment_id) |
| 467 | # Assert that show volume is called until the attachment is removed. |
Peter Penchev | dc4ceae | 2020-09-09 00:47:50 +0300 | [diff] [blame] | 468 | show_volume.assert_has_calls([mock.call(uuids.volume_id), |
| 469 | mock.call(uuids.volume_id), |
| 470 | mock.call(uuids.volume_id)]) |
Lee Yarwood | c1b2a4a | 2020-01-08 17:02:49 +0000 | [diff] [blame] | 471 | |
| 472 | def test_wait_for_volume_attachment_timeout(self): |
| 473 | show_volume = mock.MagicMock(return_value={ |
| 474 | 'volume': {'attachments': [ |
| 475 | {'attachment_id': uuids.attachment_id}]}}) |
| 476 | client = mock.Mock(spec=volumes_client.VolumesClient, |
| 477 | build_interval=1, |
| 478 | build_timeout=1, |
| 479 | show_volume=show_volume) |
| 480 | self.patch('time.time', side_effect=[0., client.build_timeout + 1.]) |
| 481 | self.patch('time.sleep') |
| 482 | # Assert that a timeout is raised if the attachment remains. |
| 483 | self.assertRaises(lib_exc.TimeoutException, |
| 484 | waiters.wait_for_volume_attachment_remove, |
| 485 | client, uuids.volume_id, uuids.attachment_id) |
| 486 | |
| 487 | def test_wait_for_volume_attachment_not_present(self): |
| 488 | show_volume = mock.MagicMock(return_value={ |
| 489 | 'volume': {'attachments': []}}) |
| 490 | client = mock.Mock(spec=volumes_client.VolumesClient, |
| 491 | build_interval=1, |
| 492 | build_timeout=1, |
| 493 | show_volume=show_volume) |
| 494 | self.patch('time.time', side_effect=[0., client.build_timeout + 1.]) |
| 495 | self.patch('time.sleep') |
| 496 | waiters.wait_for_volume_attachment_remove(client, uuids.volume_id, |
| 497 | uuids.attachment_id) |
| 498 | # Assert that show volume is only called once before we return |
| 499 | show_volume.assert_called_once_with(uuids.volume_id) |
Balazs Gibizer | 2e515fe | 2020-12-07 15:10:11 +0100 | [diff] [blame] | 500 | |
| 501 | def test_wait_for_volume_attachment_remove_from_server(self): |
| 502 | volume_attached = { |
| 503 | "volumeAttachments": [{"volumeId": uuids.volume_id}]} |
| 504 | volume_not_attached = {"volumeAttachments": []} |
| 505 | mock_list_volume_attachments = mock.Mock( |
| 506 | side_effect=[volume_attached, volume_not_attached]) |
| 507 | mock_client = mock.Mock( |
| 508 | spec=servers_client.ServersClient, |
| 509 | build_interval=1, |
| 510 | build_timeout=1, |
| 511 | list_volume_attachments=mock_list_volume_attachments) |
| 512 | self.patch( |
| 513 | 'time.time', |
| 514 | side_effect=[0., 0.5, mock_client.build_timeout + 1.]) |
| 515 | self.patch('time.sleep') |
| 516 | |
| 517 | waiters.wait_for_volume_attachment_remove_from_server( |
| 518 | mock_client, uuids.server_id, uuids.volume_id) |
| 519 | |
| 520 | # Assert that list_volume_attachments is called until the attachment is |
| 521 | # removed. |
| 522 | mock_list_volume_attachments.assert_has_calls([ |
| 523 | mock.call(uuids.server_id), |
| 524 | mock.call(uuids.server_id)]) |
| 525 | |
| 526 | def test_wait_for_volume_attachment_remove_from_server_timeout(self): |
| 527 | volume_attached = { |
| 528 | "volumeAttachments": [{"volumeId": uuids.volume_id}]} |
| 529 | mock_list_volume_attachments = mock.Mock( |
| 530 | side_effect=[volume_attached, volume_attached]) |
Lee Yarwood | 1bd6059 | 2021-06-04 10:18:35 +0100 | [diff] [blame] | 531 | mock_get_console_output = mock.Mock( |
| 532 | return_value={'output': 'output'}) |
Balazs Gibizer | 2e515fe | 2020-12-07 15:10:11 +0100 | [diff] [blame] | 533 | mock_client = mock.Mock( |
| 534 | spec=servers_client.ServersClient, |
| 535 | build_interval=1, |
| 536 | build_timeout=1, |
Lee Yarwood | 1bd6059 | 2021-06-04 10:18:35 +0100 | [diff] [blame] | 537 | list_volume_attachments=mock_list_volume_attachments, |
| 538 | get_console_output=mock_get_console_output) |
Balazs Gibizer | 2e515fe | 2020-12-07 15:10:11 +0100 | [diff] [blame] | 539 | self.patch( |
| 540 | 'time.time', |
| 541 | side_effect=[0., 0.5, mock_client.build_timeout + 1.]) |
| 542 | self.patch('time.sleep') |
| 543 | |
| 544 | self.assertRaises( |
| 545 | lib_exc.TimeoutException, |
| 546 | waiters.wait_for_volume_attachment_remove_from_server, |
| 547 | mock_client, uuids.server_id, uuids.volume_id) |
| 548 | |
| 549 | # Assert that list_volume_attachments is called until the attachment is |
| 550 | # removed. |
| 551 | mock_list_volume_attachments.assert_has_calls([ |
| 552 | mock.call(uuids.server_id), |
| 553 | mock.call(uuids.server_id)]) |
Lee Yarwood | 1bd6059 | 2021-06-04 10:18:35 +0100 | [diff] [blame] | 554 | |
| 555 | # Assert that we fetch console output |
| 556 | mock_get_console_output.assert_called_once_with(uuids.server_id) |
| 557 | |
| 558 | def test_wait_for_volume_attachment_remove_from_server_not_found(self): |
| 559 | mock_list_volume_attachments = mock.Mock( |
| 560 | side_effect=lib_exc.NotFound) |
| 561 | mock_client = mock.Mock( |
| 562 | spec=servers_client.ServersClient, |
| 563 | list_volume_attachments=mock_list_volume_attachments) |
| 564 | |
| 565 | # Assert that nothing is raised when lib_exc_NotFound is raised |
| 566 | # by the client call to list_volume_attachments |
| 567 | waiters.wait_for_volume_attachment_remove_from_server( |
| 568 | mock_client, mock.sentinel.server_id, mock.sentinel.volume_id) |
| 569 | |
| 570 | # Assert that list_volume_attachments was actually called |
| 571 | mock_list_volume_attachments.assert_called_once_with( |
| 572 | mock.sentinel.server_id) |
Artom Lifshitz | 8a959ea | 2021-09-27 12:09:12 -0400 | [diff] [blame] | 573 | |
Lee Yarwood | 0b4bc3d | 2021-11-11 17:45:25 +0000 | [diff] [blame] | 574 | @mock.patch('os.system') |
| 575 | def test_wait_for_ping_host_alive(self, mock_ping): |
| 576 | mock_ping.return_value = 0 |
| 577 | # Assert that nothing is raised as the host is alive |
| 578 | waiters.wait_for_ping('127.0.0.1', 10, 1) |
| 579 | |
| 580 | @mock.patch('os.system') |
| 581 | def test_wait_for_ping_host_eventually_alive(self, mock_ping): |
| 582 | mock_ping.side_effect = [1, 1, 0] |
| 583 | # Assert that nothing is raised when the host is eventually alive |
| 584 | waiters.wait_for_ping('127.0.0.1', 10, 1) |
| 585 | |
| 586 | @mock.patch('os.system') |
| 587 | def test_wait_for_ping_timeout(self, mock_ping): |
| 588 | mock_ping.return_value = 1 |
| 589 | # Assert that TimeoutException is raised when the host is dead |
| 590 | self.assertRaises( |
| 591 | lib_exc.TimeoutException, |
| 592 | waiters.wait_for_ping, |
| 593 | '127.0.0.1', |
| 594 | .1, |
| 595 | .1 |
| 596 | ) |
| 597 | |
| 598 | def test_wait_for_ssh(self): |
| 599 | mock_ssh_client = mock.Mock() |
| 600 | mock_ssh_client.validate_authentication.return_value = True |
| 601 | # Assert that nothing is raised when validate_authentication returns |
| 602 | waiters.wait_for_ssh(mock_ssh_client, .1) |
| 603 | mock_ssh_client.validate_authentication.assert_called_once() |
| 604 | |
| 605 | def test_wait_for_ssh_eventually_up(self): |
| 606 | mock_ssh_client = mock.Mock() |
| 607 | timeout = lib_exc.SSHTimeout( |
| 608 | host='foo', |
| 609 | username='bar', |
| 610 | password='fizz' |
| 611 | ) |
| 612 | mock_ssh_client.validate_authentication.side_effect = [ |
| 613 | timeout, |
| 614 | timeout, |
| 615 | True |
| 616 | ] |
| 617 | # Assert that nothing is raised if validate_authentication passes |
| 618 | # before the timeout |
| 619 | waiters.wait_for_ssh(mock_ssh_client, 10) |
| 620 | |
| 621 | def test_wait_for_ssh_timeout(self): |
| 622 | mock_ssh_client = mock.Mock() |
| 623 | timeout = lib_exc.SSHTimeout( |
| 624 | host='foo', |
| 625 | username='bar', |
| 626 | password='fizz' |
| 627 | ) |
| 628 | mock_ssh_client.validate_authentication.side_effect = timeout |
| 629 | # Assert that TimeoutException is raised when validate_authentication |
| 630 | # doesn't pass in time. |
| 631 | self.assertRaises( |
| 632 | lib_exc.TimeoutException, |
| 633 | waiters.wait_for_ssh, |
| 634 | mock_ssh_client, |
| 635 | .1 |
| 636 | ) |
| 637 | |
Artom Lifshitz | 8a959ea | 2021-09-27 12:09:12 -0400 | [diff] [blame] | 638 | |
Eliad Cohen | bec2d4d | 2022-09-14 17:52:59 +0000 | [diff] [blame] | 639 | class TestPortCreationWaiter(base.TestCase): |
| 640 | def test_wait_for_port_status(self): |
| 641 | """Test that the waiter replies with the port before the timeout""" |
| 642 | |
| 643 | def client_response(self): |
| 644 | """Mock client response, replies with the final status after |
| 645 | 2 calls |
| 646 | """ |
| 647 | if mock_client.call_count >= 2: |
| 648 | return mock_port |
| 649 | else: |
| 650 | mock_client.call_count += 1 |
| 651 | return mock_port_build |
| 652 | |
| 653 | mock_port = {'port': {'id': '1234', 'status': "DOWN"}} |
| 654 | mock_port_build = {'port': {'id': '1234', 'status': "BUILD"}} |
| 655 | mock_client = mock.Mock( |
| 656 | spec=ports_client.PortsClient, |
| 657 | build_timeout=30, build_interval=1, |
| 658 | show_port=client_response) |
| 659 | fake_port_id = "1234" |
| 660 | fake_status = "DOWN" |
| 661 | self.assertEqual(mock_port, waiters.wait_for_port_status( |
| 662 | mock_client, fake_port_id, fake_status)) |
| 663 | |
| 664 | def test_wait_for_port_status_timeout(self): |
| 665 | """Negative test - checking that a timeout |
| 666 | presented by a small 'fake_timeout' and a static status of |
| 667 | 'BUILD' in the mock will raise a timeout exception |
| 668 | """ |
| 669 | mock_port = {'port': {'id': '1234', 'status': "BUILD"}} |
| 670 | mock_client = mock.Mock( |
| 671 | spec=ports_client.PortsClient, |
| 672 | build_timeout=2, build_interval=1, |
| 673 | show_port=lambda id: mock_port) |
| 674 | fake_port_id = "1234" |
| 675 | fake_status = "ACTIVE" |
| 676 | self.assertRaises(lib_exc.TimeoutException, |
| 677 | waiters.wait_for_port_status, mock_client, |
| 678 | fake_port_id, fake_status) |
| 679 | |
| 680 | |
Artom Lifshitz | 8a959ea | 2021-09-27 12:09:12 -0400 | [diff] [blame] | 681 | class TestServerFloatingIPWaiters(base.TestCase): |
| 682 | |
| 683 | def test_wait_for_server_floating_ip_associate_timeout(self): |
| 684 | mock_server = {'server': {'id': 'fake_uuid', 'addresses': {}}} |
| 685 | mock_client = mock.Mock( |
| 686 | spec=servers_client.ServersClient, |
| 687 | build_timeout=1, build_interval=1, |
| 688 | show_server=lambda id: mock_server) |
| 689 | |
| 690 | fake_server = {'id': 'fake-uuid'} |
| 691 | fake_fip = {'floating_ip_address': 'fake_address'} |
| 692 | self.assertRaises( |
| 693 | lib_exc.TimeoutException, |
| 694 | waiters.wait_for_server_floating_ip, mock_client, fake_server, |
| 695 | fake_fip) |
| 696 | |
| 697 | def test_wait_for_server_floating_ip_disassociate_timeout(self): |
| 698 | mock_addresses = {'shared': [{'OS-EXT-IPS:type': 'floating', |
| 699 | 'addr': 'fake_address'}]} |
| 700 | mock_server = {'server': {'id': 'fake_uuid', |
| 701 | 'addresses': mock_addresses}} |
| 702 | mock_client = mock.Mock( |
| 703 | spec=servers_client.ServersClient, |
| 704 | build_timeout=1, build_interval=1, |
| 705 | show_server=lambda id: mock_server) |
| 706 | |
| 707 | fake_server = {'id': 'fake-uuid'} |
| 708 | fake_fip = {'floating_ip_address': 'fake_address'} |
| 709 | self.assertRaises( |
| 710 | lib_exc.TimeoutException, |
| 711 | waiters.wait_for_server_floating_ip, mock_client, fake_server, |
| 712 | fake_fip, wait_for_disassociate=True) |