Coverage for manila/tests/api/v2/test_scheduler_stats.py: 100%
103 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 (c) 2015 Clinton Knight. All rights reserved.
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.
15from unittest import mock
17import ddt
18from oslo_utils import uuidutils
19from webob import exc
21from manila.api.openstack import api_version_request as api_version
22from manila.api.v2 import scheduler_stats
23from manila import context
24from manila import exception
25from manila import policy
26from manila.scheduler import rpcapi
27from manila.share import share_types
28from manila import test
29from manila.tests.api import fakes
32FAKE_POOLS = [
33 {
34 'name': 'host1@backend1#pool1',
35 'host': 'host1',
36 'backend': 'backend1',
37 'pool': 'pool1',
38 'capabilities': {
39 'updated': None,
40 'total_capacity': 1024,
41 'free_capacity': 100,
42 'share_backend_name': 'pool1',
43 'reserved_percentage': 0,
44 'driver_version': '1.0.0',
45 'storage_protocol': 'iSCSI',
46 'qos': 'False',
47 },
48 },
49 {
50 'name': 'host1@backend1#pool2',
51 'host': 'host1',
52 'backend': 'backend1',
53 'pool': 'pool2',
54 'capabilities': {
55 'updated': None,
56 'total_capacity': 512,
57 'free_capacity': 200,
58 'share_backend_name': 'pool2',
59 'reserved_percentage': 0,
60 'driver_version': '1.0.1',
61 'storage_protocol': 'iSER',
62 'qos': 'True',
63 },
64 },
65]
68@ddt.ddt
69class SchedulerStatsControllerTestCase(test.TestCase):
70 def setUp(self):
71 super(SchedulerStatsControllerTestCase, self).setUp()
72 self.flags(host='fake')
73 self.controller = scheduler_stats.SchedulerStatsController()
74 self.resource_name = self.controller.resource_name
75 self.ctxt = context.RequestContext('admin', 'fake', True)
76 self.mock_policy_check = self.mock_object(
77 policy, 'check_policy', mock.Mock(return_value=True))
79 def test_pools_index(self):
80 mock_get_pools = self.mock_object(rpcapi.SchedulerAPI,
81 'get_pools',
82 mock.Mock(return_value=FAKE_POOLS))
83 req = fakes.HTTPRequest.blank('/v2/scheduler_stats/pools')
84 req.environ['manila.context'] = self.ctxt
86 result = self.controller.pools_index(req)
88 expected = {
89 'pools': [
90 {
91 'name': 'host1@backend1#pool1',
92 'host': 'host1',
93 'backend': 'backend1',
94 'pool': 'pool1',
95 },
96 {
97 'name': 'host1@backend1#pool2',
98 'host': 'host1',
99 'backend': 'backend1',
100 'pool': 'pool2',
101 }
102 ]
103 }
105 self.assertDictEqual(result, expected)
106 mock_get_pools.assert_called_once_with(self.ctxt, filters={},
107 cached=True)
108 self.mock_policy_check.assert_called_once_with(
109 self.ctxt, self.resource_name, 'index')
111 @ddt.data(('index', False), ('detail', True))
112 @ddt.unpack
113 def test_pools_with_share_type_disabled(self, action, detail):
114 mock_get_pools = self.mock_object(rpcapi.SchedulerAPI,
115 'get_pools',
116 mock.Mock(return_value=FAKE_POOLS))
118 req = fakes.HTTPRequest.blank(
119 f'/v2/scheduler-stats/pools/{action}'
120 f'?backend=back1&host=host1&pool=pool1'
121 )
122 req.environ['manila.context'] = self.ctxt
124 expected_filters = {
125 'host': 'host1',
126 'pool': 'pool1',
127 'backend': 'back1',
128 }
130 if detail:
131 expected_result = {"pools": FAKE_POOLS}
132 else:
133 expected_result = {
134 'pools': [
135 {
136 'name': 'host1@backend1#pool1',
137 'host': 'host1',
138 'backend': 'backend1',
139 'pool': 'pool1',
140 },
141 {
142 'name': 'host1@backend1#pool2',
143 'host': 'host1',
144 'backend': 'backend1',
145 'pool': 'pool2',
146 }
147 ]
148 }
150 result = self.controller._pools(req, action, False)
152 self.assertDictEqual(result, expected_result)
153 mock_get_pools.assert_called_once_with(self.ctxt,
154 filters=expected_filters,
155 cached=True)
157 @ddt.data(('index', False, True),
158 ('index', False, False),
159 ('detail', True, True),
160 ('detail', True, False))
161 @ddt.unpack
162 def test_pools_with_share_type_enable(self, action, detail, uuid):
163 mock_get_pools = self.mock_object(rpcapi.SchedulerAPI,
164 'get_pools',
165 mock.Mock(return_value=FAKE_POOLS))
167 if uuid:
168 share_type = uuidutils.generate_uuid()
169 else:
170 share_type = 'test_type'
172 self.mock_object(
173 share_types, 'get_share_type_by_name_or_id',
174 mock.Mock(return_value={'extra_specs':
175 {'snapshot_support': True}}))
177 req = fakes.HTTPRequest.blank(
178 f'/v2/scheduler-stats/pools/{action}'
179 f'?backend=back1&host=host1&pool=pool1&share_type={share_type}'
180 )
181 req.environ['manila.context'] = self.ctxt
183 expected_filters = {
184 'host': 'host1',
185 'pool': 'pool1',
186 'backend': 'back1',
187 'capabilities': {
188 'snapshot_support': True
189 }
190 }
192 if detail:
193 expected_result = {"pools": FAKE_POOLS}
194 else:
195 expected_result = {
196 'pools': [
197 {
198 'name': 'host1@backend1#pool1',
199 'host': 'host1',
200 'backend': 'backend1',
201 'pool': 'pool1',
202 },
203 {
204 'name': 'host1@backend1#pool2',
205 'host': 'host1',
206 'backend': 'backend1',
207 'pool': 'pool2',
208 }
209 ]
210 }
212 result = self.controller._pools(req, action, True)
214 self.assertDictEqual(result, expected_result)
215 mock_get_pools.assert_called_once_with(self.ctxt,
216 filters=expected_filters,
217 cached=True)
219 @ddt.data('index', 'detail')
220 def test_pools_with_share_type_not_found(self, action):
222 req = fakes.HTTPRequest.blank(
223 f'/v2/scheduler-stats/pools/{action}'
224 f'?backend=.%2A&host=host1&pool=pool%2A&share_type=fake_name_1'
225 )
227 self.assertRaises(exc.HTTPBadRequest,
228 self.controller._pools,
229 req, action, True)
231 @ddt.data("1.0", "2.22", "2.23")
232 def test_pools_index_with_filters(self, microversion):
233 mock_get_pools = self.mock_object(rpcapi.SchedulerAPI,
234 'get_pools',
235 mock.Mock(return_value=FAKE_POOLS))
236 self.mock_object(
237 share_types, 'get_share_type_by_name',
238 mock.Mock(return_value={'extra_specs':
239 {'snapshot_support': True}}))
241 req = fakes.HTTPRequest.blank(
242 '/v2/scheduler-stats/pools/detail'
243 '?backend=.%2A&host=host1&pool=pool%2A&share_type=test_type',
244 version=microversion
245 )
246 req.environ['manila.context'] = self.ctxt
248 result = self.controller.pools_index(req)
250 expected = {
251 'pools': [
252 {
253 'name': 'host1@backend1#pool1',
254 'host': 'host1',
255 'backend': 'backend1',
256 'pool': 'pool1',
257 },
258 {
259 'name': 'host1@backend1#pool2',
260 'host': 'host1',
261 'backend': 'backend1',
262 'pool': 'pool2',
263 }
264 ]
265 }
266 expected_filters = {
267 'host': 'host1',
268 'pool': 'pool*',
269 'backend': '.*',
270 'share_type': 'test_type',
271 }
272 if (api_version.APIVersionRequest(microversion) >=
273 api_version.APIVersionRequest('2.23')):
274 expected_filters.update(
275 {'capabilities': {'snapshot_support': True}})
276 expected_filters.pop('share_type', None)
278 self.assertDictEqual(result, expected)
279 mock_get_pools.assert_called_once_with(self.ctxt,
280 filters=expected_filters,
281 cached=True)
282 self.mock_policy_check.assert_called_once_with(
283 self.ctxt, self.resource_name, 'index')
285 def test_get_pools_detail(self):
286 mock_get_pools = self.mock_object(rpcapi.SchedulerAPI,
287 'get_pools',
288 mock.Mock(return_value=FAKE_POOLS))
289 req = fakes.HTTPRequest.blank('/v2/scheduler_stats/pools/detail')
290 req.environ['manila.context'] = self.ctxt
292 result = self.controller.pools_detail(req)
294 expected = {
295 'pools': [
296 {
297 'name': 'host1@backend1#pool1',
298 'host': 'host1',
299 'backend': 'backend1',
300 'pool': 'pool1',
301 'capabilities': {
302 'updated': None,
303 'total_capacity': 1024,
304 'free_capacity': 100,
305 'share_backend_name': 'pool1',
306 'reserved_percentage': 0,
307 'driver_version': '1.0.0',
308 'storage_protocol': 'iSCSI',
309 'qos': 'False',
310 },
311 },
312 {
313 'name': 'host1@backend1#pool2',
314 'host': 'host1',
315 'backend': 'backend1',
316 'pool': 'pool2',
317 'capabilities': {
318 'updated': None,
319 'total_capacity': 512,
320 'free_capacity': 200,
321 'share_backend_name': 'pool2',
322 'reserved_percentage': 0,
323 'driver_version': '1.0.1',
324 'storage_protocol': 'iSER',
325 'qos': 'True',
326 },
327 },
328 ],
329 }
331 self.assertDictEqual(expected, result)
332 mock_get_pools.assert_called_once_with(self.ctxt, filters={},
333 cached=True)
334 self.mock_policy_check.assert_called_once_with(
335 self.ctxt, self.resource_name, 'detail')
337 @ddt.data('index', 'detail')
338 def test_pools_forbidden(self, subresource):
339 mock_get_pools = self.mock_object(
340 rpcapi.SchedulerAPI, 'get_pools',
341 mock.Mock(side_effect=exception.AdminRequired(
342 "some traceback here")))
343 path = '/v2/scheduler_stats/pools'
344 path = path + ('/%s' % subresource if subresource == 'detail' else '')
345 req = fakes.HTTPRequest.blank(path)
346 req.environ['manila.context'] = self.ctxt
348 self.assertRaises(exc.HTTPForbidden,
349 getattr(self.controller, 'pools_%s' % subresource),
350 req)
351 mock_get_pools.assert_called_once_with(self.ctxt,
352 filters={},
353 cached=True)
356class SchedulerStatsTestCase(test.TestCase):
358 def test_create_resource(self):
359 result = scheduler_stats.create_resource()
360 self.assertIsInstance(result.controller,
361 scheduler_stats.SchedulerStatsController)