Coverage for manila/tests/scheduler/filters/test_json.py: 100%
114 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 2011 OpenStack Foundation.
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.
16"""
17Tests For JsonFilter.
18"""
20from oslo_serialization import jsonutils
22from manila.scheduler.filters import json
23from manila import test
24from manila.tests.scheduler import fakes
27class HostFiltersTestCase(test.TestCase):
28 """Test case for JsonFilter."""
30 def setUp(self):
31 super(HostFiltersTestCase, self).setUp()
32 self.json_query = jsonutils.dumps(
33 ['and', ['>=', '$free_ram_mb', 1024],
34 ['>=', '$free_disk_mb', 200 * 1024]])
35 self.filter = json.JsonFilter()
37 def test_json_filter_passes(self):
38 filter_properties = {'resource_type': {'memory_mb': 1024,
39 'root_gb': 200,
40 'ephemeral_gb': 0},
41 'scheduler_hints': {'query': self.json_query}}
42 capabilities = {'enabled': True}
43 host = fakes.FakeHostState('host1',
44 {'free_ram_mb': 1024,
45 'free_disk_mb': 200 * 1024,
46 'capabilities': capabilities})
47 self.assertTrue(self.filter.host_passes(host, filter_properties))
49 def test_json_filter_passes_with_no_query(self):
50 filter_properties = {'resource_type': {'memory_mb': 1024,
51 'root_gb': 200,
52 'ephemeral_gb': 0}}
53 capabilities = {'enabled': True}
54 host = fakes.FakeHostState('host1',
55 {'free_ram_mb': 0,
56 'free_disk_mb': 0,
57 'capabilities': capabilities})
58 self.assertTrue(self.filter.host_passes(host, filter_properties))
60 def test_json_filter_fails_on_memory(self):
61 filter_properties = {'resource_type': {'memory_mb': 1024,
62 'root_gb': 200,
63 'ephemeral_gb': 0},
64 'scheduler_hints': {'query': self.json_query}}
65 capabilities = {'enabled': True}
66 host = fakes.FakeHostState('host1',
67 {'free_ram_mb': 1023,
68 'free_disk_mb': 200 * 1024,
69 'capabilities': capabilities})
70 self.assertFalse(self.filter.host_passes(host, filter_properties))
72 def test_json_filter_fails_on_disk(self):
73 filter_properties = {'resource_type': {'memory_mb': 1024,
74 'root_gb': 200,
75 'ephemeral_gb': 0},
76 'scheduler_hints': {'query': self.json_query}}
77 capabilities = {'enabled': True}
78 host = fakes.FakeHostState('host1',
79 {'free_ram_mb': 1024,
80 'free_disk_mb': (200 * 1024) - 1,
81 'capabilities': capabilities})
82 self.assertFalse(self.filter.host_passes(host, filter_properties))
84 def test_json_filter_fails_on_caps_disabled(self):
85 json_query = jsonutils.dumps(
86 ['and', ['>=', '$free_ram_mb', 1024],
87 ['>=', '$free_disk_mb', 200 * 1024],
88 '$capabilities.enabled'])
89 filter_properties = {'resource_type': {'memory_mb': 1024,
90 'root_gb': 200,
91 'ephemeral_gb': 0},
92 'scheduler_hints': {'query': json_query}}
93 capabilities = {'enabled': False}
94 host = fakes.FakeHostState('host1',
95 {'free_ram_mb': 1024,
96 'free_disk_mb': 200 * 1024,
97 'capabilities': capabilities})
98 self.assertFalse(self.filter.host_passes(host, filter_properties))
100 def test_json_filter_fails_on_service_disabled(self):
101 json_query = jsonutils.dumps(
102 ['and', ['>=', '$free_ram_mb', 1024],
103 ['>=', '$free_disk_mb', 200 * 1024],
104 ['not', '$service.disabled']])
105 filter_properties = {'resource_type': {'memory_mb': 1024,
106 'local_gb': 200},
107 'scheduler_hints': {'query': json_query}}
108 capabilities = {'enabled': True}
109 host = fakes.FakeHostState('host1',
110 {'free_ram_mb': 1024,
111 'free_disk_mb': 200 * 1024,
112 'capabilities': capabilities})
113 self.assertFalse(self.filter.host_passes(host, filter_properties))
115 def test_json_filter_happy_day(self):
116 """Test json filter more thoroughly."""
117 raw = ['and',
118 '$capabilities.enabled',
119 ['=', '$capabilities.opt1', 'match'],
120 ['or',
121 ['and',
122 ['<', '$free_ram_mb', 30],
123 ['<', '$free_disk_mb', 300]],
124 ['and',
125 ['>', '$free_ram_mb', 30],
126 ['>', '$free_disk_mb', 300]]]]
127 filter_properties = {
128 'scheduler_hints': {
129 'query': jsonutils.dumps(raw),
130 },
131 }
133 # Passes
134 capabilities = {'enabled': True, 'opt1': 'match'}
135 service = {'disabled': False}
136 host = fakes.FakeHostState('host1',
137 {'free_ram_mb': 10,
138 'free_disk_mb': 200,
139 'capabilities': capabilities,
140 'service': service})
141 self.assertTrue(self.filter.host_passes(host, filter_properties))
143 # Passes
144 capabilities = {'enabled': True, 'opt1': 'match'}
145 service = {'disabled': False}
146 host = fakes.FakeHostState('host1',
147 {'free_ram_mb': 40,
148 'free_disk_mb': 400,
149 'capabilities': capabilities,
150 'service': service})
151 self.assertTrue(self.filter.host_passes(host, filter_properties))
153 # Fails due to capabilities being disabled
154 capabilities = {'enabled': False, 'opt1': 'match'}
155 service = {'disabled': False}
156 host = fakes.FakeHostState('host1',
157 {'free_ram_mb': 40,
158 'free_disk_mb': 400,
159 'capabilities': capabilities,
160 'service': service})
161 self.assertFalse(self.filter.host_passes(host, filter_properties))
163 # Fails due to being exact memory/disk we don't want
164 capabilities = {'enabled': True, 'opt1': 'match'}
165 service = {'disabled': False}
166 host = fakes.FakeHostState('host1',
167 {'free_ram_mb': 30,
168 'free_disk_mb': 300,
169 'capabilities': capabilities,
170 'service': service})
171 self.assertFalse(self.filter.host_passes(host, filter_properties))
173 # Fails due to memory lower but disk higher
174 capabilities = {'enabled': True, 'opt1': 'match'}
175 service = {'disabled': False}
176 host = fakes.FakeHostState('host1',
177 {'free_ram_mb': 20,
178 'free_disk_mb': 400,
179 'capabilities': capabilities,
180 'service': service})
181 self.assertFalse(self.filter.host_passes(host, filter_properties))
183 # Fails due to capabilities 'opt1' not equal
184 capabilities = {'enabled': True, 'opt1': 'no-match'}
185 service = {'enabled': True}
186 host = fakes.FakeHostState('host1',
187 {'free_ram_mb': 20,
188 'free_disk_mb': 400,
189 'capabilities': capabilities,
190 'service': service})
191 self.assertFalse(self.filter.host_passes(host, filter_properties))
193 def test_json_filter_basic_operators(self):
194 host = fakes.FakeHostState('host1',
195 {'capabilities': {'enabled': True}})
196 # (operator, arguments, expected_result)
197 ops_to_test = [
198 ['=', [1, 1], True],
199 ['=', [1, 2], False],
200 ['<', [1, 2], True],
201 ['<', [1, 1], False],
202 ['<', [2, 1], False],
203 ['>', [2, 1], True],
204 ['>', [2, 2], False],
205 ['>', [2, 3], False],
206 ['<=', [1, 2], True],
207 ['<=', [1, 1], True],
208 ['<=', [2, 1], False],
209 ['>=', [2, 1], True],
210 ['>=', [2, 2], True],
211 ['>=', [2, 3], False],
212 ['in', [1, 1], True],
213 ['in', [1, 1, 2, 3], True],
214 ['in', [4, 1, 2, 3], False],
215 ['not', [True], False],
216 ['not', [False], True],
217 ['or', [True, False], True],
218 ['or', [False, False], False],
219 ['and', [True, True], True],
220 ['and', [False, False], False],
221 ['and', [True, False], False],
222 # Nested ((True or False) and (2 > 1)) == Passes
223 ['and', [['or', True, False], ['>', 2, 1]], True]]
225 for (op, args, expected) in ops_to_test:
226 raw = [op] + args
227 filter_properties = {
228 'scheduler_hints': {
229 'query': jsonutils.dumps(raw),
230 },
231 }
232 self.assertEqual(expected,
233 self.filter.host_passes(host, filter_properties))
235 # This results in [False, True, False, True] and if any are True
236 # then it passes...
237 raw = ['not', True, False, True, False]
238 filter_properties = {
239 'scheduler_hints': {
240 'query': jsonutils.dumps(raw),
241 },
242 }
243 self.assertTrue(self.filter.host_passes(host, filter_properties))
245 # This results in [False, False, False] and if any are True
246 # then it passes...which this doesn't
247 raw = ['not', True, True, True]
248 filter_properties = {
249 'scheduler_hints': {
250 'query': jsonutils.dumps(raw),
251 },
252 }
253 self.assertFalse(self.filter.host_passes(host, filter_properties))
255 def test_json_filter_unknown_operator_raises(self):
256 raw = ['!=', 1, 2]
257 filter_properties = {
258 'scheduler_hints': {
259 'query': jsonutils.dumps(raw),
260 },
261 }
262 host = fakes.FakeHostState('host1',
263 {'capabilities': {'enabled': True}})
264 self.assertRaises(KeyError,
265 self.filter.host_passes, host, filter_properties)
267 def test_json_filter_type_errror_passes(self):
268 filter_properties = {
269 'scheduler_hints': None
270 }
271 host = fakes.FakeHostState('host1',
272 {'capabilities': {'enabled': True}})
273 self.assertTrue(self.filter.host_passes(host, filter_properties))
275 def test_json_filter_empty_filters_pass(self):
276 host = fakes.FakeHostState('host1',
277 {'capabilities': {'enabled': True}})
279 raw = []
280 filter_properties = {
281 'scheduler_hints': {
282 'query': jsonutils.dumps(raw),
283 },
284 }
285 self.assertTrue(self.filter.host_passes(host, filter_properties))
286 raw = {}
287 filter_properties = {
288 'scheduler_hints': {
289 'query': jsonutils.dumps(raw),
290 },
291 }
292 self.assertTrue(self.filter.host_passes(host, filter_properties))
294 def test_json_filter_invalid_num_arguments_fails(self):
295 host = fakes.FakeHostState('host1',
296 {'capabilities': {'enabled': True}})
298 raw = ['>', ['and', ['or', ['not', ['<', ['>=', ['<=', ['in', ]]]]]]]]
299 filter_properties = {
300 'scheduler_hints': {
301 'query': jsonutils.dumps(raw),
302 },
303 }
304 self.assertFalse(self.filter.host_passes(host, filter_properties))
306 raw = ['>', 1]
307 filter_properties = {
308 'scheduler_hints': {
309 'query': jsonutils.dumps(raw),
310 },
311 }
312 self.assertFalse(self.filter.host_passes(host, filter_properties))
314 def test_json_filter_unknown_variable_ignored(self):
315 host = fakes.FakeHostState('host1',
316 {'capabilities': {'enabled': True}})
318 raw = ['=', '$........', 1, 1]
319 filter_properties = {
320 'scheduler_hints': {
321 'query': jsonutils.dumps(raw),
322 },
323 }
324 self.assertTrue(self.filter.host_passes(host, filter_properties))
326 raw = ['=', '$foo', 2, 2]
327 filter_properties = {
328 'scheduler_hints': {
329 'query': jsonutils.dumps(raw),
330 },
331 }
332 self.assertTrue(self.filter.host_passes(host, filter_properties))