ut updates for extending sub-resources

When extending an existing sub-resource definition, the
SUB_RESOURCE_ATTRIBUTE_MAP must define the extended resources/attributes
under the 'parameters' object. This instructs the API internals to
update the existing sub-resource's attribute map rather than just
overwrite it. For internals see the logic in the extend_resources()
method in neutron.api.extensions [1]. For example the
qos_bw_limit_direction in neutron uses this approach for its
BANDWIDTH_LIMIT_RULES definition (also see related lib commit
I823f567ddf9c895eb3cf94e95ae34a382d67f51d).

This patch adds that support to the base api def test case and also
updates the contributor internals to document such. No release note
included since nothing changed from a consumption perspective.

[1] https://github.com/openstack/neutron/blob/master/neutron/api/extensions.py#L350

Change-Id: Ib91004490dc3ca71b7caafe5cc3cb07417be1e4c
This commit is contained in:
Boden R 2017-11-22 10:46:44 -07:00
parent 2042d18d1f
commit 36bb16b941
3 changed files with 46 additions and 12 deletions

View File

@ -89,3 +89,21 @@ The following are the defined keys for attribute maps:
``enforce_policy`` the attribute is actively part of the policy enforcing mechanism, ie: there might be rules which refer to this attribute
``primary_key`` Mark the attribute as a unique key.
====================== ======
When extending existing sub-resources, the sub-attribute map must define all
extension attributes under the ``parameters`` object. This instructs the API
internals to add the attributes to the existing sub-resource rather than
overwrite its existing definition. For example:
.. code-block:: python
SUB_RESOURCE_ATTRIBUTE_MAP = {
'existing_subresource_to_extend': {
'parameters': {
'new_attr1': {
'allow_post': False,
# etc..
}
}
}
}

View File

@ -76,7 +76,10 @@ RESOURCE_ATTRIBUTE_MAP = {
# The subresource attribute map for the extension. It adds child resources
# to main extension's resource. The subresource map must have a parent and
# a parameters entry. If an extension does not need such a map, None can
# be specified (mandatory). For example:
# be specified (mandatory).
# Note that if an existing sub-resource is being extended, the
# existing resources to extend the new extension attributes must be
# defined under the 'parameters' key.
SUB_RESOURCE_ATTRIBUTE_MAP = {
'subfoo': {
'parent': {

View File

@ -132,23 +132,36 @@ class DefinitionBaseTestCase(test_base.BaseTestCase):
resource[attribute],
keyword, value)
def _assert_subresource(self, subresource):
self.assertIn(
self.subresource_map[subresource]['parent']['collection_name'],
base.KNOWN_RESOURCES + self.extension_resources,
'Sub-resource parent is unknown, check for typos.')
self.assertIn('member_name',
self.subresource_map[subresource]['parent'],
'Incorrect parent definition, check for typos.')
self.assertParams(self.subresource_map[subresource]['parameters'])
def test_subresource_map(self):
if not self.subresource_map:
self.skipTest('API extension has no subresource map.')
for subresource in self.subresource_map:
self.assertIn(
subresource, self.extension_subresources,
subresource,
self.extension_subresources + base.KNOWN_RESOURCES,
'Sub-resource is unknown, check for typos.')
for attribute in self.subresource_map[subresource]:
self.assertIn(attribute, ('parent', 'parameters'))
self.assertIn(
self.subresource_map[subresource]['parent']['collection_name'],
base.KNOWN_RESOURCES + self.extension_resources,
'Sub-resource parent is unknown, check for typos.')
self.assertIn('member_name',
self.subresource_map[subresource]['parent'],
'Incorrect parent definition, check for typos.')
self.assertParams(self.subresource_map[subresource]['parameters'])
sub_attrmap = self.subresource_map[subresource]
if 'parent' in sub_attrmap:
self.assertEqual(2, len(sub_attrmap.keys()))
self.assertIn('parent', sub_attrmap)
self.assertIn('parameters', sub_attrmap)
self._assert_subresource(subresource)
else:
self.assertEqual(
['parameters'], [p for p in sub_attrmap.keys()],
'When extending sub-resources only use the parameters '
'keyword')
self.assertParams(sub_attrmap['parameters'])
def test_action_map(self):
self.assertIsInstance(self.action_map, dict)