From b2f7ae2ad7762531a9200799de4be9849cd3b42c Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Thu, 21 Jul 2011 09:43:25 -0400 Subject: Added LimitsXMLSerializer Added LimitsViewBuidlerV11Test test case --- nova/api/openstack/limits.py | 61 +++++++++- nova/tests/api/openstack/test_limits.py | 206 ++++++++++++++++++++++++++++++++ 2 files changed, 265 insertions(+), 2 deletions(-) diff --git a/nova/api/openstack/limits.py b/nova/api/openstack/limits.py index bc76547d8..86afa3b62 100644 --- a/nova/api/openstack/limits.py +++ b/nova/api/openstack/limits.py @@ -25,6 +25,7 @@ import re import time import urllib import webob.exc +from xml.dom import minidom from collections import defaultdict @@ -76,6 +77,58 @@ class LimitsControllerV11(LimitsController): return limits_views.ViewBuilderV11() +class LimitsXMLSerializer(wsgi.XMLDictSerializer): + + xmlns = wsgi.XMLNS_V11 + + def __init__(self): + pass + + def _create_rates_node(self, xml_doc, rates): + rates_node = xml_doc.createElement('rates') + for rate in rates: + rate_node = xml_doc.createElement('rate') + rate_node.setAttribute('uri', rate['uri']) + rate_node.setAttribute('regex', rate['regex']) + + for limit in rate['limit']: + limit_node = xml_doc.createElement('limit') + limit_node.setAttribute('value', str(limit['value'])) + limit_node.setAttribute('verb', limit['verb']) + limit_node.setAttribute('remaining', str(limit['remaining'])) + limit_node.setAttribute('unit', limit['unit']) + limit_node.setAttribute('next-available', + str(limit['next-available'])) + rate_node.appendChild(limit_node) + + rates_node.appendChild(rate_node) + return rates_node + + def _create_absolute_node(self, xml_doc, absolutes): + absolute_node = xml_doc.createElement('absolute') + for key, value in absolutes.iteritems(): + limit_node = xml_doc.createElement('limit') + limit_node.setAttribute('name', key) + limit_node.setAttribute('value', str(value)) + absolute_node.appendChild(limit_node) + return absolute_node + + def _limits_to_xml(self, xml_doc, limits): + limits_node = xml_doc.createElement('limits') + rates_node = self._create_rates_node(xml_doc, limits['rate']) + limits_node.appendChild(rates_node) + + absolute_node = self._create_absolute_node(xml_doc, limits['absolute']) + limits_node.appendChild(absolute_node) + + return limits_node + + def index(self, limits_dict): + xml_doc = minidom.Document() + node = self._limits_to_xml(xml_doc, limits_dict['limits']) + return self.to_xml_string(node, False) + + def create_resource(version='1.0'): controller = { '1.0': LimitsControllerV10, @@ -97,9 +150,13 @@ def create_resource(version='1.0'): }, } + xml_serializer = { + '1.0': wsgi.XMLDictSerializer(xmlns=xmlns, metadata=metadata), + '1.1': LimitsXMLSerializer(), + }[version] + body_serializers = { - 'application/xml': wsgi.XMLDictSerializer(xmlns=xmlns, - metadata=metadata), + 'application/xml': xml_serializer, } serializer = wsgi.ResponseSerializer(body_serializers) diff --git a/nova/tests/api/openstack/test_limits.py b/nova/tests/api/openstack/test_limits.py index 76363450d..9859c17f8 100644 --- a/nova/tests/api/openstack/test_limits.py +++ b/nova/tests/api/openstack/test_limits.py @@ -27,6 +27,7 @@ import webob from xml.dom.minidom import parseString +from nova import test import nova.context from nova.api.openstack import limits @@ -904,3 +905,208 @@ class WsgiLimiterProxyTest(BaseLimitTestSuite): "made to /delayed every minute.") self.assertEqual((delay, error), expected) + + +class LimitsViewBuilderV11Test(test.TestCase): + + def setUp(self): + self.view_builder = self._get_view_builder() + + def tearDown(self): + pass + + def _get_view_builder(self): + views = nova.api.openstack.views + view_builder = views.limits.ViewBuilderV11() + return view_builder + + def _get_rate_limits(self): + rate_limits = [ + { + "URI": "*", + "regex": ".*", + "value": 10, + "verb": "POST", + "remaining": 2, + "unit": "MINUTE", + "resetTime": "2011-12-15T22:42:45Z" + }, + { + "URI": "*/servers", + "regex": "^/servers", + "value": 50, + "verb": "POST", + "remaining": 10, + "unit": "DAY", + "resetTime": "2011-12-15T22:42:45Z" + }, + ] + + return rate_limits + + def _get_absolute_limits(self): + absolute_limits = { + "metadata_items": 1, + "injected_files": 5, + "injected_file_content_bytes": 5, + } + + return absolute_limits + + def test_build_limits(self): + expected_limits = { + "limits": { + "rate": [ + { + "uri": "*", + "regex": ".*", + "limit": [ + { + "value": 10, + "verb": "POST", + "remaining": 2, + "unit": "MINUTE", + "next-available": "2011-12-15T22:42:45Z" + }, + ] + }, + { + "uri": "*/servers", + "regex": "^/servers", + "limit": [ + { + "value": 50, + "verb": "POST", + "remaining": 10, + "unit": "DAY", + "next-available": "2011-12-15T22:42:45Z" + }, + ] + }, + ], + "absolute": { + "maxServerMeta": 1, + "maxImageMeta": 1, + "maxPersonality": 5, + "maxPersonalitySize": 5 + } + } + } + + output = self.view_builder.build(self._get_rate_limits(), + self._get_absolute_limits()) + self.assertDictMatch(output, expected_limits) + + def test_build_limits_empty_limits(self): + expected_limits = { + "limits": { + "rate": [], + "absolute": {} + } + } + + abs_limits = {} + rate_limits = [] + output = self.view_builder.build(rate_limits, abs_limits) + self.assertDictMatch(output, expected_limits) + + +class LimitsXMLSerializationTest(test.TestCase): + + def setUp(self): + self.maxDiff = None + + def tearDown(self): + pass + + def test_index(self): + serializer = limits.LimitsXMLSerializer() + + fixture = { + "limits": { + "rate": [ + { + "uri": "*", + "regex": ".*", + "limit": [ + { + "value": 10, + "verb": "POST", + "remaining": 2, + "unit": "MINUTE", + "next-available": "2011-12-15T22:42:45Z" + }, + ] + }, + { + "uri": "*/servers", + "regex": "^/servers", + "limit": [ + { + "value": 50, + "verb": "POST", + "remaining": 10, + "unit": "DAY", + "next-available": "2011-12-15T22:42:45Z" + }, + ] + }, + ], + "absolute": { + "maxServerMeta": 1, + "maxImageMeta": 1, + "maxPersonality": 5, + "maxPersonalitySize": 10240 + } + } + } + + output = serializer.serialize(fixture, 'index') + actual = parseString(output.replace(" ", "")) + + expected = parseString(""" + + + + + + + + + + + + + + + + + """.replace(" ", "") % (locals())) + + self.assertEqual(expected.toxml(), actual.toxml()) + + def test_index_no_limits(self): + serializer = limits.LimitsXMLSerializer() + + fixture = { + "limits": { + "rate": [], + "absolute": {} + } + } + + output = serializer.serialize(fixture, 'index') + actual = parseString(output.replace(" ", "")) + + expected = parseString(""" + + + + + """.replace(" ", "") % (locals())) + + self.assertEqual(expected.toxml(), actual.toxml()) -- cgit From 210038b8d36e74ecfa791c1a25b5a8529cecdca0 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Thu, 21 Jul 2011 11:54:03 -0400 Subject: cleanup --- nova/tests/api/openstack/test_limits.py | 39 +++++++++++---------------------- 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/nova/tests/api/openstack/test_limits.py b/nova/tests/api/openstack/test_limits.py index 9859c17f8..4d032b093 100644 --- a/nova/tests/api/openstack/test_limits.py +++ b/nova/tests/api/openstack/test_limits.py @@ -25,11 +25,11 @@ import time import unittest import webob -from xml.dom.minidom import parseString +import xml.dom.minidom -from nova import test import nova.context from nova.api.openstack import limits +from nova import test TEST_LIMITS = [ @@ -910,18 +910,8 @@ class WsgiLimiterProxyTest(BaseLimitTestSuite): class LimitsViewBuilderV11Test(test.TestCase): def setUp(self): - self.view_builder = self._get_view_builder() - - def tearDown(self): - pass - - def _get_view_builder(self): - views = nova.api.openstack.views - view_builder = views.limits.ViewBuilderV11() - return view_builder - - def _get_rate_limits(self): - rate_limits = [ + self.view_builder = views.limits.ViewBuilderV11() + self.rate_limits = [ { "URI": "*", "regex": ".*", @@ -941,17 +931,14 @@ class LimitsViewBuilderV11Test(test.TestCase): "resetTime": "2011-12-15T22:42:45Z" }, ] - - return rate_limits - - def _get_absolute_limits(self): - absolute_limits = { + self.absolute_limits = { "metadata_items": 1, "injected_files": 5, "injected_file_content_bytes": 5, } - return absolute_limits + def tearDown(self): + pass def test_build_limits(self): expected_limits = { @@ -993,8 +980,8 @@ class LimitsViewBuilderV11Test(test.TestCase): } } - output = self.view_builder.build(self._get_rate_limits(), - self._get_absolute_limits()) + output = self.view_builder.build(self.rate_limits, + self.absolute_limits) self.assertDictMatch(output, expected_limits) def test_build_limits_empty_limits(self): @@ -1062,7 +1049,7 @@ class LimitsXMLSerializationTest(test.TestCase): } output = serializer.serialize(fixture, 'index') - actual = parseString(output.replace(" ", "")) + actual = minidom.parseString(output.replace(" ", "")) expected = parseString(""" @@ -1085,7 +1072,7 @@ class LimitsXMLSerializationTest(test.TestCase): - """.replace(" ", "") % (locals())) + """.replace(" ", "")) self.assertEqual(expected.toxml(), actual.toxml()) @@ -1100,13 +1087,13 @@ class LimitsXMLSerializationTest(test.TestCase): } output = serializer.serialize(fixture, 'index') - actual = parseString(output.replace(" ", "")) + actual = minidom.parseString(output.replace(" ", "")) expected = parseString(""" - """.replace(" ", "") % (locals())) + """.replace(" ", "")) self.assertEqual(expected.toxml(), actual.toxml()) -- cgit From ca285e0cdede6f3332856e63d7828616aefdc4cc Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Thu, 21 Jul 2011 11:57:44 -0400 Subject: minor cleanup --- nova/tests/api/openstack/test_limits.py | 1 - 1 file changed, 1 deletion(-) diff --git a/nova/tests/api/openstack/test_limits.py b/nova/tests/api/openstack/test_limits.py index 4d032b093..d9f0ac942 100644 --- a/nova/tests/api/openstack/test_limits.py +++ b/nova/tests/api/openstack/test_limits.py @@ -24,7 +24,6 @@ import stubout import time import unittest import webob - import xml.dom.minidom import nova.context -- cgit From f7988845281ab2fb963eaf059a6308917db79ff8 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Thu, 21 Jul 2011 12:51:29 -0400 Subject: Fixed import issue --- nova/tests/api/openstack/test_limits.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/nova/tests/api/openstack/test_limits.py b/nova/tests/api/openstack/test_limits.py index d9f0ac942..9edcf1b73 100644 --- a/nova/tests/api/openstack/test_limits.py +++ b/nova/tests/api/openstack/test_limits.py @@ -24,10 +24,11 @@ import stubout import time import unittest import webob -import xml.dom.minidom +from xml.dom import minidom import nova.context from nova.api.openstack import limits +from nova.api.openstack import views from nova import test @@ -166,7 +167,7 @@ class LimitsControllerV10Test(BaseLimitTestSuite): request = self._get_index_request("application/xml") response = request.get_response(self.controller) - expected = parseString(""" + expected = minidom.parseString(""" @@ -174,7 +175,7 @@ class LimitsControllerV10Test(BaseLimitTestSuite): """.replace(" ", "")) - body = parseString(response.body.replace(" ", "")) + body = minidom.parseString(response.body.replace(" ", "")) self.assertEqual(expected.toxml(), body.toxml()) @@ -184,7 +185,7 @@ class LimitsControllerV10Test(BaseLimitTestSuite): request = self._populate_limits(request) response = request.get_response(self.controller) - expected = parseString(""" + expected = minidom.parseString(""" @@ -196,7 +197,7 @@ class LimitsControllerV10Test(BaseLimitTestSuite): """.replace(" ", "")) - body = parseString(response.body.replace(" ", "")) + body = minidom.parseString(response.body.replace(" ", "")) self.assertEqual(expected.toxml(), body.toxml()) @@ -458,7 +459,7 @@ class LimitMiddlewareTest(BaseLimitTestSuite): response = request.get_response(self.app) self.assertEqual(response.status_int, 403) - root = parseString(response.body).childNodes[0] + root = minidom.parseString(response.body).childNodes[0] expected = "Only 1 GET request(s) can be made to * every minute." details = root.getElementsByTagName("details") @@ -1050,7 +1051,7 @@ class LimitsXMLSerializationTest(test.TestCase): output = serializer.serialize(fixture, 'index') actual = minidom.parseString(output.replace(" ", "")) - expected = parseString(""" + expected = minidom.parseString(""" @@ -1088,7 +1089,7 @@ class LimitsXMLSerializationTest(test.TestCase): output = serializer.serialize(fixture, 'index') actual = minidom.parseString(output.replace(" ", "")) - expected = parseString(""" + expected = minidom.parseString(""" -- cgit From c1b4dd1b8e3a8043b494854bc9ddd5e6cd335ef0 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Thu, 21 Jul 2011 16:16:34 -0400 Subject: Updated time-available to be correct format Fixed old tests to respect this --- nova/api/openstack/views/limits.py | 5 ++++- nova/tests/api/openstack/test_limits.py | 19 ++++++++++--------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/nova/api/openstack/views/limits.py b/nova/api/openstack/views/limits.py index 934b4921a..e34d47e63 100644 --- a/nova/api/openstack/views/limits.py +++ b/nova/api/openstack/views/limits.py @@ -15,9 +15,11 @@ # License for the specific language governing permissions and limitations # under the License. +import datetime import time from nova.api.openstack import common +from nova import utils class ViewBuilder(object): @@ -113,10 +115,11 @@ class ViewBuilderV11(ViewBuilder): return limits def _build_rate_limit(self, rate_limit): + next_avail = datetime.datetime.fromtimestamp(rate_limit["resetTime"]) return { "verb": rate_limit["verb"], "value": rate_limit["value"], "remaining": int(rate_limit["remaining"]), "unit": rate_limit["unit"], - "next-available": rate_limit["resetTime"], + "next-available": utils.isotime(at=next_avail), } diff --git a/nova/tests/api/openstack/test_limits.py b/nova/tests/api/openstack/test_limits.py index 9edcf1b73..6a3f7e79a 100644 --- a/nova/tests/api/openstack/test_limits.py +++ b/nova/tests/api/openstack/test_limits.py @@ -211,6 +211,7 @@ class LimitsControllerV11Test(BaseLimitTestSuite): """Run before each test.""" BaseLimitTestSuite.setUp(self) self.controller = limits.create_resource('1.1') + self.maxDiff = None def _get_index_request(self, accept_header="application/json"): """Helper to set routing arguments.""" @@ -267,14 +268,14 @@ class LimitsControllerV11Test(BaseLimitTestSuite): "limit": [ { "verb": "GET", - "next-available": 0, + "next-available": "1969-12-31T19:00:00Z", "unit": "MINUTE", "value": 10, "remaining": 10, }, { "verb": "POST", - "next-available": 0, + "next-available": "1969-12-31T19:00:00Z", "unit": "HOUR", "value": 5, "remaining": 5, @@ -287,7 +288,7 @@ class LimitsControllerV11Test(BaseLimitTestSuite): "limit": [ { "verb": "GET", - "next-available": 0, + "next-available": "1969-12-31T19:00:00Z", "unit": "MINUTE", "value": 5, "remaining": 5, @@ -329,7 +330,7 @@ class LimitsControllerV11Test(BaseLimitTestSuite): "limit": [ { "verb": "GET", - "next-available": 0, + "next-available": "1969-12-31T19:00:00Z", "unit": "MINUTE", "value": 10, "remaining": 10, @@ -342,7 +343,7 @@ class LimitsControllerV11Test(BaseLimitTestSuite): "limit": [ { "verb": "GET", - "next-available": 0, + "next-available": "1969-12-31T19:00:00Z", "unit": "MINUTE", "value": 10, "remaining": 10, @@ -919,7 +920,7 @@ class LimitsViewBuilderV11Test(test.TestCase): "verb": "POST", "remaining": 2, "unit": "MINUTE", - "resetTime": "2011-12-15T22:42:45Z" + "resetTime": 1311272226 }, { "URI": "*/servers", @@ -928,7 +929,7 @@ class LimitsViewBuilderV11Test(test.TestCase): "verb": "POST", "remaining": 10, "unit": "DAY", - "resetTime": "2011-12-15T22:42:45Z" + "resetTime": 1311272226 }, ] self.absolute_limits = { @@ -953,7 +954,7 @@ class LimitsViewBuilderV11Test(test.TestCase): "verb": "POST", "remaining": 2, "unit": "MINUTE", - "next-available": "2011-12-15T22:42:45Z" + "next-available": "2011-07-21T14:17:06Z" }, ] }, @@ -966,7 +967,7 @@ class LimitsViewBuilderV11Test(test.TestCase): "verb": "POST", "remaining": 10, "unit": "DAY", - "next-available": "2011-12-15T22:42:45Z" + "next-available": "2011-07-21T14:17:06Z" }, ] }, -- cgit From f6514ba9fbb6b3c1939bde6ba081f632b3d0a24f Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Thu, 21 Jul 2011 17:11:57 -0400 Subject: updated next-available to use utc time --- nova/api/openstack/views/limits.py | 2 +- nova/tests/api/openstack/test_limits.py | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/nova/api/openstack/views/limits.py b/nova/api/openstack/views/limits.py index e34d47e63..c7163e33c 100644 --- a/nova/api/openstack/views/limits.py +++ b/nova/api/openstack/views/limits.py @@ -115,7 +115,7 @@ class ViewBuilderV11(ViewBuilder): return limits def _build_rate_limit(self, rate_limit): - next_avail = datetime.datetime.fromtimestamp(rate_limit["resetTime"]) + next_avail = datetime.datetime.utcfromtimestamp(rate_limit["resetTime"]) return { "verb": rate_limit["verb"], "value": rate_limit["value"], diff --git a/nova/tests/api/openstack/test_limits.py b/nova/tests/api/openstack/test_limits.py index 6a3f7e79a..8a3fe681a 100644 --- a/nova/tests/api/openstack/test_limits.py +++ b/nova/tests/api/openstack/test_limits.py @@ -268,14 +268,14 @@ class LimitsControllerV11Test(BaseLimitTestSuite): "limit": [ { "verb": "GET", - "next-available": "1969-12-31T19:00:00Z", + "next-available": "1970-01-01T00:00:00Z", "unit": "MINUTE", "value": 10, "remaining": 10, }, { "verb": "POST", - "next-available": "1969-12-31T19:00:00Z", + "next-available": "1970-01-01T00:00:00Z", "unit": "HOUR", "value": 5, "remaining": 5, @@ -288,7 +288,7 @@ class LimitsControllerV11Test(BaseLimitTestSuite): "limit": [ { "verb": "GET", - "next-available": "1969-12-31T19:00:00Z", + "next-available": "1970-01-01T00:00:00Z", "unit": "MINUTE", "value": 5, "remaining": 5, @@ -330,7 +330,7 @@ class LimitsControllerV11Test(BaseLimitTestSuite): "limit": [ { "verb": "GET", - "next-available": "1969-12-31T19:00:00Z", + "next-available": "1970-01-01T00:00:00Z", "unit": "MINUTE", "value": 10, "remaining": 10, @@ -343,7 +343,7 @@ class LimitsControllerV11Test(BaseLimitTestSuite): "limit": [ { "verb": "GET", - "next-available": "1969-12-31T19:00:00Z", + "next-available": "1970-01-01T00:00:00Z", "unit": "MINUTE", "value": 10, "remaining": 10, @@ -954,7 +954,7 @@ class LimitsViewBuilderV11Test(test.TestCase): "verb": "POST", "remaining": 2, "unit": "MINUTE", - "next-available": "2011-07-21T14:17:06Z" + "next-available": "2011-07-21T18:17:06Z" }, ] }, @@ -967,7 +967,7 @@ class LimitsViewBuilderV11Test(test.TestCase): "verb": "POST", "remaining": 10, "unit": "DAY", - "next-available": "2011-07-21T14:17:06Z" + "next-available": "2011-07-21T18:17:06Z" }, ] }, -- cgit From fe708ae810efd17da70659076faa9c2f3b544d3b Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Thu, 21 Jul 2011 17:13:12 -0400 Subject: pep8 --- nova/api/openstack/views/limits.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nova/api/openstack/views/limits.py b/nova/api/openstack/views/limits.py index c7163e33c..f603d7cb4 100644 --- a/nova/api/openstack/views/limits.py +++ b/nova/api/openstack/views/limits.py @@ -115,7 +115,8 @@ class ViewBuilderV11(ViewBuilder): return limits def _build_rate_limit(self, rate_limit): - next_avail = datetime.datetime.utcfromtimestamp(rate_limit["resetTime"]) + next_avail = \ + datetime.datetime.utcfromtimestamp(rate_limit["resetTime"]) return { "verb": rate_limit["verb"], "value": rate_limit["value"], -- cgit