From 7d69c21189cb75618a64576364e89dd5cd84650c Mon Sep 17 00:00:00 2001 From: Chris Behrens Date: Fri, 9 Nov 2012 01:57:42 +0000 Subject: [PATCH] Refactor scheduling filters This changes the scheduling filters to use the code in nova/loadables.py to locate filtering classes. This also creates some base functionality in nova/filters.py to be used by both the host scheduler and the cells scheduler. The scheduler_available_filters default has changed to 'nova.scheduler.filters.all_filters' which is better named compared to the old setting of 'standard_filters'. The old method is still supported for those that have put it explicitly in their configs, but it's marked as deprecated. DocImpact Change-Id: I84fdeafdba0275ab4b25f8857563bd7b1494bb69 --- nova/tests/test_filters.py | 125 +++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 nova/tests/test_filters.py diff --git a/nova/tests/test_filters.py b/nova/tests/test_filters.py new file mode 100644 index 00000000..546b1318 --- /dev/null +++ b/nova/tests/test_filters.py @@ -0,0 +1,125 @@ +# Copyright 2012 OpenStack LLC. # All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +""" +Tests For Scheduler Host Filters. +""" + +import inspect +import sys + +from nova import filters +from nova import loadables +from nova import test + + +class Filter1(filters.BaseFilter): + """Test Filter class #1.""" + pass + + +class Filter2(filters.BaseFilter): + """Test Filter class #2.""" + pass + + +class FiltersTestCase(test.TestCase): + def test_filter_all(self): + filter_obj_list = ['obj1', 'obj2', 'obj3'] + filter_properties = 'fake_filter_properties' + base_filter = filters.BaseFilter() + + self.mox.StubOutWithMock(base_filter, '_filter_one') + + base_filter._filter_one('obj1', filter_properties).AndReturn(True) + base_filter._filter_one('obj2', filter_properties).AndReturn(False) + base_filter._filter_one('obj3', filter_properties).AndReturn(True) + + self.mox.ReplayAll() + + result = base_filter.filter_all(filter_obj_list, filter_properties) + self.assertTrue(inspect.isgenerator(result)) + self.assertEqual(list(result), ['obj1', 'obj3']) + + def test_filter_all_recursive_yields(self): + """Test filter_all() allows generators from previous filter_all()s.""" + # filter_all() yields results. We want to make sure that we can + # call filter_all() with generators returned from previous calls + # to filter_all(). + filter_obj_list = ['obj1', 'obj2', 'obj3'] + filter_properties = 'fake_filter_properties' + base_filter = filters.BaseFilter() + + self.mox.StubOutWithMock(base_filter, '_filter_one') + + total_iterations = 200 + + # The order that _filter_one is going to get called gets + # confusing because we will be recursively yielding things.. + # We are going to simulate the first call to filter_all() + # returning False for 'obj2'. So, 'obj1' will get yielded + # 'total_iterations' number of times before the first filter_all() + # call gets to processing 'obj2'. We then return 'False' for it. + # After that, 'obj3' gets yielded 'total_iterations' number of + # times. + for x in xrange(total_iterations): + base_filter._filter_one('obj1', filter_properties).AndReturn(True) + base_filter._filter_one('obj2', filter_properties).AndReturn(False) + for x in xrange(total_iterations): + base_filter._filter_one('obj3', filter_properties).AndReturn(True) + self.mox.ReplayAll() + + objs = iter(filter_obj_list) + for x in xrange(total_iterations): + # Pass in generators returned from previous calls. + objs = base_filter.filter_all(objs, filter_properties) + self.assertTrue(inspect.isgenerator(objs)) + self.assertEqual(list(objs), ['obj1', 'obj3']) + + def test_get_filtered_objects(self): + filter_objs_initial = ['initial', 'filter1', 'objects1'] + filter_objs_second = ['second', 'filter2', 'objects2'] + filter_objs_last = ['last', 'filter3', 'objects3'] + filter_properties = 'fake_filter_properties' + + def _fake_base_loader_init(*args, **kwargs): + pass + + self.stubs.Set(loadables.BaseLoader, '__init__', + _fake_base_loader_init) + + filt1_mock = self.mox.CreateMock(Filter1) + filt2_mock = self.mox.CreateMock(Filter2) + + self.mox.StubOutWithMock(sys.modules[__name__], 'Filter1', + use_mock_anything=True) + self.mox.StubOutWithMock(filt1_mock, 'filter_all') + self.mox.StubOutWithMock(sys.modules[__name__], 'Filter2', + use_mock_anything=True) + self.mox.StubOutWithMock(filt2_mock, 'filter_all') + + Filter1().AndReturn(filt1_mock) + filt1_mock.filter_all(filter_objs_initial, + filter_properties).AndReturn(filter_objs_second) + Filter2().AndReturn(filt2_mock) + filt2_mock.filter_all(filter_objs_second, + filter_properties).AndReturn(filter_objs_last) + + self.mox.ReplayAll() + + filter_handler = filters.BaseFilterHandler(filters.BaseFilter) + filter_classes = [Filter1, Filter2] + result = filter_handler.get_filtered_objects(filter_classes, + filter_objs_initial, + filter_properties) + self.assertEqual(result, filter_objs_last)