Coverage for manila/tests/share/test_migration.py: 100%
143 statements
« prev ^ index » next coverage.py v7.11.0, created at 2026-02-18 22:19 +0000
« prev ^ index » next coverage.py v7.11.0, created at 2026-02-18 22:19 +0000
1# Copyright 2015 Hitachi Data Systems inc.
2# All Rights Reserved.
3#
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
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
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
14# under the License.
16import time
17from unittest import mock
19import ddt
21from manila.common import constants
22from manila import context
23from manila import db
24from manila import exception
25from manila.share import access as access_helper
26from manila.share import api as share_api
27from manila.share import migration
28from manila.share import rpcapi as share_rpcapi
29from manila import test
30from manila.tests import db_utils
31from manila import utils
34@ddt.ddt
35class ShareMigrationHelperTestCase(test.TestCase):
36 """Tests ShareMigrationHelper."""
38 def setUp(self):
39 super(ShareMigrationHelperTestCase, self).setUp()
40 self.share = db_utils.create_share()
41 self.share_instance = db_utils.create_share_instance(
42 share_id=self.share['id'],
43 share_network_id='fake_network_id')
44 self.access_helper = access_helper.ShareInstanceAccess(db, None)
45 self.context = context.get_admin_context()
46 self.helper = migration.ShareMigrationHelper(
47 self.context, db, self.access_helper)
49 def test_delete_instance_and_wait(self):
51 # mocks
52 self.mock_object(share_api.API, 'delete_instance')
53 self.mock_object(db, 'share_instance_get',
54 mock.Mock(side_effect=[self.share_instance,
55 exception.NotFound()]))
56 self.mock_object(time, 'sleep')
58 # run
59 self.helper.delete_instance_and_wait(self.share_instance)
61 # asserts
62 share_api.API.delete_instance.assert_called_once_with(
63 self.context, self.share_instance, True)
65 db.share_instance_get.assert_has_calls([
66 mock.call(self.context, self.share_instance['id']),
67 mock.call(self.context, self.share_instance['id'])])
69 time.sleep.assert_called_once_with(1.414)
71 def test_delete_instance_and_wait_timeout(self):
73 # mocks
74 self.mock_object(share_api.API, 'delete_instance')
76 self.mock_object(db, 'share_instance_get',
77 mock.Mock(side_effect=[self.share_instance, None]))
78 self.mock_object(time, 'sleep')
80 now = time.time()
81 timeout = now + 310
83 self.mock_object(time, 'time',
84 mock.Mock(side_effect=[now, timeout]))
86 # run
87 self.assertRaises(exception.ShareMigrationFailed,
88 self.helper.delete_instance_and_wait,
89 self.share_instance)
91 # asserts
92 share_api.API.delete_instance.assert_called_once_with(
93 self.context, self.share_instance, True)
95 db.share_instance_get.assert_called_once_with(
96 self.context, self.share_instance['id'])
98 time.time.assert_has_calls([mock.call(), mock.call()])
100 def test_delete_instance_and_wait_not_found(self):
102 # mocks
103 self.mock_object(share_api.API, 'delete_instance')
104 self.mock_object(db, 'share_instance_get',
105 mock.Mock(side_effect=exception.NotFound))
107 # run
108 self.helper.delete_instance_and_wait(self.share_instance)
110 # asserts
111 share_api.API.delete_instance.assert_called_once_with(
112 self.context, self.share_instance, True)
114 db.share_instance_get.assert_called_once_with(
115 self.context, self.share_instance['id'])
117 def test_create_instance_and_wait(self):
119 host = 'fake_host'
121 share_instance_creating = db_utils.create_share_instance(
122 share_id=self.share['id'], status=constants.STATUS_CREATING,
123 share_network_id='fake_network_id')
124 share_instance_available = db_utils.create_share_instance(
125 share_id=self.share['id'], status=constants.STATUS_AVAILABLE,
126 share_network_id='fake_network_id')
128 # mocks
129 self.mock_object(share_api.API, 'create_instance',
130 mock.Mock(return_value=share_instance_creating))
131 self.mock_object(db, 'share_instance_get',
132 mock.Mock(side_effect=[share_instance_creating,
133 share_instance_available]))
134 self.mock_object(time, 'sleep')
136 # run
137 self.helper.create_instance_and_wait(
138 self.share, host, 'fake_net_id', 'fake_az_id', 'fake_type_id')
140 # asserts
141 share_api.API.create_instance.assert_called_once_with(
142 self.context, self.share, 'fake_net_id', 'fake_host', 'fake_az_id',
143 share_type_id='fake_type_id')
145 db.share_instance_get.assert_has_calls([
146 mock.call(self.context, share_instance_creating['id'],
147 with_share_data=True),
148 mock.call(self.context, share_instance_creating['id'],
149 with_share_data=True)])
151 time.sleep.assert_called_once_with(1.414)
153 def test_create_instance_and_wait_status_error(self):
155 host = 'fake_host'
157 share_instance_error = db_utils.create_share_instance(
158 share_id=self.share['id'], status=constants.STATUS_ERROR,
159 share_network_id='fake_network_id')
161 # mocks
162 self.mock_object(share_api.API, 'create_instance',
163 mock.Mock(return_value=share_instance_error))
164 self.mock_object(self.helper, 'cleanup_new_instance')
165 self.mock_object(db, 'share_instance_get',
166 mock.Mock(return_value=share_instance_error))
168 # run
169 self.assertRaises(
170 exception.ShareMigrationFailed,
171 self.helper.create_instance_and_wait, self.share,
172 host, 'fake_net_id', 'fake_az_id', 'fake_type_id')
174 # asserts
175 share_api.API.create_instance.assert_called_once_with(
176 self.context, self.share, 'fake_net_id', 'fake_host', 'fake_az_id',
177 share_type_id='fake_type_id')
179 db.share_instance_get.assert_called_once_with(
180 self.context, share_instance_error['id'], with_share_data=True)
182 self.helper.cleanup_new_instance.assert_called_once_with(
183 share_instance_error)
185 def test_create_instance_and_wait_timeout(self):
187 host = 'fake_host'
189 share_instance_creating = db_utils.create_share_instance(
190 share_id=self.share['id'], status=constants.STATUS_CREATING,
191 share_network_id='fake_network_id')
193 # mocks
194 self.mock_object(share_api.API, 'create_instance',
195 mock.Mock(return_value=share_instance_creating))
197 self.mock_object(self.helper, 'cleanup_new_instance')
199 self.mock_object(db, 'share_instance_get',
200 mock.Mock(return_value=share_instance_creating))
201 self.mock_object(time, 'sleep')
203 now = time.time()
204 timeout = now + 310
206 self.mock_object(time, 'time', mock.Mock(side_effect=[now, timeout]))
208 # run
209 self.assertRaises(
210 exception.ShareMigrationFailed,
211 self.helper.create_instance_and_wait, self.share,
212 host, 'fake_net_id', 'fake_az_id', 'fake_type_id')
214 # asserts
215 share_api.API.create_instance.assert_called_once_with(
216 self.context, self.share, 'fake_net_id', 'fake_host', 'fake_az_id',
217 share_type_id='fake_type_id')
219 db.share_instance_get.assert_called_once_with(
220 self.context, share_instance_creating['id'], with_share_data=True)
222 time.time.assert_has_calls([mock.call(), mock.call()])
224 self.helper.cleanup_new_instance.assert_called_once_with(
225 share_instance_creating)
227 @ddt.data(constants.STATUS_ACTIVE, constants.STATUS_ERROR,
228 constants.STATUS_CREATING)
229 def test_wait_for_share_server(self, status):
231 server = db_utils.create_share_server(status=status)
233 # mocks
234 self.mock_object(db, 'share_server_get',
235 mock.Mock(return_value=server))
237 # run
238 if status == constants.STATUS_ACTIVE:
239 result = self.helper.wait_for_share_server('fake_server_id')
240 self.assertEqual(server, result)
241 elif status == constants.STATUS_ERROR:
242 self.assertRaises(
243 exception.ShareServerNotCreated,
244 self.helper.wait_for_share_server, 'fake_server_id')
245 else:
246 self.mock_object(time, 'sleep')
247 self.assertRaises(
248 exception.ShareServerNotReady,
249 self.helper.wait_for_share_server, 'fake_server_id')
251 # asserts
252 db.share_server_get.assert_called_with(self.context, 'fake_server_id')
254 @ddt.data(None, 'fakehost@fakebackend')
255 def test_revert_access_rules(self, dest_host):
257 share_instance = db_utils.create_share_instance(
258 share_id=self.share['id'], status=constants.STATUS_AVAILABLE)
259 share_instance_ids = [instance['id'] for instance in [share_instance]]
261 access = db_utils.create_access(share_id=self.share['id'],
262 access_to='fake_ip',
263 access_level='rw')
265 server = db_utils.create_share_server(share_id=self.share['id'])
267 # mocks
268 self.mock_object(self.access_helper, 'update_access_rules')
269 get_and_update_call = self.mock_object(
270 self.access_helper, 'get_and_update_share_instance_access_rules',
271 mock.Mock(return_value=[access]))
272 mock_update_access_for_instances = self.mock_object(
273 share_rpcapi.ShareAPI, 'update_access_for_instances')
275 # run
276 self.helper.revert_access_rules([share_instance], server,
277 dest_host=dest_host)
279 # asserts
280 get_and_update_call.assert_called_once_with(
281 self.context, share_instance_id=share_instance['id'],
282 updates={'state': constants.ACCESS_STATE_QUEUED_TO_APPLY})
283 if dest_host:
284 mock_update_access_for_instances.assert_called_once_with(
285 self.context, dest_host, share_instance_ids, server)
286 else:
287 self.access_helper.update_access_rules.assert_called_once_with(
288 self.context, share_instance['id'], share_server=server)
290 @ddt.data(True, False)
291 def test_apply_new_access_rules_there_are_rules(self, prior_rules):
293 new_share_instance = db_utils.create_share_instance(
294 share_id=self.share['id'], status=constants.STATUS_AVAILABLE,
295 access_rules_status='active')
296 rules = None
297 if prior_rules:
298 rules = [
299 db_utils.create_access(
300 share_id=self.share['id'], access_to='fake_ip')
301 ]
303 # mocks
304 self.mock_object(db, 'share_instance_access_copy', mock.Mock(
305 return_value=rules))
306 self.mock_object(share_api.API, 'allow_access_to_instance')
307 self.mock_object(utils, 'wait_for_access_update')
309 # run
310 self.helper.apply_new_access_rules(new_share_instance,
311 self.share['id'])
313 # asserts
314 db.share_instance_access_copy.assert_called_once_with(
315 self.context, self.share['id'], new_share_instance['id'])
316 if prior_rules:
317 share_api.API.allow_access_to_instance.assert_called_with(
318 self.context, new_share_instance)
319 utils.wait_for_access_update.assert_called_with(
320 self.context, db, new_share_instance,
321 self.helper.migration_wait_access_rules_timeout)
322 else:
323 self.assertFalse(share_api.API.allow_access_to_instance.called)
324 self.assertFalse(utils.wait_for_access_update.called)
326 @ddt.data(None, Exception('fake'))
327 def test_cleanup_new_instance(self, exc):
329 # mocks
330 self.mock_object(self.helper, 'delete_instance_and_wait',
331 mock.Mock(side_effect=exc))
333 self.mock_object(migration.LOG, 'warning')
335 # run
336 self.helper.cleanup_new_instance(self.share_instance)
338 # asserts
339 self.helper.delete_instance_and_wait.assert_called_once_with(
340 self.share_instance)
342 if exc:
343 self.assertEqual(1, migration.LOG.warning.call_count)
345 @ddt.data(None, Exception('fake'))
346 def test_cleanup_access_rules(self, exc):
348 # mocks
349 server = db_utils.create_share_server()
350 self.mock_object(self.helper, 'revert_access_rules',
351 mock.Mock(side_effect=exc))
353 self.mock_object(migration.LOG, 'warning')
355 # run
356 self.helper.cleanup_access_rules(self.share_instance, server)
358 # asserts
359 self.helper.revert_access_rules.assert_called_once_with(
360 self.share_instance, server, None)
362 if exc:
363 self.assertEqual(1, migration.LOG.warning.call_count)