Model, Client, and Config for querying deployed Neutron Extensions
* Implemented Response Model (JSON only) * Implemented Client - Supports single API call * Implemented Config - Specific extensions required for test execution * Added section and options to reference.json.config template * Metatests for validating model logic Change-Id: I90b87d6092bbbcc928901fac71c9690ef26535a4
This commit is contained in:
parent
0062307d8e
commit
2bce7ad403
70
cloudcafe/networking/networks/extensions/client.py
Normal file
70
cloudcafe/networking/networks/extensions/client.py
Normal file
@ -0,0 +1,70 @@
|
||||
"""
|
||||
Copyright 2015 Rackspace
|
||||
|
||||
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 cafe.engine.http.client import AutoMarshallingHTTPClient
|
||||
|
||||
from cloudcafe.networking.networks.extensions.model import NeutronExtensions
|
||||
|
||||
content_type_fmt = '{content_type}/{content_subtype}'
|
||||
|
||||
|
||||
class ExtensionsClient(AutoMarshallingHTTPClient):
|
||||
"""
|
||||
This client will retrieve a list of Neutron extensions currently
|
||||
deployed in the target environment.
|
||||
|
||||
"""
|
||||
def __init__(self, url, auth_token, serialize_format=None,
|
||||
deserialize_format=None, tenant_id=None):
|
||||
|
||||
"""
|
||||
@summary: Rackspace Neutron API extension client
|
||||
@param url: Base URL for the networks service
|
||||
@type url: string
|
||||
@param auth_token: Auth token to be used for all requests
|
||||
@type auth_token: string
|
||||
@param serialize_format: Format for serializing requests
|
||||
@type serialize_format: string
|
||||
@param deserialize_format: Format for de-serializing responses
|
||||
@type deserialize_format: string
|
||||
@param tenant_id: optional tenant id to be included in the
|
||||
header if given
|
||||
@type tenant_id: string
|
||||
"""
|
||||
super(ExtensionsClient, self).__init__(serialize_format,
|
||||
deserialize_format)
|
||||
self.auth_token = auth_token
|
||||
self.default_headers['X-Auth-Token'] = auth_token
|
||||
self.default_headers['Content-Type'] = content_type_fmt.format(
|
||||
content_type='application',
|
||||
content_subtype=self.serialize_format)
|
||||
self.default_headers['Accept'] = content_type_fmt.format(
|
||||
content_type='application',
|
||||
content_subtype=self.deserialize_format)
|
||||
if tenant_id:
|
||||
self.default_headers['X-Auth-Project-Id'] = tenant_id
|
||||
self.url = url
|
||||
self.extensions_url = '{url}/extensions'.format(url=self.url)
|
||||
|
||||
def get_deployed_extensions(self, requestslib_kwargs=None):
|
||||
"""
|
||||
Get the list of extensions deployed in the target environment.
|
||||
:param requestslib_kwargs:
|
||||
:return:
|
||||
"""
|
||||
return self.request('GET', self.extensions_url,
|
||||
response_entity_type=NeutronExtensions,
|
||||
requestslib_kwargs=requestslib_kwargs)
|
30
cloudcafe/networking/networks/extensions/config.py
Normal file
30
cloudcafe/networking/networks/extensions/config.py
Normal file
@ -0,0 +1,30 @@
|
||||
"""
|
||||
Copyright 2015 Rackspace
|
||||
|
||||
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 cloudcafe.common.models.configuration import ConfigSectionInterface
|
||||
|
||||
class NeutronExtensionConfig(ConfigSectionInterface):
|
||||
|
||||
SECTION_NAME = 'neutron_extensions'
|
||||
|
||||
@property
|
||||
def required(self):
|
||||
"""
|
||||
List (comma-separated string) of required, deployed neutron extensions.
|
||||
"""
|
||||
extensions = self.get("required", '')
|
||||
return [ext.strip() for ext in extensions.split(',')
|
||||
if ext.strip() != '']
|
50
cloudcafe/networking/networks/extensions/model.py
Normal file
50
cloudcafe/networking/networks/extensions/model.py
Normal file
@ -0,0 +1,50 @@
|
||||
"""
|
||||
Copyright 2015 Rackspace
|
||||
|
||||
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 json
|
||||
|
||||
from cafe.engine.models.base \
|
||||
import AutoMarshallingListModel, AutoMarshallingModel
|
||||
|
||||
class NeutronExtension(AutoMarshallingModel):
|
||||
def __init__(self, updated, name, links, namespace, alias, description):
|
||||
super(NeutronExtension, self).__init__()
|
||||
self.updated = updated
|
||||
self.name = name
|
||||
self.links = links
|
||||
self.namespace = namespace
|
||||
self.alias = alias
|
||||
self.description = description
|
||||
|
||||
@classmethod
|
||||
def _json_to_obj(cls, serialized_str):
|
||||
# NOTE: The individual extension summaries do not have a ROOT TAG.
|
||||
json_dict = json.loads(serialized_str)
|
||||
return cls(**json_dict)
|
||||
|
||||
|
||||
class NeutronExtensions(AutoMarshallingListModel):
|
||||
ROOT_TAG = 'extensions'
|
||||
LIST_MODEL = NeutronExtension
|
||||
|
||||
@classmethod
|
||||
def _json_to_obj(cls, serialized_str):
|
||||
json_dict = json.loads(serialized_str)
|
||||
|
||||
extensions = cls()
|
||||
for extension in json_dict.get(cls.ROOT_TAG, {}):
|
||||
extensions.append(cls.LIST_MODEL(**extension))
|
||||
return extensions
|
@ -152,3 +152,6 @@ keep_resources_on_failure=<Flag for not deleting resources w failures on tearDow
|
||||
resource_create_timeout=<Seconds to wait for creating a resource>
|
||||
resource_delete_timeout=<Seconds to wait for deleting a resource>
|
||||
starts_with_name=<Port start name label for test runs>
|
||||
|
||||
[neutron_extensions]
|
||||
required=<extensions required for test execution>
|
||||
|
@ -0,0 +1,71 @@
|
||||
"""
|
||||
Copyright 2015 Rackspace
|
||||
|
||||
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 unittest
|
||||
|
||||
import cloudcafe.networking.networks.extensions.model as ext_models
|
||||
|
||||
|
||||
class ValidateExtensionEntries(unittest.TestCase):
|
||||
"""
|
||||
This test validates the model generated from a Neutron Extensions query.
|
||||
These tests only verify the JSON-to-Obj translation, since there is no
|
||||
request (POST/PUT/DELETE) aspect to the API.
|
||||
"""
|
||||
|
||||
MODEL = ext_models.NeutronExtensions
|
||||
LIST_ELEMENT_MODEL = ext_models.NeutronExtension
|
||||
RESPONSE_FORMAT = 'json'
|
||||
NUM_OF_EXTENSIONS = 10
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.expected_response_obj = []
|
||||
cls.json_parts = []
|
||||
|
||||
json_format = """
|
||||
{{
|
||||
"updated": "{updated}",
|
||||
"name": "{name}",
|
||||
"links": {links},
|
||||
"namespace": "{namespace}",
|
||||
"alias": "{alias}",
|
||||
"description": "{description}"
|
||||
}} """
|
||||
|
||||
|
||||
data_name = 'test_extension_{0}'
|
||||
namespace = 'namespace_link_{0}'
|
||||
for index in xrange(cls.NUM_OF_EXTENSIONS):
|
||||
|
||||
data = {'updated': "Timestamp goes here",
|
||||
'name': data_name.format(index),
|
||||
'links': [],
|
||||
'namespace': namespace.format(index),
|
||||
'alias': data_name.format(index),
|
||||
'description': 'A brief description of the extension'}
|
||||
|
||||
cls.expected_response_obj.append(cls.LIST_ELEMENT_MODEL(**data))
|
||||
cls.json_parts.append(json_format.format(**data))
|
||||
|
||||
list_body = ','.join(cls.json_parts)
|
||||
cls.json_response = '{{ "{root_tag}": [{body}\n ]\n}}'.format(
|
||||
root_tag=cls.MODEL.ROOT_TAG, body=list_body)
|
||||
|
||||
def test_deserialize_extension_list_response_into_obj(self):
|
||||
""" Deserialize a JSON response into an NeutronExtensions obj """
|
||||
response_obj = self.MODEL.deserialize(
|
||||
self.json_response, self.RESPONSE_FORMAT)
|
||||
self.assertEqual(response_obj, self.expected_response_obj)
|
Loading…
x
Reference in New Issue
Block a user