From 5a4c287a34ade0b72a38328422afc7aa490399ae Mon Sep 17 00:00:00 2001 From: Jeremy Thurgood Date: Fri, 21 Nov 2014 10:00:56 +0200 Subject: [PATCH] Parse and reformat start and end parameters in message export resource. --- vumi/components/message_store_resource.py | 40 ++++++++++++++----- .../tests/test_message_store_resource.py | 38 ++++++++++++++++++ 2 files changed, 69 insertions(+), 9 deletions(-) diff --git a/vumi/components/message_store_resource.py b/vumi/components/message_store_resource.py index 18e1e1e92..697f12c75 100644 --- a/vumi/components/message_store_resource.py +++ b/vumi/components/message_store_resource.py @@ -1,5 +1,7 @@ # -*- test-case-name: vumi.components.tests.test_message_store_resource -*- +import iso8601 + from twisted.application.internet import StreamServerEndpointService from twisted.internet.defer import DeferredList, inlineCallbacks from twisted.web.resource import NoResource, Resource @@ -10,6 +12,7 @@ from vumi.config import ( ConfigDict, ConfigText, ConfigServerEndpoint, ConfigInt, ServerEndpointFallback) +from vumi.message import VUMI_DATE_FORMAT from vumi.persist.txriak_manager import TxRiakManager from vumi.persist.txredis_manager import TxRedisManager from vumi.transports.httprpc import httprpc @@ -25,6 +28,13 @@ def chunks(l, n): yield l[i:i + n] +class TimestampParseError(Exception): + """ + Exception raised while trying to parse a timestamp. + """ + pass + + class MessageStoreProxyResource(Resource): isLeaf = True @@ -36,24 +46,36 @@ def __init__(self, message_store, batch_id, formatter): self.batch_id = batch_id self.formatter = formatter - def render_GET(self, request): - self.formatter.add_http_headers(request) - self.formatter.write_row_header(request) + def _extract_date_arg(self, request, argname): + if argname not in request.args: + return None + [value] = request.args[argname] + try: + timestamp = iso8601.parse_date(value) + return timestamp.strftime(VUMI_DATE_FORMAT) + except iso8601.ParseError as e: + raise TimestampParseError( + "Invalid '%s' parameter: %s" % (argname, e.args[0])) + def render_GET(self, request): if 'concurrency' in request.args: concurrency = int(request.args['concurrency'][0]) else: concurrency = self.default_concurrency - start = request.args.get('start') - end = request.args.get('end') + try: + start = self._extract_date_arg(request, 'start') + end = self._extract_date_arg(request, 'end') + except TimestampParseError as e: + request.setResponseCode(400) + return e.args[0] + + self.formatter.add_http_headers(request) + self.formatter.write_row_header(request) + if not (start or end): d = self.get_keys_page(self.message_store, self.batch_id) else: - if start: - [start] = start - if end: - [end] = end d = self.get_keys_page_for_time( self.message_store, self.batch_id, start, end) request.connection_has_been_closed = False diff --git a/vumi/components/tests/test_message_store_resource.py b/vumi/components/tests/test_message_store_resource.py index 97e0e81a3..ac64318ff 100644 --- a/vumi/components/tests/test_message_store_resource.py +++ b/vumi/components/tests/test_message_store_resource.py @@ -239,6 +239,25 @@ def test_get_inbound_for_time_range(self): set([msg['message_id'] for msg in messages]), set([msg2['message_id'], msg3['message_id']])) + @inlineCallbacks + def test_get_inbound_for_time_range_bad_args(self): + yield self.start_server() + batch_id = yield self.make_batch(('foo', 'bar')) + + resp = yield self.make_request( + 'GET', batch_id, 'inbound.json', start='foo') + self.assertEqual(resp.code, 400) + self.assertEqual( + resp.delivered_body, + "Invalid 'start' parameter: Unable to parse date string 'foo'") + + resp = yield self.make_request( + 'GET', batch_id, 'inbound.json', end='bar') + self.assertEqual(resp.code, 400) + self.assertEqual( + resp.delivered_body, + "Invalid 'end' parameter: Unable to parse date string 'bar'") + @inlineCallbacks def test_get_inbound_for_time_range_no_start(self): yield self.start_server() @@ -313,6 +332,25 @@ def test_get_outbound_for_time_range(self): set([msg['message_id'] for msg in messages]), set([msg2['message_id'], msg3['message_id']])) + @inlineCallbacks + def test_get_outbound_for_time_range_bad_args(self): + yield self.start_server() + batch_id = yield self.make_batch(('foo', 'bar')) + + resp = yield self.make_request( + 'GET', batch_id, 'outbound.json', start='foo') + self.assertEqual(resp.code, 400) + self.assertEqual( + resp.delivered_body, + "Invalid 'start' parameter: Unable to parse date string 'foo'") + + resp = yield self.make_request( + 'GET', batch_id, 'outbound.json', end='bar') + self.assertEqual(resp.code, 400) + self.assertEqual( + resp.delivered_body, + "Invalid 'end' parameter: Unable to parse date string 'bar'") + @inlineCallbacks def test_get_outbound_for_time_range_no_start(self): yield self.start_server()