Add a test fixture
This adds a fixture that can be used by consuming projects to simulate a set of limits in keystone, without requiring actual keystone. Currently, consumers have to mock oslo.limit internals (at least) in order to do testing. Change-Id: If72050e90ca8b03e26d128c7bbcef6bbea92b501
This commit is contained in:
parent
1175b0f7c1
commit
caa75c1bab
@ -1,6 +1,7 @@
|
|||||||
# The order of packages is significant, because pip processes them in the order
|
# The order of packages is significant, because pip processes them in the order
|
||||||
# of appearance. Changing the order has an impact on the overall integration
|
# of appearance. Changing the order has an impact on the overall integration
|
||||||
# process, which may cause wedges in the gate later.
|
# process, which may cause wedges in the gate later.
|
||||||
|
fixtures>=3.0.0 # Apache-2.0/BSD
|
||||||
openstackdocstheme>=2.2.1 # Apache-2.0
|
openstackdocstheme>=2.2.1 # Apache-2.0
|
||||||
reno>=3.1.0 # Apache-2.0
|
reno>=3.1.0 # Apache-2.0
|
||||||
sphinx>=2.0.0,!=2.1.0 # BSD
|
sphinx>=2.0.0,!=2.1.0 # BSD
|
||||||
|
@ -4,3 +4,4 @@ Using oslo.limit
|
|||||||
.. toctree::
|
.. toctree::
|
||||||
|
|
||||||
usage.rst
|
usage.rst
|
||||||
|
testing.rst
|
||||||
|
30
doc/source/user/testing.rst
Normal file
30
doc/source/user/testing.rst
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
=======
|
||||||
|
Testing
|
||||||
|
=======
|
||||||
|
|
||||||
|
To test a project that uses oslo.limit, a fixture is provided. This
|
||||||
|
mocks out the connection to keystone and retrieval of registered and
|
||||||
|
project limits.
|
||||||
|
|
||||||
|
Example
|
||||||
|
=======
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from oslo_limit import fixture
|
||||||
|
|
||||||
|
class MyTest(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(MyTest, self).setUp()
|
||||||
|
|
||||||
|
# Default limit of 10 widgets
|
||||||
|
registered_limits = {'widgets': 10}
|
||||||
|
|
||||||
|
# project2 gets 20 widgets
|
||||||
|
project_limits = {'project2': {'widgets': 20}}
|
||||||
|
|
||||||
|
self.useFixture(fixture.LimitFixture(registered_limits,
|
||||||
|
project_limits))
|
||||||
|
|
||||||
|
def test_thing(self):
|
||||||
|
# ... use limit.Enforcer() as usual
|
75
oslo_limit/fixture.py
Normal file
75
oslo_limit/fixture.py
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
# Copyright 2021 Red Hat, 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.
|
||||||
|
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
|
import fixtures as fixtures
|
||||||
|
|
||||||
|
from openstack.identity.v3 import endpoint
|
||||||
|
from openstack.identity.v3 import limit as keystone_limit
|
||||||
|
|
||||||
|
|
||||||
|
class LimitFixture(fixtures.Fixture):
|
||||||
|
def __init__(self, reglimits, projlimits):
|
||||||
|
"""A fixture for testing code that relies on Keystone Unified Limits.
|
||||||
|
|
||||||
|
:param reglimits: A dictionary of {resource_name: limit} values to
|
||||||
|
simulate registered limits in keystone.
|
||||||
|
:type reglimits: dict
|
||||||
|
:param projlimits: A dictionary of dictionaries defining per-project
|
||||||
|
limits like {project_id: {resource_name: limit}}.
|
||||||
|
As in reality, only per-project overrides need be
|
||||||
|
provided here; any unmentioned projects or
|
||||||
|
resources will take the registered limit defaults.
|
||||||
|
:type reglimits: dict
|
||||||
|
"""
|
||||||
|
self.reglimits = reglimits
|
||||||
|
self.projlimits = projlimits
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(LimitFixture, self).setUp()
|
||||||
|
|
||||||
|
# We mock our own cached connection to Keystone
|
||||||
|
self.mock_conn = mock.MagicMock()
|
||||||
|
self.useFixture(fixtures.MockPatch('oslo_limit.limit._SDK_CONNECTION',
|
||||||
|
new=self.mock_conn))
|
||||||
|
|
||||||
|
# Use a flat enforcement model
|
||||||
|
mock_gem = self.useFixture(
|
||||||
|
fixtures.MockPatch('oslo_limit.limit.Enforcer.'
|
||||||
|
'_get_enforcement_model')).mock
|
||||||
|
mock_gem.return_value = 'flat'
|
||||||
|
|
||||||
|
# Fake keystone endpoint; no per-service limit distinction
|
||||||
|
fake_endpoint = endpoint.Endpoint()
|
||||||
|
fake_endpoint.service_id = "service_id"
|
||||||
|
fake_endpoint.region_id = "region_id"
|
||||||
|
self.mock_conn.get_endpoint.return_value = fake_endpoint
|
||||||
|
|
||||||
|
def fake_limits(service_id, region_id, resource_name, project_id=None):
|
||||||
|
this_limit = keystone_limit.Limit()
|
||||||
|
this_limit.resource_name = resource_name
|
||||||
|
if project_id is None:
|
||||||
|
this_limit.default_limit = self.reglimits.get(resource_name)
|
||||||
|
if this_limit.default_limit is None:
|
||||||
|
return iter([None])
|
||||||
|
else:
|
||||||
|
this_limit.resource_limit = \
|
||||||
|
self.projlimits.get(project_id, {}).get(resource_name)
|
||||||
|
if this_limit.resource_limit is None:
|
||||||
|
return iter([None])
|
||||||
|
|
||||||
|
return iter([this_limit])
|
||||||
|
|
||||||
|
self.mock_conn.limits.side_effect = fake_limits
|
||||||
|
self.mock_conn.registered_limits.side_effect = fake_limits
|
92
oslo_limit/tests/test_fixture.py
Normal file
92
oslo_limit/tests/test_fixture.py
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
# Copyright 2021 Red Hat, 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.
|
||||||
|
|
||||||
|
from oslotest import base
|
||||||
|
|
||||||
|
from oslo_limit import exception
|
||||||
|
from oslo_limit import fixture
|
||||||
|
from oslo_limit import limit
|
||||||
|
|
||||||
|
|
||||||
|
class TestFixture(base.BaseTestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(TestFixture, self).setUp()
|
||||||
|
|
||||||
|
# Set up some default projects, registered limits,
|
||||||
|
# and project limits
|
||||||
|
reglimits = {'widgets': 100,
|
||||||
|
'sprockets': 50}
|
||||||
|
projlimits = {
|
||||||
|
'project2': {'widgets': 10},
|
||||||
|
}
|
||||||
|
self.useFixture(fixture.LimitFixture(reglimits, projlimits))
|
||||||
|
|
||||||
|
# Some fake usage for projects
|
||||||
|
self.usage = {
|
||||||
|
'project1': {'sprockets': 10,
|
||||||
|
'widgets': 10},
|
||||||
|
'project2': {'sprockets': 3,
|
||||||
|
'widgets': 3},
|
||||||
|
}
|
||||||
|
|
||||||
|
def proj_usage(project_id, resource_names):
|
||||||
|
return self.usage[project_id]
|
||||||
|
|
||||||
|
# An enforcer to play with
|
||||||
|
self.enforcer = limit.Enforcer(proj_usage)
|
||||||
|
|
||||||
|
def test_project_under_registered_limit_only(self):
|
||||||
|
# Project1 has quota of 50 and 100 each, so no problem with
|
||||||
|
# 10+1 usage.
|
||||||
|
self.enforcer.enforce('project1', {'sprockets': 1,
|
||||||
|
'widgets': 1})
|
||||||
|
|
||||||
|
def test_project_over_registered_limit_only(self):
|
||||||
|
# Project1 has quota of 100 widgets, usage of 112 is over
|
||||||
|
# quota.
|
||||||
|
self.assertRaises(exception.ProjectOverLimit,
|
||||||
|
self.enforcer.enforce,
|
||||||
|
'project1', {'sprockets': 1,
|
||||||
|
'widgets': 102})
|
||||||
|
|
||||||
|
def test_project_over_registered_limit(self):
|
||||||
|
# delta=1 should be under the registered limit of 50
|
||||||
|
self.enforcer.enforce('project2', {'sprockets': 1})
|
||||||
|
|
||||||
|
# delta=50 should be over the registered limit of 50
|
||||||
|
self.assertRaises(exception.ProjectOverLimit,
|
||||||
|
self.enforcer.enforce,
|
||||||
|
'project2', {'sprockets': 50})
|
||||||
|
|
||||||
|
def test_project_over_project_limits(self):
|
||||||
|
# delta=7 is usage=10, right at our project limit of 10
|
||||||
|
self.enforcer.enforce('project2', {'widgets': 7})
|
||||||
|
|
||||||
|
# delta=10 is usage 13, over our project limit of 10
|
||||||
|
self.assertRaises(exception.ProjectOverLimit,
|
||||||
|
self.enforcer.enforce,
|
||||||
|
'project2', {'widgets': 10})
|
||||||
|
|
||||||
|
def test_calculate_usage(self):
|
||||||
|
# Make sure the usage calculator works with the fixture too
|
||||||
|
u = self.enforcer.calculate_usage('project2', ['widgets'])['widgets']
|
||||||
|
self.assertEqual(3, u.usage)
|
||||||
|
self.assertEqual(10, u.limit)
|
||||||
|
|
||||||
|
u = self.enforcer.calculate_usage('project1', ['widgets', 'sprockets'])
|
||||||
|
self.assertEqual(10, u['sprockets'].usage)
|
||||||
|
self.assertEqual(10, u['widgets'].usage)
|
||||||
|
# Since project1 has no project limits, make sure we get the
|
||||||
|
# registered limit values
|
||||||
|
self.assertEqual(50, u['sprockets'].limit)
|
||||||
|
self.assertEqual(100, u['widgets'].limit)
|
@ -2,6 +2,7 @@
|
|||||||
# of appearance. Changing the order has an impact on the overall integration
|
# of appearance. Changing the order has an impact on the overall integration
|
||||||
# process, which may cause wedges in the gate later.
|
# process, which may cause wedges in the gate later.
|
||||||
|
|
||||||
|
fixtures>=3.0.0 # Apache-2.0/BSD
|
||||||
hacking>=3.0.1,<3.1.0 # Apache-2.0
|
hacking>=3.0.1,<3.1.0 # Apache-2.0
|
||||||
oslotest>=3.2.0 # Apache-2.0
|
oslotest>=3.2.0 # Apache-2.0
|
||||||
stestr>=1.0.0 # Apache-2.0
|
stestr>=1.0.0 # Apache-2.0
|
||||||
|
Loading…
x
Reference in New Issue
Block a user