Nova IP Associations Rackspace Extension for Shared IPs
- Adding a couple of HTTPResponseCodes to compute constants - Adding the compute IP Associations request and response models and metatests - Adding the compute IP Associations constants, client and composite Change-Id: I43dbbf16192c31f9b95860ed5dddfd578c1a0006
This commit is contained in:
parent
5279061acf
commit
3093aaa6f8
@ -54,6 +54,12 @@ class Constants:
|
|||||||
"""
|
"""
|
||||||
return [v for k, v in cls.__dict__.items() if k.startswith('XML')]
|
return [v for k, v in cls.__dict__.items() if k.startswith('XML')]
|
||||||
|
|
||||||
|
|
||||||
class HTTPResponseCodes(object):
|
class HTTPResponseCodes(object):
|
||||||
NOT_FOUND = 404
|
NOT_FOUND = 404
|
||||||
SERVER_ERROR = 500
|
SERVER_ERROR = 500
|
||||||
|
BAD_REQUEST = 400
|
||||||
|
UNAUTHORIZED = 401
|
||||||
|
FORBIDDEN = 403
|
||||||
|
CONFLICT = 409
|
||||||
|
REQUEST_ENTITY_TOO_LARGE = 413
|
||||||
|
15
cloudcafe/compute/extensions/ip_associations_api/__init__.py
Normal file
15
cloudcafe/compute/extensions/ip_associations_api/__init__.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
"""
|
||||||
|
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.
|
||||||
|
"""
|
149
cloudcafe/compute/extensions/ip_associations_api/client.py
Normal file
149
cloudcafe/compute/extensions/ip_associations_api/client.py
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
"""
|
||||||
|
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.compute.extensions.ip_associations_api.models.response \
|
||||||
|
import IPAssociation, IPAssociations
|
||||||
|
|
||||||
|
|
||||||
|
class IPAssociationsClient(AutoMarshallingHTTPClient):
|
||||||
|
|
||||||
|
def __init__(self, url, auth_token, serialize_format=None,
|
||||||
|
deserialize_format=None):
|
||||||
|
"""
|
||||||
|
@summary: Rackspace Compute API IP Associations extension client
|
||||||
|
@param url: Base URL for the compute 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
|
||||||
|
"""
|
||||||
|
super(IPAssociationsClient, self).__init__(serialize_format,
|
||||||
|
deserialize_format)
|
||||||
|
self.auth_token = auth_token
|
||||||
|
self.default_headers['X-Auth-Token'] = auth_token
|
||||||
|
ct = '{content_type}/{content_subtype}'.format(
|
||||||
|
content_type='application',
|
||||||
|
content_subtype=self.serialize_format)
|
||||||
|
accept = '{content_type}/{content_subtype}'.format(
|
||||||
|
content_type='application',
|
||||||
|
content_subtype=self.deserialize_format)
|
||||||
|
self.default_headers['Content-Type'] = ct
|
||||||
|
self.default_headers['Accept'] = accept
|
||||||
|
self.url = url
|
||||||
|
|
||||||
|
def list_ip_associations(self, server_id, ip_address_id=None,
|
||||||
|
address=None, limit=None, marker=None,
|
||||||
|
page_reverse=None, requestslib_kwargs=None):
|
||||||
|
"""
|
||||||
|
@summary: Lists IP associations by server, filtered by params if given
|
||||||
|
@param server_id: server UUID to get shared IP associations
|
||||||
|
@type server_id: str
|
||||||
|
@param ip_address_id: shared IP UUID to filter by
|
||||||
|
@type ip_address_id: str
|
||||||
|
@param address: IPv4 or IPv6 shared IP address to filter by
|
||||||
|
@type address: str
|
||||||
|
@param limit: page size
|
||||||
|
@type limit: int
|
||||||
|
@param marker: Id of the last item of the previous page
|
||||||
|
@type marker: string
|
||||||
|
@param page_reverse: direction of the page
|
||||||
|
@type page_reverse: bool
|
||||||
|
@return: IP associations list response
|
||||||
|
@rtype: Requests.response
|
||||||
|
"""
|
||||||
|
|
||||||
|
params = {'id': ip_address_id, 'address': address,
|
||||||
|
'limit': limit, 'marker': marker,
|
||||||
|
'page_reverse': page_reverse}
|
||||||
|
|
||||||
|
url = '{base_url}/servers/{server_id}/ip_associations'.format(
|
||||||
|
base_url=self.url, server_id=server_id)
|
||||||
|
|
||||||
|
resp = self.request('GET', url, params=params,
|
||||||
|
response_entity_type=IPAssociations,
|
||||||
|
requestslib_kwargs=requestslib_kwargs)
|
||||||
|
return resp
|
||||||
|
|
||||||
|
def get_ip_association(self, server_id, ip_address_id,
|
||||||
|
requestslib_kwargs=None):
|
||||||
|
"""
|
||||||
|
@summary: Shows a specific IP association
|
||||||
|
@param server_id: server UUID to get shared IP association
|
||||||
|
@type server_id: str
|
||||||
|
@param ip_address_id: shared IP UUID
|
||||||
|
@type ip_address_id: str
|
||||||
|
@return: IP association get response
|
||||||
|
@rtype: Requests.response
|
||||||
|
"""
|
||||||
|
|
||||||
|
url = ('{base_url}/servers/{server_id}/ip_associations/'
|
||||||
|
'{ip_address_id}').format(base_url=self.url,
|
||||||
|
server_id=server_id,
|
||||||
|
ip_address_id=ip_address_id)
|
||||||
|
|
||||||
|
resp = self.request('GET', url,
|
||||||
|
response_entity_type=IPAssociation,
|
||||||
|
requestslib_kwargs=requestslib_kwargs)
|
||||||
|
return resp
|
||||||
|
|
||||||
|
def create_ip_association(self, server_id, ip_address_id,
|
||||||
|
requestslib_kwargs=None):
|
||||||
|
"""
|
||||||
|
@summary: Creates a shared IP association with a server instance
|
||||||
|
@param server_id: server UUID to create shared IP association
|
||||||
|
@type server_id: str
|
||||||
|
@param ip_address_id: shared IP UUID to associate with server
|
||||||
|
@type ip_address_id: str
|
||||||
|
@return: IP association get response
|
||||||
|
@rtype: Requests.response
|
||||||
|
"""
|
||||||
|
|
||||||
|
url = ('{base_url}/servers/{server_id}/ip_associations/'
|
||||||
|
'{ip_address_id}').format(base_url=self.url,
|
||||||
|
server_id=server_id,
|
||||||
|
ip_address_id=ip_address_id)
|
||||||
|
|
||||||
|
# Currently this call does NOT requires a request body
|
||||||
|
resp = self.request('PUT', url,
|
||||||
|
response_entity_type=IPAssociation,
|
||||||
|
requestslib_kwargs=requestslib_kwargs)
|
||||||
|
return resp
|
||||||
|
|
||||||
|
def delete_ip_association(self, server_id, ip_address_id,
|
||||||
|
requestslib_kwargs=None):
|
||||||
|
"""
|
||||||
|
@summary: Deletes a shared IP association with a server instance
|
||||||
|
@param server_id: server UUID to remove shared IP association
|
||||||
|
@type server_id: str
|
||||||
|
@param ip_address_id: shared IP UUID to disassociate from server
|
||||||
|
@type ip_address_id: str
|
||||||
|
@return: IP association delete response
|
||||||
|
@rtype: Requests.response
|
||||||
|
"""
|
||||||
|
|
||||||
|
url = ('{base_url}/servers/{server_id}/ip_associations/'
|
||||||
|
'{ip_address_id}').format(base_url=self.url,
|
||||||
|
server_id=server_id,
|
||||||
|
ip_address_id=ip_address_id)
|
||||||
|
|
||||||
|
# Currently this call does NOT requires a request body
|
||||||
|
resp = self.request('DELETE', url,
|
||||||
|
requestslib_kwargs=requestslib_kwargs)
|
||||||
|
return resp
|
@ -0,0 +1,29 @@
|
|||||||
|
"""
|
||||||
|
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.compute.common.composites import BaseComputeComposite
|
||||||
|
from cloudcafe.compute.extensions.ip_associations_api.client import \
|
||||||
|
IPAssociationsClient
|
||||||
|
|
||||||
|
|
||||||
|
class IPAssociationsComposite(BaseComputeComposite):
|
||||||
|
|
||||||
|
def __init__(self, auth_composite):
|
||||||
|
super(IPAssociationsComposite, self).__init__(auth_composite)
|
||||||
|
self.client = IPAssociationsClient(
|
||||||
|
**self.compute_auth_composite.client_args)
|
||||||
|
self.config = None
|
||||||
|
self.behaviors = None
|
@ -0,0 +1,25 @@
|
|||||||
|
"""
|
||||||
|
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.compute.common.constants import HTTPResponseCodes
|
||||||
|
|
||||||
|
|
||||||
|
class IPAssociationsResponseCodes(HTTPResponseCodes):
|
||||||
|
"""HTTP IP Associations API Expected Response codes"""
|
||||||
|
|
||||||
|
LIST_IP_ASSOCIATIONS = 200
|
||||||
|
GET_IP_ASSOCIATION = 200
|
||||||
|
CREATE_IP_ASSOCIATION = 201
|
||||||
|
DELETE_IP_ASSOCIATION = 204
|
@ -0,0 +1,15 @@
|
|||||||
|
"""
|
||||||
|
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.
|
||||||
|
"""
|
@ -0,0 +1,42 @@
|
|||||||
|
"""
|
||||||
|
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 AutoMarshallingModel
|
||||||
|
|
||||||
|
|
||||||
|
class IPAssociationRequest(AutoMarshallingModel):
|
||||||
|
"""
|
||||||
|
@summary: IP Association model request object for the Shared IPs Rackspace
|
||||||
|
Compute v2.0 API extension for creating, by an API PUT call,
|
||||||
|
a Shared IP addresses association with a server instance
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
super(IPAssociationRequest, self).__init__()
|
||||||
|
# Currently the IPAssociation is done without the need of a
|
||||||
|
# request body with the following API call,
|
||||||
|
# PUT https://{novaUri}/{version}/servers/{serverId}/ip_associations/
|
||||||
|
# {ipAddressId}
|
||||||
|
# This model is to be updated and used later on with body params
|
||||||
|
|
||||||
|
def _obj_to_json(self):
|
||||||
|
|
||||||
|
body = {}
|
||||||
|
|
||||||
|
main_body = {'ip_association': body}
|
||||||
|
return json.dumps(main_body)
|
@ -0,0 +1,85 @@
|
|||||||
|
"""
|
||||||
|
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 IPAssociation(AutoMarshallingModel):
|
||||||
|
"""
|
||||||
|
@summary: IP Association model response object for the Shared IPs Rackspace
|
||||||
|
Compute v2.0 API extension.
|
||||||
|
@param id_: Server instance shared IP address ID
|
||||||
|
@type id_: str
|
||||||
|
@param address: IPv4 or IPv6 shared IP address
|
||||||
|
@type address: str
|
||||||
|
"""
|
||||||
|
|
||||||
|
IP_ASSOCIATION = 'ip_association'
|
||||||
|
|
||||||
|
def __init__(self, id_=None, address=None, **kwargs):
|
||||||
|
|
||||||
|
# kwargs to be used for checking unexpected response attrs
|
||||||
|
super(IPAssociation, self).__init__()
|
||||||
|
self.id = id_
|
||||||
|
self.address = address
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _json_to_obj(cls, serialized_str):
|
||||||
|
"""
|
||||||
|
@summary: Return IP association object from a JSON serialized string
|
||||||
|
"""
|
||||||
|
|
||||||
|
ret = None
|
||||||
|
json_dict = json.loads(serialized_str)
|
||||||
|
|
||||||
|
# Replacing attribute response names if they are Python reserved words
|
||||||
|
# with a trailing underscore, for ex. id for id_
|
||||||
|
json_dict = cls._replace_dict_key(
|
||||||
|
json_dict, 'id', 'id_', recursion=True)
|
||||||
|
|
||||||
|
if cls.IP_ASSOCIATION in json_dict:
|
||||||
|
ip_address_dict = json_dict.get(cls.IP_ASSOCIATION)
|
||||||
|
ret = IPAssociation(**ip_address_dict)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
class IPAssociations(AutoMarshallingListModel):
|
||||||
|
|
||||||
|
IP_ASSOCIATIONS = 'ip_associations'
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _json_to_obj(cls, serialized_str):
|
||||||
|
"""
|
||||||
|
@summary: Return a list of IP association objects from a JSON
|
||||||
|
serialized string
|
||||||
|
"""
|
||||||
|
ret = cls()
|
||||||
|
json_dict = json.loads(serialized_str)
|
||||||
|
|
||||||
|
# Replacing attribute response names if they are Python reserved words
|
||||||
|
# with a trailing underscore, for ex. id for id_
|
||||||
|
json_dict = cls._replace_dict_key(
|
||||||
|
json_dict, 'id', 'id_', recursion=True)
|
||||||
|
|
||||||
|
if cls.IP_ASSOCIATIONS in json_dict:
|
||||||
|
ip_associations = json_dict.get(cls.IP_ASSOCIATIONS)
|
||||||
|
for ip_association in ip_associations:
|
||||||
|
result = IPAssociation(**ip_association)
|
||||||
|
ret.append(result)
|
||||||
|
return ret
|
@ -0,0 +1,15 @@
|
|||||||
|
"""
|
||||||
|
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.
|
||||||
|
"""
|
@ -0,0 +1,15 @@
|
|||||||
|
"""
|
||||||
|
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.
|
||||||
|
"""
|
@ -0,0 +1,101 @@
|
|||||||
|
"""
|
||||||
|
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
|
||||||
|
|
||||||
|
from cloudcafe.compute.extensions.ip_associations_api.models.request \
|
||||||
|
import IPAssociationRequest
|
||||||
|
from cloudcafe.compute.extensions.ip_associations_api.models.response \
|
||||||
|
import IPAssociation, IPAssociations
|
||||||
|
|
||||||
|
|
||||||
|
ERROR_MSG_REQ = ('JSON unexpected IP Association request serialization\n'
|
||||||
|
'Actual Serialization:\n{request}\n'
|
||||||
|
'Expected Serialization:\n{expected}\n')
|
||||||
|
ERROR_MSG_RESP = ('JSON to Obj response different than expected\n'
|
||||||
|
'Actual Response:\n{response}\n'
|
||||||
|
'Expected Response:\n{expected}\n')
|
||||||
|
|
||||||
|
|
||||||
|
class CreateIPAssociationTest(unittest.TestCase):
|
||||||
|
"""
|
||||||
|
@summary: Test for the IP Associations PUT model object request body
|
||||||
|
"""
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
cls.ip_association_model = IPAssociationRequest()
|
||||||
|
cls.expected_json_output = ('{"ip_association": {}}')
|
||||||
|
|
||||||
|
def test_json_request(self):
|
||||||
|
request_body = self.ip_association_model._obj_to_json()
|
||||||
|
msg = ERROR_MSG_REQ.format(request=request_body,
|
||||||
|
expected=self.expected_json_output)
|
||||||
|
self.assertEqual(request_body, self.expected_json_output, msg)
|
||||||
|
|
||||||
|
|
||||||
|
class GetIPAssociationTest(unittest.TestCase):
|
||||||
|
"""
|
||||||
|
@sumary: Test for the IP Association GET model object response
|
||||||
|
"""
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
# Setting the expected response object
|
||||||
|
get_attrs = dict(id_='1', address='10.1.1.1')
|
||||||
|
cls.expected_response = IPAssociation(**get_attrs)
|
||||||
|
|
||||||
|
# Data simulating the JSON API response
|
||||||
|
cls.api_json_resp = ("""
|
||||||
|
{"ip_association": {"id": "1", "address": "10.1.1.1"}}""")
|
||||||
|
|
||||||
|
def test_json_response(self):
|
||||||
|
response_obj = IPAssociation()._json_to_obj(self.api_json_resp)
|
||||||
|
msg = ERROR_MSG_RESP.format(response=response_obj,
|
||||||
|
expected=self.expected_response)
|
||||||
|
self.assertEqual(response_obj, self.expected_response, msg)
|
||||||
|
|
||||||
|
|
||||||
|
class ListIPAssociationsTest(unittest.TestCase):
|
||||||
|
"""
|
||||||
|
@sumary: Test for the IP Associations (List) GET model object response
|
||||||
|
"""
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
# Setting the expected response object
|
||||||
|
get_attrs1 = dict(id_='1', address='10.1.1.1')
|
||||||
|
get_attrs2 = dict(id_='2', address='10.1.1.2')
|
||||||
|
get_attrs3 = dict(id_='3', address='10.1.1.3')
|
||||||
|
ip_association1 = IPAssociation(**get_attrs1)
|
||||||
|
ip_association2 = IPAssociation(**get_attrs2)
|
||||||
|
ip_association3 = IPAssociation(**get_attrs3)
|
||||||
|
cls.expected_response = [ip_association1, ip_association2,
|
||||||
|
ip_association3]
|
||||||
|
|
||||||
|
# Data simulating the JSON API response
|
||||||
|
cls.api_json_resp = ("""
|
||||||
|
{"ip_associations": [{"id": "1", "address": "10.1.1.1"},
|
||||||
|
{"id": "2", "address": "10.1.1.2"},
|
||||||
|
{"id": "3", "address": "10.1.1.3"}]}
|
||||||
|
""")
|
||||||
|
|
||||||
|
def test_json_response(self):
|
||||||
|
response_obj = IPAssociations()._json_to_obj(self.api_json_resp)
|
||||||
|
msg = ERROR_MSG_RESP.format(response=response_obj,
|
||||||
|
expected=self.expected_response)
|
||||||
|
self.assertEqual(response_obj, self.expected_response, msg)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
Loading…
Reference in New Issue
Block a user