From fc63129340ee223ad86d87207706035f4140a5ba Mon Sep 17 00:00:00 2001 From: Dan Wendlandt Date: Sun, 7 Aug 2011 21:03:24 -0700 Subject: [PATCH 1/4] minor enhancements to quantum client-lib --- quantum/client.py | 70 ++++++++++++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 25 deletions(-) diff --git a/quantum/client.py b/quantum/client.py index ca05236faa..7069786162 100644 --- a/quantum/client.py +++ b/quantum/client.py @@ -57,7 +57,8 @@ class Client(object): attachment_path = "/networks/%s/ports/%s/attachment" def __init__(self, host="127.0.0.1", port=9696, use_ssl=False, tenant=None, - format="xml", testingStub=None, key_file=None, cert_file=None): + format="xml", testingStub=None, key_file=None, cert_file=None, + logger=None): """ Creates a new client to some service. @@ -79,6 +80,7 @@ class Client(object): self.testingStub = testingStub self.key_file = key_file self.cert_file = cert_file + self.logger = logger def get_connection_type(self): """ @@ -132,14 +134,26 @@ class Client(object): else: c = connection_type(self.host, self.port) + if self.logger: + self.logger.debug("Quantum Client Request:\n" \ + + method + " " + action + "\n") + if body: + self.logger.debug(body) + c.request(method, action, body, headers) res = c.getresponse() status_code = self.get_status_code(res) + data = res.read() + + if self.logger: + self.logger.debug("Quantum Client Reply (code = %s) :\n %s" \ + % (str(status_code), data)) + if status_code in (httplib.OK, httplib.CREATED, httplib.ACCEPTED, httplib.NO_CONTENT): - return self.deserialize(res) + return self.deserialize(data, status_code) else: raise Exception("Server returned error: %s" % res.read()) @@ -158,13 +172,18 @@ class Client(object): return response.status def serialize(self, data): - if type(data) is dict: + if data is None: + return None + elif type(data) is dict: return Serializer().serialize(data, self.content_type()) + else: + raise Exception("unable to deserialize object of type = '%s'" \ + % type(data)) - def deserialize(self, data): - if self.get_status_code(data) == 202: - return data.read() - return Serializer().deserialize(data.read(), self.content_type()) + def deserialize(self, data, status_code): + if status_code == 202: + return data + return Serializer().deserialize(data, self.content_type()) def content_type(self, format=None): if not format: @@ -174,21 +193,21 @@ class Client(object): @api_call def list_networks(self): """ - Queries the server for a list of networks + Fetches a list of all networks for a tenant """ return self.do_request("GET", self.networks_path) @api_call - def list_network_details(self, network): + def show_network_details(self, network): """ - Queries the server for the details of a certain network + Fetches the details of a certain network """ return self.do_request("GET", self.network_path % (network)) @api_call def create_network(self, body=None): """ - Creates a new network on the server + Creates a new network """ body = self.serialize(body) return self.do_request("POST", self.networks_path, body=body) @@ -196,7 +215,7 @@ class Client(object): @api_call def update_network(self, network, body=None): """ - Updates a network on the server + Updates a network """ body = self.serialize(body) return self.do_request("PUT", self.network_path % (network), body=body) @@ -204,58 +223,59 @@ class Client(object): @api_call def delete_network(self, network): """ - Deletes a network on the server + Deletes the specified network """ return self.do_request("DELETE", self.network_path % (network)) @api_call def list_ports(self, network): """ - Queries the server for a list of ports on a given network + Fetches a list of ports on a given network """ return self.do_request("GET", self.ports_path % (network)) @api_call - def list_port_details(self, network, port): + def show_port_details(self, network, port): """ - Queries the server for a list of ports on a given network + Fetches the details of a certain port """ return self.do_request("GET", self.port_path % (network, port)) @api_call - def create_port(self, network): + def create_port(self, network, body=None): """ - Creates a new port on a network on the server + Creates a new port on a given network """ - return self.do_request("POST", self.ports_path % (network)) + body = self.serialize(body) + return self.do_request("POST", self.ports_path % (network), body=body) @api_call def delete_port(self, network, port): """ - Deletes a port from a network on the server + Deletes the specified port from a network """ return self.do_request("DELETE", self.port_path % (network, port)) @api_call def set_port_state(self, network, port, body=None): """ - Sets the state of a port on the server + Sets the state of the specified port """ body = self.serialize(body) return self.do_request("PUT", self.port_path % (network, port), body=body) @api_call - def list_port_attachments(self, network, port): + def show_port_attachment(self, network, port): """ - Deletes a port from a network on the server + Fetches the attachment-id associated with the specified port """ return self.do_request("GET", self.attachment_path % (network, port)) @api_call def attach_resource(self, network, port, body=None): """ - Deletes a port from a network on the server + Sets the attachment-id of the specified port """ body = self.serialize(body) return self.do_request("PUT", @@ -264,7 +284,7 @@ class Client(object): @api_call def detach_resource(self, network, port): """ - Deletes a port from a network on the server + Removes the attachment-id of the specified port """ return self.do_request("DELETE", self.attachment_path % (network, port)) From 679b2c601724a9dbb8dbc2e0e0b1db4dab5ea3d7 Mon Sep 17 00:00:00 2001 From: Dan Wendlandt Date: Tue, 9 Aug 2011 09:11:53 -0700 Subject: [PATCH 2/4] rename client_lib unit tests so it is run by ./run_tests.sh, update tests to handle name changes --- tests/unit/api.py | 625 ---------------------------------------------- 1 file changed, 625 deletions(-) delete mode 100644 tests/unit/api.py diff --git a/tests/unit/api.py b/tests/unit/api.py deleted file mode 100644 index aed6c4bacf..0000000000 --- a/tests/unit/api.py +++ /dev/null @@ -1,625 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2011 Cisco Systems -# 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. -# @author: Tyler Smith, Cisco Systems - -import logging -import unittest -import re - -from quantum.common.wsgi import Serializer -from quantum.client import Client - -LOG = logging.getLogger('quantum.tests.test_api') - -# Set a couple tenants to use for testing -TENANT_1 = 'totore' -TENANT_2 = 'totore2' - - -class ServerStub(): - """This class stubs a basic server for the API client to talk to""" - - class Response(object): - """This class stubs a basic response to send the API client""" - def __init__(self, content=None, status=None): - self.content = content - self.status = status - - def read(self): - return self.content - - def status(self): - return status - - # To test error codes, set the host to 10.0.0.1, and the port to the code - def __init__(self, host, port=9696, key_file="", cert_file=""): - self.host = host - self.port = port - self.key_file = key_file - self.cert_file = cert_file - - def request(self, method, action, body, headers): - self.method = method - self.action = action - self.body = body - - def status(self, status=None): - return status or 200 - - def getresponse(self): - res = self.Response(status=self.status()) - - # If the host is 10.0.0.1, return the port as an error code - if self.host == "10.0.0.1": - res.status = self.port - return res - - # Extract important information from the action string to assure sanity - match = re.search('tenants/(.+?)/(.+)\.(json|xml)$', self.action) - - tenant = match.group(1) - path = match.group(2) - format = match.group(3) - - data = {'data': {'method': self.method, 'action': self.action, - 'body': self.body, 'tenant': tenant, 'path': path, - 'format': format, 'key_file': self.key_file, - 'cert_file': self.cert_file}} - - # Serialize it to the proper format so the API client can handle it - if data['data']['format'] == 'json': - res.content = Serializer().serialize(data, "application/json") - else: - res.content = Serializer().serialize(data, "application/xml") - return res - - -class APITest(unittest.TestCase): - - def setUp(self): - """ Setups a test environment for the API client """ - HOST = '127.0.0.1' - PORT = 9696 - USE_SSL = False - - self.client = Client(HOST, PORT, USE_SSL, TENANT_1, 'json', ServerStub) - - def _assert_sanity(self, call, status, method, path, data=[], params={}): - """ Perform common assertions to test the sanity of client requests """ - - # Handle an error case first - if status != 200: - (self.client.host, self.client.port) = ("10.0.0.1", status) - self.assertRaises(Exception, call, *data, **params) - return - - # Make the call, then get the data from the root node and assert it - data = call(*data, **params)['data'] - - self.assertEqual(data['method'], method) - self.assertEqual(data['format'], params['format']) - self.assertEqual(data['tenant'], params['tenant']) - self.assertEqual(data['path'], path) - - return data - - def _test_list_networks(self, tenant=TENANT_1, format='json', status=200): - LOG.debug("_test_list_networks - tenant:%s "\ - "- format:%s - START", format, tenant) - - self._assert_sanity(self.client.list_networks, - status, - "GET", - "networks", - data=[], - params={'tenant': tenant, 'format': format}) - - LOG.debug("_test_list_networks - tenant:%s "\ - "- format:%s - END", format, tenant) - - def _test_list_network_details(self, - tenant=TENANT_1, format='json', status=200): - LOG.debug("_test_list_network_details - tenant:%s "\ - "- format:%s - START", format, tenant) - - self._assert_sanity(self.client.list_network_details, - status, - "GET", - "networks/001", - data=["001"], - params={'tenant': tenant, 'format': format}) - - LOG.debug("_test_list_network_details - tenant:%s "\ - "- format:%s - END", format, tenant) - - def _test_create_network(self, tenant=TENANT_1, format='json', status=200): - LOG.debug("_test_create_network - tenant:%s "\ - "- format:%s - START", format, tenant) - - self._assert_sanity(self.client.create_network, - status, - "POST", - "networks", - data=[{'network': {'net-name': 'testNetwork'}}], - params={'tenant': tenant, 'format': format}) - - LOG.debug("_test_create_network - tenant:%s "\ - "- format:%s - END", format, tenant) - - def _test_update_network(self, tenant=TENANT_1, format='json', status=200): - LOG.debug("_test_update_network - tenant:%s "\ - "- format:%s - START", format, tenant) - - self._assert_sanity(self.client.update_network, - status, - "PUT", - "networks/001", - data=["001", - {'network': {'net-name': 'newName'}}], - params={'tenant': tenant, 'format': format}) - - LOG.debug("_test_update_network - tenant:%s "\ - "- format:%s - END", format, tenant) - - def _test_delete_network(self, tenant=TENANT_1, format='json', status=200): - LOG.debug("_test_delete_network - tenant:%s "\ - "- format:%s - START", format, tenant) - - self._assert_sanity(self.client.delete_network, - status, - "DELETE", - "networks/001", - data=["001"], - params={'tenant': tenant, 'format': format}) - - LOG.debug("_test_delete_network - tenant:%s "\ - "- format:%s - END", format, tenant) - - def _test_list_ports(self, tenant=TENANT_1, format='json', status=200): - LOG.debug("_test_list_ports - tenant:%s "\ - "- format:%s - START", format, tenant) - - self._assert_sanity(self.client.list_ports, - status, - "GET", - "networks/001/ports", - data=["001"], - params={'tenant': tenant, 'format': format}) - - LOG.debug("_test_list_ports - tenant:%s "\ - "- format:%s - END", format, tenant) - - def _test_list_port_details(self, - tenant=TENANT_1, format='json', status=200): - LOG.debug("_test_list_port_details - tenant:%s "\ - "- format:%s - START", format, tenant) - - self._assert_sanity(self.client.list_port_details, - status, - "GET", - "networks/001/ports/001", - data=["001", "001"], - params={'tenant': tenant, 'format': format}) - - LOG.debug("_test_list_port_details - tenant:%s "\ - "- format:%s - END", format, tenant) - - def _test_create_port(self, tenant=TENANT_1, format='json', status=200): - LOG.debug("_test_create_port - tenant:%s "\ - "- format:%s - START", format, tenant) - - self._assert_sanity(self.client.create_port, - status, - "POST", - "networks/001/ports", - data=["001"], - params={'tenant': tenant, 'format': format}) - - LOG.debug("_test_create_port - tenant:%s "\ - "- format:%s - END", format, tenant) - - def _test_delete_port(self, tenant=TENANT_1, format='json', status=200): - LOG.debug("_test_delete_port - tenant:%s "\ - "- format:%s - START", format, tenant) - - self._assert_sanity(self.client.delete_port, - status, - "DELETE", - "networks/001/ports/001", - data=["001", "001"], - params={'tenant': tenant, 'format': format}) - - LOG.debug("_test_delete_port - tenant:%s "\ - "- format:%s - END", format, tenant) - - def _test_set_port_state(self, tenant=TENANT_1, format='json', status=200): - LOG.debug("_test_set_port_state - tenant:%s "\ - "- format:%s - START", format, tenant) - - self._assert_sanity(self.client.set_port_state, - status, - "PUT", - "networks/001/ports/001", - data=["001", "001", - {'port': {'state': 'ACTIVE'}}], - params={'tenant': tenant, 'format': format}) - - LOG.debug("_test_set_port_state - tenant:%s "\ - "- format:%s - END", format, tenant) - - def _test_list_port_attachments(self, - tenant=TENANT_1, format='json', status=200): - LOG.debug("_test_list_port_attachments - tenant:%s "\ - "- format:%s - START", format, tenant) - - self._assert_sanity(self.client.list_port_attachments, - status, - "GET", - "networks/001/ports/001/attachment", - data=["001", "001"], - params={'tenant': tenant, 'format': format}) - - LOG.debug("_test_list_port_attachments - tenant:%s "\ - "- format:%s - END", format, tenant) - - def _test_attach_resource(self, tenant=TENANT_1, - format='json', status=200): - LOG.debug("_test_attach_resource - tenant:%s "\ - "- format:%s - START", format, tenant) - - self._assert_sanity(self.client.attach_resource, - status, - "PUT", - "networks/001/ports/001/attachment", - data=["001", "001", - {'resource': {'id': '1234'}}], - params={'tenant': tenant, 'format': format}) - - LOG.debug("_test_attach_resource - tenant:%s "\ - "- format:%s - END", format, tenant) - - def _test_detach_resource(self, tenant=TENANT_1, - format='json', status=200): - LOG.debug("_test_detach_resource - tenant:%s "\ - "- format:%s - START", format, tenant) - - self._assert_sanity(self.client.detach_resource, - status, - "DELETE", - "networks/001/ports/001/attachment", - data=["001", "001"], - params={'tenant': tenant, 'format': format}) - - LOG.debug("_test_detach_resource - tenant:%s "\ - "- format:%s - END", format, tenant) - - def _test_ssl_certificates(self, tenant=TENANT_1, - format='json', status=200): - LOG.debug("_test_ssl_certificates - tenant:%s "\ - "- format:%s - START", format, tenant) - - # Set SSL, and our cert file - self.client.use_ssl = True - cert_file = "/fake.cert" - self.client.key_file = self.client.cert_file = cert_file - - data = self._assert_sanity(self.client.list_networks, - status, - "GET", - "networks", - data=[], - params={'tenant': tenant, 'format': format}) - - self.assertEquals(data["key_file"], cert_file) - self.assertEquals(data["cert_file"], cert_file) - - LOG.debug("_test_ssl_certificates - tenant:%s "\ - "- format:%s - END", format, tenant) - - def test_list_networks_json(self): - self._test_list_networks(format='json') - - def test_list_networks_xml(self): - self._test_list_networks(format='xml') - - def test_list_networks_alt_tenant(self): - self._test_list_networks(tenant=TENANT_2) - - def test_list_networks_error_470(self): - self._test_list_networks(status=470) - - def test_list_networks_error_401(self): - self._test_list_networks(status=401) - - def test_list_network_details_json(self): - self._test_list_network_details(format='json') - - def test_list_network_details_xml(self): - self._test_list_network_details(format='xml') - - def test_list_network_details_alt_tenant(self): - self._test_list_network_details(tenant=TENANT_2) - - def test_list_network_details_error_470(self): - self._test_list_network_details(status=470) - - def test_list_network_details_error_401(self): - self._test_list_network_details(status=401) - - def test_list_network_details_error_420(self): - self._test_list_network_details(status=420) - - def test_create_network_json(self): - self._test_create_network(format='json') - - def test_create_network_xml(self): - self._test_create_network(format='xml') - - def test_create_network_alt_tenant(self): - self._test_create_network(tenant=TENANT_2) - - def test_create_network_error_470(self): - self._test_create_network(status=470) - - def test_create_network_error_401(self): - self._test_create_network(status=401) - - def test_create_network_error_400(self): - self._test_create_network(status=400) - - def test_create_network_error_422(self): - self._test_create_network(status=422) - - def test_update_network_json(self): - self._test_update_network(format='json') - - def test_update_network_xml(self): - self._test_update_network(format='xml') - - def test_update_network_alt_tenant(self): - self._test_update_network(tenant=TENANT_2) - - def test_update_network_error_470(self): - self._test_update_network(status=470) - - def test_update_network_error_401(self): - self._test_update_network(status=401) - - def test_update_network_error_400(self): - self._test_update_network(status=400) - - def test_update_network_error_420(self): - self._test_update_network(status=420) - - def test_update_network_error_422(self): - self._test_update_network(status=422) - - def test_delete_network_json(self): - self._test_delete_network(format='json') - - def test_delete_network_xml(self): - self._test_delete_network(format='xml') - - def test_delete_network_alt_tenant(self): - self._test_delete_network(tenant=TENANT_2) - - def test_delete_network_error_470(self): - self._test_delete_network(status=470) - - def test_delete_network_error_401(self): - self._test_delete_network(status=401) - - def test_delete_network_error_420(self): - self._test_delete_network(status=420) - - def test_delete_network_error_421(self): - self._test_delete_network(status=421) - - def test_list_ports_json(self): - self._test_list_ports(format='json') - - def test_list_ports_xml(self): - self._test_list_ports(format='xml') - - def test_list_ports_alt_tenant(self): - self._test_list_ports(tenant=TENANT_2) - - def test_list_ports_error_470(self): - self._test_list_ports(status=470) - - def test_list_ports_error_401(self): - self._test_list_ports(status=401) - - def test_list_ports_error_420(self): - self._test_list_ports(status=420) - - def test_list_port_details_json(self): - self._test_list_ports(format='json') - - def test_list_port_details_xml(self): - self._test_list_ports(format='xml') - - def test_list_port_details_alt_tenant(self): - self._test_list_ports(tenant=TENANT_2) - - def test_list_port_details_error_470(self): - self._test_list_port_details(status=470) - - def test_list_port_details_error_401(self): - self._test_list_ports(status=401) - - def test_list_port_details_error_420(self): - self._test_list_ports(status=420) - - def test_list_port_details_error_430(self): - self._test_list_ports(status=430) - - def test_create_port_json(self): - self._test_create_port(format='json') - - def test_create_port_xml(self): - self._test_create_port(format='xml') - - def test_create_port_alt_tenant(self): - self._test_create_port(tenant=TENANT_2) - - def test_create_port_error_470(self): - self._test_create_port(status=470) - - def test_create_port_error_401(self): - self._test_create_port(status=401) - - def test_create_port_error_400(self): - self._test_create_port(status=400) - - def test_create_port_error_420(self): - self._test_create_port(status=420) - - def test_create_port_error_430(self): - self._test_create_port(status=430) - - def test_create_port_error_431(self): - self._test_create_port(status=431) - - def test_delete_port_json(self): - self._test_delete_port(format='json') - - def test_delete_port_xml(self): - self._test_delete_port(format='xml') - - def test_delete_port_alt_tenant(self): - self._test_delete_port(tenant=TENANT_2) - - def test_delete_port_error_470(self): - self._test_delete_port(status=470) - - def test_delete_port_error_401(self): - self._test_delete_port(status=401) - - def test_delete_port_error_420(self): - self._test_delete_port(status=420) - - def test_delete_port_error_430(self): - self._test_delete_port(status=430) - - def test_delete_port_error_432(self): - self._test_delete_port(status=432) - - def test_set_port_state_json(self): - self._test_set_port_state(format='json') - - def test_set_port_state_xml(self): - self._test_set_port_state(format='xml') - - def test_set_port_state_alt_tenant(self): - self._test_set_port_state(tenant=TENANT_2) - - def test_set_port_state_error_470(self): - self._test_set_port_state(status=470) - - def test_set_port_state_error_401(self): - self._test_set_port_state(status=401) - - def test_set_port_state_error_400(self): - self._test_set_port_state(status=400) - - def test_set_port_state_error_420(self): - self._test_set_port_state(status=420) - - def test_set_port_state_error_430(self): - self._test_set_port_state(status=430) - - def test_set_port_state_error_431(self): - self._test_set_port_state(status=431) - - def test_list_port_attachments_json(self): - self._test_list_port_attachments(format='json') - - def test_list_port_attachments_xml(self): - self._test_list_port_attachments(format='xml') - - def test_list_port_attachments_alt_tenant(self): - self._test_list_port_attachments(tenant=TENANT_2) - - def test_list_port_attachments_error_470(self): - self._test_list_port_attachments(status=470) - - def test_list_port_attachments_error_401(self): - self._test_list_port_attachments(status=401) - - def test_list_port_attachments_error_400(self): - self._test_list_port_attachments(status=400) - - def test_list_port_attachments_error_420(self): - self._test_list_port_attachments(status=420) - - def test_list_port_attachments_error_430(self): - self._test_list_port_attachments(status=430) - - def test_attach_resource_json(self): - self._test_attach_resource(format='json') - - def test_attach_resource_xml(self): - self._test_attach_resource(format='xml') - - def test_attach_resource_alt_tenant(self): - self._test_attach_resource(tenant=TENANT_2) - - def test_attach_resource_error_470(self): - self._test_attach_resource(status=470) - - def test_attach_resource_error_401(self): - self._test_attach_resource(status=401) - - def test_attach_resource_error_400(self): - self._test_attach_resource(status=400) - - def test_attach_resource_error_420(self): - self._test_attach_resource(status=420) - - def test_attach_resource_error_430(self): - self._test_attach_resource(status=430) - - def test_attach_resource_error_432(self): - self._test_attach_resource(status=432) - - def test_attach_resource_error_440(self): - self._test_attach_resource(status=440) - - def test_detach_resource_json(self): - self._test_detach_resource(format='json') - - def test_detach_resource_xml(self): - self._test_detach_resource(format='xml') - - def test_detach_resource_alt_tenant(self): - self._test_detach_resource(tenant=TENANT_2) - - def test_detach_resource_error_470(self): - self._test_detach_resource(status=470) - - def test_detach_resource_error_401(self): - self._test_detach_resource(status=401) - - def test_detach_resource_error_420(self): - self._test_detach_resource(status=420) - - def test_detach_resource_error_430(self): - self._test_detach_resource(status=430) - - def test_ssl_certificates(self): - self._test_ssl_certificates() From 40a8473344a9561e53583456bec6d2d93cd2607f Mon Sep 17 00:00:00 2001 From: Dan Wendlandt Date: Tue, 9 Aug 2011 09:15:04 -0700 Subject: [PATCH 3/4] update CLI to use show instead of list for calls that do not return a list --- quantum/cli.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/quantum/cli.py b/quantum/cli.py index a015565d87..6b19f98fcf 100644 --- a/quantum/cli.py +++ b/quantum/cli.py @@ -104,7 +104,7 @@ def detail_net(manager, *args): def api_detail_net(client, *args): tid, nid = args try: - res = client.list_network_details(nid)["networks"]["network"] + res = client.show_network_details(nid)["networks"]["network"] except Exception, e: LOG.error("Failed to get network details: %s" % e) return @@ -119,7 +119,7 @@ def api_detail_net(client, *args): print "Remote Interfaces on Virtual Network:%s\n" % nid for port in ports["ports"]: pid = port["id"] - res = client.list_port_attachments(nid, pid) + res = client.show_port_attachment(nid, pid) LOG.debug(res) remote_iface = res["attachment"] print "\tRemote interface:%s" % remote_iface @@ -214,7 +214,7 @@ def detail_port(manager, *args): def api_detail_port(client, *args): tid, nid, pid = args try: - port = client.list_port_details(nid, pid)["ports"]["port"] + port = client.show_port_details(nid, pid)["ports"]["port"] except Exception, e: LOG.error("Failed to get port details: %s" % e) return From 289e80212ed09276a8abfed40689adb9af2f04f7 Mon Sep 17 00:00:00 2001 From: Dan Wendlandt Date: Tue, 9 Aug 2011 19:15:14 -0700 Subject: [PATCH 4/4] adding renamed client-lib tests --- tests/unit/test_clientlib.py | 625 +++++++++++++++++++++++++++++++++++ 1 file changed, 625 insertions(+) create mode 100644 tests/unit/test_clientlib.py diff --git a/tests/unit/test_clientlib.py b/tests/unit/test_clientlib.py new file mode 100644 index 0000000000..128d069234 --- /dev/null +++ b/tests/unit/test_clientlib.py @@ -0,0 +1,625 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 Cisco Systems +# 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. +# @author: Tyler Smith, Cisco Systems + +import logging +import unittest +import re + +from quantum.common.wsgi import Serializer +from quantum.client import Client + +LOG = logging.getLogger('quantum.tests.test_api') + +# Set a couple tenants to use for testing +TENANT_1 = 'totore' +TENANT_2 = 'totore2' + + +class ServerStub(): + """This class stubs a basic server for the API client to talk to""" + + class Response(object): + """This class stubs a basic response to send the API client""" + def __init__(self, content=None, status=None): + self.content = content + self.status = status + + def read(self): + return self.content + + def status(self): + return status + + # To test error codes, set the host to 10.0.0.1, and the port to the code + def __init__(self, host, port=9696, key_file="", cert_file=""): + self.host = host + self.port = port + self.key_file = key_file + self.cert_file = cert_file + + def request(self, method, action, body, headers): + self.method = method + self.action = action + self.body = body + + def status(self, status=None): + return status or 200 + + def getresponse(self): + res = self.Response(status=self.status()) + + # If the host is 10.0.0.1, return the port as an error code + if self.host == "10.0.0.1": + res.status = self.port + return res + + # Extract important information from the action string to assure sanity + match = re.search('tenants/(.+?)/(.+)\.(json|xml)$', self.action) + + tenant = match.group(1) + path = match.group(2) + format = match.group(3) + + data = {'data': {'method': self.method, 'action': self.action, + 'body': self.body, 'tenant': tenant, 'path': path, + 'format': format, 'key_file': self.key_file, + 'cert_file': self.cert_file}} + + # Serialize it to the proper format so the API client can handle it + if data['data']['format'] == 'json': + res.content = Serializer().serialize(data, "application/json") + else: + res.content = Serializer().serialize(data, "application/xml") + return res + + +class APITest(unittest.TestCase): + + def setUp(self): + """ Setups a test environment for the API client """ + HOST = '127.0.0.1' + PORT = 9696 + USE_SSL = False + + self.client = Client(HOST, PORT, USE_SSL, TENANT_1, 'json', ServerStub) + + def _assert_sanity(self, call, status, method, path, data=[], params={}): + """ Perform common assertions to test the sanity of client requests """ + + # Handle an error case first + if status != 200: + (self.client.host, self.client.port) = ("10.0.0.1", status) + self.assertRaises(Exception, call, *data, **params) + return + + # Make the call, then get the data from the root node and assert it + data = call(*data, **params)['data'] + + self.assertEqual(data['method'], method) + self.assertEqual(data['format'], params['format']) + self.assertEqual(data['tenant'], params['tenant']) + self.assertEqual(data['path'], path) + + return data + + def _test_list_networks(self, tenant=TENANT_1, format='json', status=200): + LOG.debug("_test_list_networks - tenant:%s "\ + "- format:%s - START", format, tenant) + + self._assert_sanity(self.client.list_networks, + status, + "GET", + "networks", + data=[], + params={'tenant': tenant, 'format': format}) + + LOG.debug("_test_list_networks - tenant:%s "\ + "- format:%s - END", format, tenant) + + def _test_show_network_details(self, + tenant=TENANT_1, format='json', status=200): + LOG.debug("_test_show_network_details - tenant:%s "\ + "- format:%s - START", format, tenant) + + self._assert_sanity(self.client.show_network_details, + status, + "GET", + "networks/001", + data=["001"], + params={'tenant': tenant, 'format': format}) + + LOG.debug("_test_show_network_details - tenant:%s "\ + "- format:%s - END", format, tenant) + + def _test_create_network(self, tenant=TENANT_1, format='json', status=200): + LOG.debug("_test_create_network - tenant:%s "\ + "- format:%s - START", format, tenant) + + self._assert_sanity(self.client.create_network, + status, + "POST", + "networks", + data=[{'network': {'net-name': 'testNetwork'}}], + params={'tenant': tenant, 'format': format}) + + LOG.debug("_test_create_network - tenant:%s "\ + "- format:%s - END", format, tenant) + + def _test_update_network(self, tenant=TENANT_1, format='json', status=200): + LOG.debug("_test_update_network - tenant:%s "\ + "- format:%s - START", format, tenant) + + self._assert_sanity(self.client.update_network, + status, + "PUT", + "networks/001", + data=["001", + {'network': {'net-name': 'newName'}}], + params={'tenant': tenant, 'format': format}) + + LOG.debug("_test_update_network - tenant:%s "\ + "- format:%s - END", format, tenant) + + def _test_delete_network(self, tenant=TENANT_1, format='json', status=200): + LOG.debug("_test_delete_network - tenant:%s "\ + "- format:%s - START", format, tenant) + + self._assert_sanity(self.client.delete_network, + status, + "DELETE", + "networks/001", + data=["001"], + params={'tenant': tenant, 'format': format}) + + LOG.debug("_test_delete_network - tenant:%s "\ + "- format:%s - END", format, tenant) + + def _test_list_ports(self, tenant=TENANT_1, format='json', status=200): + LOG.debug("_test_list_ports - tenant:%s "\ + "- format:%s - START", format, tenant) + + self._assert_sanity(self.client.list_ports, + status, + "GET", + "networks/001/ports", + data=["001"], + params={'tenant': tenant, 'format': format}) + + LOG.debug("_test_list_ports - tenant:%s "\ + "- format:%s - END", format, tenant) + + def _test_show_port_details(self, + tenant=TENANT_1, format='json', status=200): + LOG.debug("_test_show_port_details - tenant:%s "\ + "- format:%s - START", format, tenant) + + self._assert_sanity(self.client.show_port_details, + status, + "GET", + "networks/001/ports/001", + data=["001", "001"], + params={'tenant': tenant, 'format': format}) + + LOG.debug("_test_show_port_details - tenant:%s "\ + "- format:%s - END", format, tenant) + + def _test_create_port(self, tenant=TENANT_1, format='json', status=200): + LOG.debug("_test_create_port - tenant:%s "\ + "- format:%s - START", format, tenant) + + self._assert_sanity(self.client.create_port, + status, + "POST", + "networks/001/ports", + data=["001"], + params={'tenant': tenant, 'format': format}) + + LOG.debug("_test_create_port - tenant:%s "\ + "- format:%s - END", format, tenant) + + def _test_delete_port(self, tenant=TENANT_1, format='json', status=200): + LOG.debug("_test_delete_port - tenant:%s "\ + "- format:%s - START", format, tenant) + + self._assert_sanity(self.client.delete_port, + status, + "DELETE", + "networks/001/ports/001", + data=["001", "001"], + params={'tenant': tenant, 'format': format}) + + LOG.debug("_test_delete_port - tenant:%s "\ + "- format:%s - END", format, tenant) + + def _test_set_port_state(self, tenant=TENANT_1, format='json', status=200): + LOG.debug("_test_set_port_state - tenant:%s "\ + "- format:%s - START", format, tenant) + + self._assert_sanity(self.client.set_port_state, + status, + "PUT", + "networks/001/ports/001", + data=["001", "001", + {'port': {'state': 'ACTIVE'}}], + params={'tenant': tenant, 'format': format}) + + LOG.debug("_test_set_port_state - tenant:%s "\ + "- format:%s - END", format, tenant) + + def _test_show_port_attachment(self, + tenant=TENANT_1, format='json', status=200): + LOG.debug("_test_show_port_attachment - tenant:%s "\ + "- format:%s - START", format, tenant) + + self._assert_sanity(self.client.show_port_attachment, + status, + "GET", + "networks/001/ports/001/attachment", + data=["001", "001"], + params={'tenant': tenant, 'format': format}) + + LOG.debug("_test_show_port_attachment - tenant:%s "\ + "- format:%s - END", format, tenant) + + def _test_attach_resource(self, tenant=TENANT_1, + format='json', status=200): + LOG.debug("_test_attach_resource - tenant:%s "\ + "- format:%s - START", format, tenant) + + self._assert_sanity(self.client.attach_resource, + status, + "PUT", + "networks/001/ports/001/attachment", + data=["001", "001", + {'resource': {'id': '1234'}}], + params={'tenant': tenant, 'format': format}) + + LOG.debug("_test_attach_resource - tenant:%s "\ + "- format:%s - END", format, tenant) + + def _test_detach_resource(self, tenant=TENANT_1, + format='json', status=200): + LOG.debug("_test_detach_resource - tenant:%s "\ + "- format:%s - START", format, tenant) + + self._assert_sanity(self.client.detach_resource, + status, + "DELETE", + "networks/001/ports/001/attachment", + data=["001", "001"], + params={'tenant': tenant, 'format': format}) + + LOG.debug("_test_detach_resource - tenant:%s "\ + "- format:%s - END", format, tenant) + + def _test_ssl_certificates(self, tenant=TENANT_1, + format='json', status=200): + LOG.debug("_test_ssl_certificates - tenant:%s "\ + "- format:%s - START", format, tenant) + + # Set SSL, and our cert file + self.client.use_ssl = True + cert_file = "/fake.cert" + self.client.key_file = self.client.cert_file = cert_file + + data = self._assert_sanity(self.client.list_networks, + status, + "GET", + "networks", + data=[], + params={'tenant': tenant, 'format': format}) + + self.assertEquals(data["key_file"], cert_file) + self.assertEquals(data["cert_file"], cert_file) + + LOG.debug("_test_ssl_certificates - tenant:%s "\ + "- format:%s - END", format, tenant) + + def test_list_networks_json(self): + self._test_list_networks(format='json') + + def test_list_networks_xml(self): + self._test_list_networks(format='xml') + + def test_list_networks_alt_tenant(self): + self._test_list_networks(tenant=TENANT_2) + + def test_list_networks_error_470(self): + self._test_list_networks(status=470) + + def test_list_networks_error_401(self): + self._test_list_networks(status=401) + + def test_show_network_details_json(self): + self._test_show_network_details(format='json') + + def test_show_network_details_xml(self): + self._test_show_network_details(format='xml') + + def test_show_network_details_alt_tenant(self): + self._test_show_network_details(tenant=TENANT_2) + + def test_show_network_details_error_470(self): + self._test_show_network_details(status=470) + + def test_show_network_details_error_401(self): + self._test_show_network_details(status=401) + + def test_show_network_details_error_420(self): + self._test_show_network_details(status=420) + + def test_create_network_json(self): + self._test_create_network(format='json') + + def test_create_network_xml(self): + self._test_create_network(format='xml') + + def test_create_network_alt_tenant(self): + self._test_create_network(tenant=TENANT_2) + + def test_create_network_error_470(self): + self._test_create_network(status=470) + + def test_create_network_error_401(self): + self._test_create_network(status=401) + + def test_create_network_error_400(self): + self._test_create_network(status=400) + + def test_create_network_error_422(self): + self._test_create_network(status=422) + + def test_update_network_json(self): + self._test_update_network(format='json') + + def test_update_network_xml(self): + self._test_update_network(format='xml') + + def test_update_network_alt_tenant(self): + self._test_update_network(tenant=TENANT_2) + + def test_update_network_error_470(self): + self._test_update_network(status=470) + + def test_update_network_error_401(self): + self._test_update_network(status=401) + + def test_update_network_error_400(self): + self._test_update_network(status=400) + + def test_update_network_error_420(self): + self._test_update_network(status=420) + + def test_update_network_error_422(self): + self._test_update_network(status=422) + + def test_delete_network_json(self): + self._test_delete_network(format='json') + + def test_delete_network_xml(self): + self._test_delete_network(format='xml') + + def test_delete_network_alt_tenant(self): + self._test_delete_network(tenant=TENANT_2) + + def test_delete_network_error_470(self): + self._test_delete_network(status=470) + + def test_delete_network_error_401(self): + self._test_delete_network(status=401) + + def test_delete_network_error_420(self): + self._test_delete_network(status=420) + + def test_delete_network_error_421(self): + self._test_delete_network(status=421) + + def test_list_ports_json(self): + self._test_list_ports(format='json') + + def test_list_ports_xml(self): + self._test_list_ports(format='xml') + + def test_list_ports_alt_tenant(self): + self._test_list_ports(tenant=TENANT_2) + + def test_list_ports_error_470(self): + self._test_list_ports(status=470) + + def test_list_ports_error_401(self): + self._test_list_ports(status=401) + + def test_list_ports_error_420(self): + self._test_list_ports(status=420) + + def test_show_port_details_json(self): + self._test_list_ports(format='json') + + def test_show_port_details_xml(self): + self._test_list_ports(format='xml') + + def test_show_port_details_alt_tenant(self): + self._test_list_ports(tenant=TENANT_2) + + def test_show_port_details_error_470(self): + self._test_show_port_details(status=470) + + def test_show_port_details_error_401(self): + self._test_show_port_details(status=401) + + def test_show_port_details_error_420(self): + self._test_show_port_details(status=420) + + def test_show_port_details_error_430(self): + self._test_show_port_details(status=430) + + def test_create_port_json(self): + self._test_create_port(format='json') + + def test_create_port_xml(self): + self._test_create_port(format='xml') + + def test_create_port_alt_tenant(self): + self._test_create_port(tenant=TENANT_2) + + def test_create_port_error_470(self): + self._test_create_port(status=470) + + def test_create_port_error_401(self): + self._test_create_port(status=401) + + def test_create_port_error_400(self): + self._test_create_port(status=400) + + def test_create_port_error_420(self): + self._test_create_port(status=420) + + def test_create_port_error_430(self): + self._test_create_port(status=430) + + def test_create_port_error_431(self): + self._test_create_port(status=431) + + def test_delete_port_json(self): + self._test_delete_port(format='json') + + def test_delete_port_xml(self): + self._test_delete_port(format='xml') + + def test_delete_port_alt_tenant(self): + self._test_delete_port(tenant=TENANT_2) + + def test_delete_port_error_470(self): + self._test_delete_port(status=470) + + def test_delete_port_error_401(self): + self._test_delete_port(status=401) + + def test_delete_port_error_420(self): + self._test_delete_port(status=420) + + def test_delete_port_error_430(self): + self._test_delete_port(status=430) + + def test_delete_port_error_432(self): + self._test_delete_port(status=432) + + def test_set_port_state_json(self): + self._test_set_port_state(format='json') + + def test_set_port_state_xml(self): + self._test_set_port_state(format='xml') + + def test_set_port_state_alt_tenant(self): + self._test_set_port_state(tenant=TENANT_2) + + def test_set_port_state_error_470(self): + self._test_set_port_state(status=470) + + def test_set_port_state_error_401(self): + self._test_set_port_state(status=401) + + def test_set_port_state_error_400(self): + self._test_set_port_state(status=400) + + def test_set_port_state_error_420(self): + self._test_set_port_state(status=420) + + def test_set_port_state_error_430(self): + self._test_set_port_state(status=430) + + def test_set_port_state_error_431(self): + self._test_set_port_state(status=431) + + def test_show_port_attachment_json(self): + self._test_show_port_attachment(format='json') + + def test_show_port_attachment_xml(self): + self._test_show_port_attachment(format='xml') + + def test_show_port_attachment_alt_tenant(self): + self._test_show_port_attachment(tenant=TENANT_2) + + def test_show_port_attachment_error_470(self): + self._test_show_port_attachment(status=470) + + def test_show_port_attachment_error_401(self): + self._test_show_port_attachment(status=401) + + def test_show_port_attachment_error_400(self): + self._test_show_port_attachment(status=400) + + def test_show_port_attachment_error_420(self): + self._test_show_port_attachment(status=420) + + def test_show_port_attachment_error_430(self): + self._test_show_port_attachment(status=430) + + def test_attach_resource_json(self): + self._test_attach_resource(format='json') + + def test_attach_resource_xml(self): + self._test_attach_resource(format='xml') + + def test_attach_resource_alt_tenant(self): + self._test_attach_resource(tenant=TENANT_2) + + def test_attach_resource_error_470(self): + self._test_attach_resource(status=470) + + def test_attach_resource_error_401(self): + self._test_attach_resource(status=401) + + def test_attach_resource_error_400(self): + self._test_attach_resource(status=400) + + def test_attach_resource_error_420(self): + self._test_attach_resource(status=420) + + def test_attach_resource_error_430(self): + self._test_attach_resource(status=430) + + def test_attach_resource_error_432(self): + self._test_attach_resource(status=432) + + def test_attach_resource_error_440(self): + self._test_attach_resource(status=440) + + def test_detach_resource_json(self): + self._test_detach_resource(format='json') + + def test_detach_resource_xml(self): + self._test_detach_resource(format='xml') + + def test_detach_resource_alt_tenant(self): + self._test_detach_resource(tenant=TENANT_2) + + def test_detach_resource_error_470(self): + self._test_detach_resource(status=470) + + def test_detach_resource_error_401(self): + self._test_detach_resource(status=401) + + def test_detach_resource_error_420(self): + self._test_detach_resource(status=420) + + def test_detach_resource_error_430(self): + self._test_detach_resource(status=430) + + def test_ssl_certificates(self): + self._test_ssl_certificates()