Add engine scheduler unit test
Change-Id: Ib210fff443b34e223141bc7490ddcd4e2e49f48f
This commit is contained in:
parent
99424b71db
commit
c7b473e81f
|
@ -13,6 +13,7 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import mock
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
|
@ -95,3 +96,25 @@ class TestCase(base.BaseTestCase):
|
||||||
return os.path.join(root, project_file)
|
return os.path.join(root, project_file)
|
||||||
else:
|
else:
|
||||||
return root
|
return root
|
||||||
|
|
||||||
|
def mock_object(self, obj, attr_name, *args, **kwargs):
|
||||||
|
"""Use python mock to mock an object attribute
|
||||||
|
|
||||||
|
Mocks the specified objects attribute with the given value.
|
||||||
|
Automatically performs 'addCleanup' for the mock.
|
||||||
|
|
||||||
|
"""
|
||||||
|
patcher = mock.patch.object(obj, attr_name, *args, **kwargs)
|
||||||
|
result = patcher.start()
|
||||||
|
self.addCleanup(patcher.stop)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def override_config(self, name, override, group=None):
|
||||||
|
"""Cleanly override CONF variables."""
|
||||||
|
CONF.set_override(name, override, group)
|
||||||
|
self.addCleanup(CONF.clear_override, name, group)
|
||||||
|
|
||||||
|
def flags(self, **kw):
|
||||||
|
"""Override CONF variables for a test."""
|
||||||
|
for k, v in kw.items():
|
||||||
|
self.override_config(k, v)
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
# Copyright (c) 2016 OpenStack Foundation
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
"""
|
||||||
|
Fakes For Scheduler tests.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from oslo_versionedobjects import base as object_base
|
||||||
|
|
||||||
|
|
||||||
|
from nimble.engine.scheduler import filter_scheduler
|
||||||
|
from nimble.engine.scheduler import node_manager
|
||||||
|
from nimble.objects import base
|
||||||
|
from nimble.objects import fields as object_fields
|
||||||
|
|
||||||
|
|
||||||
|
class FakeFilterScheduler(filter_scheduler.FilterScheduler):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(FakeFilterScheduler, self).__init__(*args, **kwargs)
|
||||||
|
self.node_manager = node_manager.NodeManager()
|
||||||
|
|
||||||
|
|
||||||
|
@base.NimbleObjectRegistry.register
|
||||||
|
class FakeNode(base.NimbleObject, object_base.VersionedObjectDictCompat):
|
||||||
|
fields = {
|
||||||
|
'id': object_fields.IntegerField(),
|
||||||
|
'uuid': object_fields.UUIDField(nullable=True),
|
||||||
|
'properties': object_fields.FlexibleDictField(nullable=True),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fakenode1 = FakeNode(id=1, uuid='1a617131-cdbc-45dc-afff-f21f17ae054e',
|
||||||
|
properties={'capabilities': '',
|
||||||
|
'availability_zone': 'az1',
|
||||||
|
'instance_type': 'type1'})
|
||||||
|
fakenode2 = FakeNode(id=2, uuid='2a617131-cdbc-45dc-afff-f21f17ae054e',
|
||||||
|
properties={'capabilities': '',
|
||||||
|
'availability_zone': 'az2',
|
||||||
|
'instance_type': 'type2'})
|
||||||
|
fakenode3 = FakeNode(id=3, uuid='3a617131-cdbc-45dc-afff-f21f17ae054e',
|
||||||
|
properties={'capabilities': '',
|
||||||
|
'availability_zone': 'az3',
|
||||||
|
'instance_type': 'type3'})
|
||||||
|
|
||||||
|
|
||||||
|
class FakeNodeState(node_manager.NodeState):
|
||||||
|
def __init__(self, node, attribute_dict):
|
||||||
|
super(FakeNodeState, self).__init__(node)
|
||||||
|
for (key, val) in attribute_dict.items():
|
||||||
|
setattr(self, key, val)
|
|
@ -0,0 +1,174 @@
|
||||||
|
# Copyright (c) 2016 OpenStack Foundation.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
import mock
|
||||||
|
|
||||||
|
from nimble.engine.scheduler import base_filter
|
||||||
|
from nimble.tests import base as test
|
||||||
|
|
||||||
|
|
||||||
|
class TestBaseFilter(test.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestBaseFilter, self).setUp()
|
||||||
|
self.filter = base_filter.BaseFilter()
|
||||||
|
|
||||||
|
def test_filter_one_is_called(self):
|
||||||
|
filters = [1, 2, 3, 4]
|
||||||
|
filter_properties = {'x': 'y'}
|
||||||
|
|
||||||
|
self.filter._filter_one = mock.Mock()
|
||||||
|
self.filter._filter_one.side_effect = [False, True, True, False]
|
||||||
|
calls = [mock.call(i, filter_properties) for i in filters]
|
||||||
|
|
||||||
|
result = list(self.filter.filter_all(filters, filter_properties))
|
||||||
|
self.assertEqual([2, 3], result)
|
||||||
|
self.filter._filter_one.assert_has_calls(calls)
|
||||||
|
|
||||||
|
|
||||||
|
class FakeExtension(object):
|
||||||
|
|
||||||
|
def __init__(self, plugin):
|
||||||
|
self.plugin = plugin
|
||||||
|
|
||||||
|
|
||||||
|
class BaseFakeFilter(base_filter.BaseFilter):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class FakeFilter1(BaseFakeFilter):
|
||||||
|
"""Derives from BaseFakeFilter and has a fake entry point defined.
|
||||||
|
|
||||||
|
Entry point is returned by fake ExtensionManager.
|
||||||
|
Should be included in the output of all_classes.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class FakeFilter2(BaseFakeFilter):
|
||||||
|
"""Derives from BaseFakeFilter but has no entry point.
|
||||||
|
|
||||||
|
Should be not included in all_classes.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class FakeFilter3(base_filter.BaseFilter):
|
||||||
|
"""Does not derive from BaseFakeFilter.
|
||||||
|
|
||||||
|
Should not be included.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class FakeFilter4(BaseFakeFilter):
|
||||||
|
"""Derives from BaseFakeFilter and has an entry point.
|
||||||
|
|
||||||
|
Should be included.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class FakeFilter5(BaseFakeFilter):
|
||||||
|
"""Derives from BaseFakeFilter but has no entry point.
|
||||||
|
|
||||||
|
Should not be included.
|
||||||
|
"""
|
||||||
|
run_filter_once_per_request = True
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class FilterA(base_filter.BaseFilter):
|
||||||
|
def filter_all(self, list_objs, filter_properties):
|
||||||
|
# return all but the first object
|
||||||
|
return list_objs[1:]
|
||||||
|
|
||||||
|
|
||||||
|
class FilterB(base_filter.BaseFilter):
|
||||||
|
def filter_all(self, list_objs, filter_properties):
|
||||||
|
# return an empty list
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class FakeExtensionManager(list):
|
||||||
|
|
||||||
|
def __init__(self, namespace):
|
||||||
|
classes = [FakeFilter1, FakeFilter3, FakeFilter4]
|
||||||
|
exts = map(FakeExtension, classes)
|
||||||
|
super(FakeExtensionManager, self).__init__(exts)
|
||||||
|
self.namespace = namespace
|
||||||
|
|
||||||
|
|
||||||
|
class TestBaseFilterHandler(test.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestBaseFilterHandler, self).setUp()
|
||||||
|
self.mock_object(base_filter.base_handler.extension,
|
||||||
|
'ExtensionManager', FakeExtensionManager)
|
||||||
|
self.handler = base_filter.BaseFilterHandler(BaseFakeFilter,
|
||||||
|
'fake_filters')
|
||||||
|
|
||||||
|
def test_get_all_classes(self):
|
||||||
|
# In order for a FakeFilter to be returned by get_all_classes, it has
|
||||||
|
# to comply with these rules:
|
||||||
|
# * It must be derived from BaseFakeFilter
|
||||||
|
# AND
|
||||||
|
# * It must have a python entrypoint assigned (returned by
|
||||||
|
# FakeExtensionManager)
|
||||||
|
expected = [FakeFilter1, FakeFilter4]
|
||||||
|
result = self.handler.get_all_classes()
|
||||||
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
|
def _get_filtered_objects(self, filter_classes, index=0):
|
||||||
|
filter_objs_initial = [1, 2, 3, 4]
|
||||||
|
filter_properties = {'x': 'y'}
|
||||||
|
return self.handler.get_filtered_objects(filter_classes,
|
||||||
|
filter_objs_initial,
|
||||||
|
filter_properties,
|
||||||
|
index)
|
||||||
|
|
||||||
|
@mock.patch.object(FakeFilter4, 'filter_all')
|
||||||
|
@mock.patch.object(FakeFilter3, 'filter_all', return_value=None)
|
||||||
|
def test_get_filtered_objects_return_none(self, fake3_filter_all,
|
||||||
|
fake4_filter_all):
|
||||||
|
filter_classes = [FakeFilter1, FakeFilter2, FakeFilter3, FakeFilter4]
|
||||||
|
result = self._get_filtered_objects(filter_classes)
|
||||||
|
self.assertIsNone(result)
|
||||||
|
self.assertFalse(fake4_filter_all.called)
|
||||||
|
|
||||||
|
def test_get_filtered_objects(self):
|
||||||
|
filter_objs_expected = [1, 2, 3, 4]
|
||||||
|
filter_classes = [FakeFilter1, FakeFilter2, FakeFilter3, FakeFilter4]
|
||||||
|
result = self._get_filtered_objects(filter_classes)
|
||||||
|
self.assertEqual(filter_objs_expected, result)
|
||||||
|
|
||||||
|
def test_get_filtered_objects_with_filter_run_once(self):
|
||||||
|
filter_objs_expected = [1, 2, 3, 4]
|
||||||
|
filter_classes = [FakeFilter5]
|
||||||
|
|
||||||
|
with mock.patch.object(FakeFilter5, 'filter_all',
|
||||||
|
return_value=filter_objs_expected
|
||||||
|
) as fake5_filter_all:
|
||||||
|
result = self._get_filtered_objects(filter_classes)
|
||||||
|
self.assertEqual(filter_objs_expected, result)
|
||||||
|
self.assertEqual(1, fake5_filter_all.call_count)
|
||||||
|
|
||||||
|
result = self._get_filtered_objects(filter_classes, index=1)
|
||||||
|
self.assertEqual(filter_objs_expected, result)
|
||||||
|
self.assertEqual(1, fake5_filter_all.call_count)
|
||||||
|
|
||||||
|
result = self._get_filtered_objects(filter_classes, index=2)
|
||||||
|
self.assertEqual(filter_objs_expected, result)
|
||||||
|
self.assertEqual(1, fake5_filter_all.call_count)
|
|
@ -0,0 +1,86 @@
|
||||||
|
# Copyright (c) 2016 OpenStack Foundation
|
||||||
|
# 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 NodeManager
|
||||||
|
"""
|
||||||
|
|
||||||
|
import mock
|
||||||
|
|
||||||
|
from nimble.common import exception
|
||||||
|
from nimble.engine.scheduler import filters
|
||||||
|
from nimble.engine.scheduler import node_manager
|
||||||
|
from nimble.engine.scheduler.node_manager import NodeState
|
||||||
|
from nimble.tests import base as test
|
||||||
|
from nimble.tests.unit.engine.scheduler import fakes
|
||||||
|
|
||||||
|
|
||||||
|
class FakeFilterClass1(filters.BaseNodeFilter):
|
||||||
|
def node_passes(self, node_state, filter_properties):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class FakeFilterClass2(filters.BaseNodeFilter):
|
||||||
|
def node_passes(self, node_state, filter_properties):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class NodeManagerTestCase(test.TestCase):
|
||||||
|
"""Test case for NodeManager class."""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(NodeManagerTestCase, self).setUp()
|
||||||
|
self.node_manager = node_manager.NodeManager()
|
||||||
|
|
||||||
|
self.fake_nodes = [NodeState(fakes.fakenode1),
|
||||||
|
NodeState(fakes.fakenode2),
|
||||||
|
NodeState(fakes.fakenode3)]
|
||||||
|
|
||||||
|
def test_choose_node_filters_not_found(self):
|
||||||
|
self.override_config('scheduler_default_filters', 'FakeFilterClass3',
|
||||||
|
'scheduler')
|
||||||
|
self.node_manager.filter_classes = [FakeFilterClass1,
|
||||||
|
FakeFilterClass2]
|
||||||
|
self.assertRaises(exception.SchedulerNodeFilterNotFound,
|
||||||
|
self.node_manager._choose_node_filters, None)
|
||||||
|
|
||||||
|
def test_choose_node_filters(self):
|
||||||
|
self.override_config('scheduler_default_filters', 'FakeFilterClass2',
|
||||||
|
group='scheduler')
|
||||||
|
self.node_manager.filter_classes = [FakeFilterClass1,
|
||||||
|
FakeFilterClass2]
|
||||||
|
|
||||||
|
# Test returns 1 correct filter class
|
||||||
|
filter_classes = self.node_manager._choose_node_filters(None)
|
||||||
|
self.assertEqual(1, len(filter_classes))
|
||||||
|
self.assertEqual('FakeFilterClass2', filter_classes[0].__name__)
|
||||||
|
|
||||||
|
@mock.patch('nimble.engine.scheduler.node_manager.NodeManager.'
|
||||||
|
'_choose_node_filters')
|
||||||
|
def test_get_filtered_nodes(self, _mock_choose_node_filters):
|
||||||
|
filter_class = FakeFilterClass1
|
||||||
|
mock_func = mock.Mock()
|
||||||
|
mock_func.return_value = True
|
||||||
|
filter_class._filter_one = mock_func
|
||||||
|
_mock_choose_node_filters.return_value = [filter_class]
|
||||||
|
|
||||||
|
fake_properties = {'moo': 1, 'cow': 2}
|
||||||
|
expected = []
|
||||||
|
for fake_node in self.fake_nodes:
|
||||||
|
expected.append(mock.call(fake_node, fake_properties))
|
||||||
|
|
||||||
|
result = self.node_manager.get_filtered_nodes(self.fake_nodes,
|
||||||
|
fake_properties)
|
||||||
|
self.assertEqual(expected, mock_func.call_args_list)
|
||||||
|
self.assertEqual(set(self.fake_nodes), set(result))
|
|
@ -0,0 +1,138 @@
|
||||||
|
# Copyright 2016 OpenStack Foundation
|
||||||
|
# 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 PickledScheduler.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
from oslo_serialization import jsonutils
|
||||||
|
import six
|
||||||
|
|
||||||
|
from nimble.engine.scheduler import scheduler_options
|
||||||
|
from nimble.tests import base as test
|
||||||
|
|
||||||
|
|
||||||
|
class FakeSchedulerOptions(scheduler_options.SchedulerOptions):
|
||||||
|
def __init__(self, last_checked, now, file_old, file_now, data, filedata):
|
||||||
|
super(FakeSchedulerOptions, self).__init__()
|
||||||
|
# Change internals ...
|
||||||
|
self.last_modified = file_old
|
||||||
|
self.last_checked = last_checked
|
||||||
|
self.data = data
|
||||||
|
|
||||||
|
# For overrides ...
|
||||||
|
self._time_now = now
|
||||||
|
self._file_now = file_now
|
||||||
|
self._file_data = filedata
|
||||||
|
|
||||||
|
self.file_was_loaded = False
|
||||||
|
|
||||||
|
def _get_file_timestamp(self, filename):
|
||||||
|
return self._file_now
|
||||||
|
|
||||||
|
def _get_file_handle(self, filename):
|
||||||
|
self.file_was_loaded = True
|
||||||
|
return six.StringIO(self._file_data)
|
||||||
|
|
||||||
|
def _get_time_now(self):
|
||||||
|
return self._time_now
|
||||||
|
|
||||||
|
|
||||||
|
class SchedulerOptionsTestCase(test.TestCase):
|
||||||
|
def test_get_configuration_first_time_no_flag(self):
|
||||||
|
last_checked = None
|
||||||
|
now = datetime.datetime(2012, 1, 1, 1, 1, 1)
|
||||||
|
file_old = None
|
||||||
|
file_now = datetime.datetime(2012, 1, 1, 1, 1, 1)
|
||||||
|
|
||||||
|
data = dict(a=1, b=2, c=3)
|
||||||
|
jdata = jsonutils.dumps(data)
|
||||||
|
|
||||||
|
fake = FakeSchedulerOptions(last_checked, now, file_old, file_now,
|
||||||
|
{}, jdata)
|
||||||
|
self.assertEqual({}, fake.get_configuration())
|
||||||
|
self.assertFalse(fake.file_was_loaded)
|
||||||
|
|
||||||
|
def test_get_configuration_first_time_empty_file(self):
|
||||||
|
last_checked = None
|
||||||
|
now = datetime.datetime(2012, 1, 1, 1, 1, 1)
|
||||||
|
file_old = None
|
||||||
|
file_now = datetime.datetime(2012, 1, 1, 1, 1, 1)
|
||||||
|
|
||||||
|
jdata = ""
|
||||||
|
|
||||||
|
fake = FakeSchedulerOptions(last_checked, now, file_old, file_now,
|
||||||
|
{}, jdata)
|
||||||
|
self.assertEqual({}, fake.get_configuration('foo.json'))
|
||||||
|
self.assertTrue(fake.file_was_loaded)
|
||||||
|
|
||||||
|
def test_get_configuration_first_time_happy_day(self):
|
||||||
|
last_checked = None
|
||||||
|
now = datetime.datetime(2012, 1, 1, 1, 1, 1)
|
||||||
|
file_old = None
|
||||||
|
file_now = datetime.datetime(2012, 1, 1, 1, 1, 1)
|
||||||
|
|
||||||
|
data = dict(a=1, b=2, c=3)
|
||||||
|
jdata = jsonutils.dumps(data)
|
||||||
|
|
||||||
|
fake = FakeSchedulerOptions(last_checked, now, file_old, file_now,
|
||||||
|
{}, jdata)
|
||||||
|
self.assertEqual(data, fake.get_configuration('foo.json'))
|
||||||
|
self.assertTrue(fake.file_was_loaded)
|
||||||
|
|
||||||
|
def test_get_configuration_second_time_no_change(self):
|
||||||
|
last_checked = datetime.datetime(2011, 1, 1, 1, 1, 1)
|
||||||
|
now = datetime.datetime(2012, 1, 1, 1, 1, 1)
|
||||||
|
file_old = datetime.datetime(2012, 1, 1, 1, 1, 1)
|
||||||
|
file_now = datetime.datetime(2012, 1, 1, 1, 1, 1)
|
||||||
|
|
||||||
|
data = dict(a=1, b=2, c=3)
|
||||||
|
jdata = jsonutils.dumps(data)
|
||||||
|
|
||||||
|
fake = FakeSchedulerOptions(last_checked, now, file_old, file_now,
|
||||||
|
data, jdata)
|
||||||
|
self.assertEqual(data, fake.get_configuration('foo.json'))
|
||||||
|
self.assertFalse(fake.file_was_loaded)
|
||||||
|
|
||||||
|
def test_get_configuration_second_time_too_fast(self):
|
||||||
|
last_checked = datetime.datetime(2011, 1, 1, 1, 1, 1)
|
||||||
|
now = datetime.datetime(2011, 1, 1, 1, 1, 2)
|
||||||
|
file_old = datetime.datetime(2012, 1, 1, 1, 1, 1)
|
||||||
|
file_now = datetime.datetime(2013, 1, 1, 1, 1, 1)
|
||||||
|
|
||||||
|
old_data = dict(a=1, b=2, c=3)
|
||||||
|
data = dict(a=11, b=12, c=13)
|
||||||
|
jdata = jsonutils.dumps(data)
|
||||||
|
|
||||||
|
fake = FakeSchedulerOptions(last_checked, now, file_old, file_now,
|
||||||
|
old_data, jdata)
|
||||||
|
self.assertEqual(old_data, fake.get_configuration('foo.json'))
|
||||||
|
self.assertFalse(fake.file_was_loaded)
|
||||||
|
|
||||||
|
def test_get_configuration_second_time_change(self):
|
||||||
|
last_checked = datetime.datetime(2011, 1, 1, 1, 1, 1)
|
||||||
|
now = datetime.datetime(2012, 1, 1, 1, 1, 1)
|
||||||
|
file_old = datetime.datetime(2012, 1, 1, 1, 1, 1)
|
||||||
|
file_now = datetime.datetime(2013, 1, 1, 1, 1, 1)
|
||||||
|
|
||||||
|
old_data = dict(a=1, b=2, c=3)
|
||||||
|
data = dict(a=11, b=12, c=13)
|
||||||
|
jdata = jsonutils.dumps(data)
|
||||||
|
|
||||||
|
fake = FakeSchedulerOptions(last_checked, now, file_old, file_now,
|
||||||
|
old_data, jdata)
|
||||||
|
self.assertEqual(data, fake.get_configuration('foo.json'))
|
||||||
|
self.assertTrue(fake.file_was_loaded)
|
|
@ -0,0 +1,54 @@
|
||||||
|
# Copyright 2016 OpenStack Foundation.
|
||||||
|
# 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 weights.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from nimble.engine.scheduler import base_weight
|
||||||
|
from nimble.tests import base as test
|
||||||
|
|
||||||
|
|
||||||
|
class TestWeightHandler(test.TestCase):
|
||||||
|
def test_no_multiplier(self):
|
||||||
|
class FakeWeigher(base_weight.BaseWeigher):
|
||||||
|
def _weigh_object(self, *args, **kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
self.assertEqual(1.0,
|
||||||
|
FakeWeigher().weight_multiplier())
|
||||||
|
|
||||||
|
def test_no_weight_object(self):
|
||||||
|
class FakeWeigher(base_weight.BaseWeigher):
|
||||||
|
def weight_multiplier(self, *args, **kwargs):
|
||||||
|
pass
|
||||||
|
self.assertRaises(TypeError,
|
||||||
|
FakeWeigher)
|
||||||
|
|
||||||
|
def test_normalization(self):
|
||||||
|
# weight_list, expected_result, minval, maxval
|
||||||
|
map_ = (
|
||||||
|
((), (), None, None),
|
||||||
|
((0.0, 0.0), (0.0, 0.0), None, None),
|
||||||
|
((1.0, 1.0), (0.0, 0.0), None, None),
|
||||||
|
|
||||||
|
((20.0, 50.0), (0.0, 1.0), None, None),
|
||||||
|
((20.0, 50.0), (0.0, 0.375), None, 100.0),
|
||||||
|
((20.0, 50.0), (0.4, 1.0), 0.0, None),
|
||||||
|
((20.0, 50.0), (0.2, 0.5), 0.0, 100.0),
|
||||||
|
)
|
||||||
|
for seq, result, minval, maxval in map_:
|
||||||
|
ret = base_weight.normalize(seq, minval=minval, maxval=maxval)
|
||||||
|
self.assertEqual(result, tuple(ret))
|
|
@ -0,0 +1,22 @@
|
||||||
|
# Copyright 2016 Intel, Inc.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
IMAGE_ID = 'e79161cd-5f9d-4007-8823-81a807a64332'
|
||||||
|
INSTANCE_ID = 'fa617131-cdbc-45dc-afff-f21f17ae054e'
|
||||||
|
PROJECT_ID = '89afd400-b646-4bbc-b12b-c0a4d63e5bd3'
|
||||||
|
PROJECT2_ID = '452ebfbc-55d9-402a-87af-65061916c24b'
|
||||||
|
PROJECT3_ID = 'f6c912d7-bf30-4b12-af81-a9e0b2f85f85'
|
||||||
|
USER_ID = 'c853ca26-e8ea-4797-8a52-ee124a013d0e'
|
||||||
|
USER2_ID = '95f7b7ed-bd7f-426e-b05f-f1ffeb4f09df'
|
|
@ -7,6 +7,7 @@ hacking<0.12,>=0.11.0 # Apache-2.0
|
||||||
coverage>=3.6 # Apache-2.0
|
coverage>=3.6 # Apache-2.0
|
||||||
python-subunit>=0.0.18 # Apache-2.0/BSD
|
python-subunit>=0.0.18 # Apache-2.0/BSD
|
||||||
sphinx!=1.3b1,<1.4,>=1.2.1 # BSD
|
sphinx!=1.3b1,<1.4,>=1.2.1 # BSD
|
||||||
|
ddt>=1.0.1 # MIT
|
||||||
oslosphinx>=4.7.0 # Apache-2.0
|
oslosphinx>=4.7.0 # Apache-2.0
|
||||||
oslotest>=1.10.0 # Apache-2.0
|
oslotest>=1.10.0 # Apache-2.0
|
||||||
testrepository>=0.0.18 # Apache-2.0/BSD
|
testrepository>=0.0.18 # Apache-2.0/BSD
|
||||||
|
|
Loading…
Reference in New Issue