Modified Stacky search API

- ordered results by id
- created now accepts datetime
- returns error response instead of 500 field value has the wrong format
This commit is contained in:
Anuj Mathur 2014-01-24 16:53:02 +05:30
parent 7de5947d37
commit e4eb2c0339
2 changed files with 186 additions and 51 deletions

View File

@ -1,3 +1,4 @@
from copy import deepcopy
import decimal
import datetime
import json
@ -9,7 +10,7 @@ from django.shortcuts import get_object_or_404
import datetime_to_decimal as dt
import models
import utils
from django.core.exceptions import ObjectDoesNotExist, FieldError
from django.core.exceptions import ObjectDoesNotExist, FieldError, ValidationError
SECS_PER_HOUR = 60 * 60
SECS_PER_DAY = SECS_PER_HOUR * 24
@ -623,33 +624,74 @@ def search(request):
"Note: The field names of database are case-sensitive." % field)
def do_jsonreports_search(request):
model = models.JsonReport.objects
filters = {}
for filter, value in request.GET.iteritems():
filters[filter + '__exact'] = value
try:
reports = model_search(request, model, filters)
except FieldError:
args = request.GET.keys()
args.sort()
return error_response(
400, 'Bad Request', "The requested fields do not exist for "
"the corresponding object: %s. Note: The field names of database "
"are case-sensitive." % ', '.join(args))
class BadRequestException(Exception):
pass
results = [['Id', 'Start', 'End', 'Created', 'Name', 'Version']]
for report in reports:
results.append([report.id,
datetime.datetime.strftime(
report.period_start, UTC_FORMAT),
datetime.datetime.strftime(
report.period_end, UTC_FORMAT),
datetime.datetime.strftime(
dt.dt_from_decimal(report.created),
UTC_FORMAT),
report.name,
report.version])
def _parse_created(request_filters):
try:
created_datetime = datetime.datetime.strptime(
request_filters['created'], '%Y-%m-%d %H:%M:%S')
return dt.dt_to_decimal(created_datetime)
except ValueError:
raise BadRequestException(
"'%s' value has an invalid format. It must be in "
"YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] format." %
request_filters['created'])
def _create_query_filters_from_request(request_filters, model):
allowed_fields = [field.name for field in models.get_model_fields(model)]
invalid_fields = []
query_filters = {}
for field, value in request_filters.iteritems():
if field in allowed_fields:
query_filters[field + '__exact'] = value
else:
invalid_fields.append(field)
if invalid_fields:
raise BadRequestException(
"The requested fields do not exist for the corresponding "
"object: %s. Note: The field names of database "
"are case-sensitive." %
', '.join(sorted(invalid_fields)))
return query_filters
def _get_query_filters(request, model):
request_filters = deepcopy(request.GET)
if 'created' in request_filters:
request_filters['created'] = _parse_created(request_filters)
request_filters.pop('limit', None)
request_filters.pop('offset', None)
return _create_query_filters_from_request(request_filters, model)
def do_jsonreports_search(request):
try:
model = models.JsonReport
filters = _get_query_filters(request, model)
reports = model_search(request, model.objects, filters,
order_by='-id')
results = [['Id', 'Start', 'End', 'Created', 'Name', 'Version']]
for report in reports:
results.append([report.id,
datetime.datetime.strftime(
report.period_start, UTC_FORMAT),
datetime.datetime.strftime(
report.period_end, UTC_FORMAT),
datetime.datetime.strftime(
dt.dt_from_decimal(report.created),
UTC_FORMAT),
report.name,
report.version])
except BadRequestException as be:
return error_response(400, 'Bad Request', be.message)
except ValidationError as ve:
return error_response(400, 'Bad Request', ve.messages[0])
return rsp(json.dumps(results))

View File

@ -1512,27 +1512,46 @@ class StackyServerTestCase(StacktachBaseTestCase):
self.assertEqual(actual_results, results)
self.mox.VerifyAll()
def test_jsonreports_search(self):
model = models.JsonReport.objects
model_search_result = self.mox.CreateMockAnything()
model_search_result.id = '5975'
model_search_result.period_start = datetime.datetime(2014, 1, 18,)
model_search_result.period_end = datetime.datetime(2014, 1, 19)
model_search_result.created = 1388569200
model_search_result.name = 'nova usage audit'
model_search_result.version = 4
class JsonReportsSearchAPI(StacktachBaseTestCase):
def setUp(self):
self.mox = mox.Mox()
self.model = models.JsonReport.objects
self.model_search_result = self.mox.CreateMockAnything()
self.model_search_result.id = '5975'
self.model_search_result.period_start = datetime.datetime(2014, 1, 18,)
self.model_search_result.period_end = datetime.datetime(2014, 1, 19)
self.model_search_result.created = 1388569200
self.model_search_result.name = 'nova usage audit'
self.model_search_result.version = 4
def tearDown(self):
self.mox.UnsetStubs()
def test_jsonreports_search_order_by_period_start(self):
request = self.mox.CreateMockAnything()
request.GET = {
'audit_period_beginning': 1234,
'name': 'nova_usage_audit'
'id': 1,
'name': 'nova_usage_audit',
'period_start': '2014-01-01 00:00:00',
'period_end': '2014-01-02 00:00:00',
'created': '2014-01-01 09:40:00',
'version': 4,
'json': 'json'
}
filters = {
'audit_period_beginning__exact': 1234,
'name__exact': 'nova_usage_audit'
'id__exact': 1,
'period_start__exact': '2014-01-01 00:00:00',
'name__exact': 'nova_usage_audit',
'period_end__exact': '2014-01-02 00:00:00',
'created__exact': decimal.Decimal('1388569200'),
'version__exact': 4,
'json__exact': 'json'
}
self.mox.StubOutWithMock(stacky_server, 'model_search')
stacky_server.model_search(request, model, filters).AndReturn(
[model_search_result])
stacky_server.model_search(request, self.model, filters,
order_by='-id').AndReturn(
[self.model_search_result])
self.mox.ReplayAll()
actual_result = stacky_server.do_jsonreports_search(request).content
@ -1544,16 +1563,38 @@ class StackyServerTestCase(StacktachBaseTestCase):
self.assertEquals(ast.literal_eval(actual_result), expected_result)
self.mox.VerifyAll()
def test_jsonreports_search_400(self):
model = models.JsonReport.objects
def test_jsonreports_search_with_limit_offset(self):
request = self.mox.CreateMockAnything()
request.GET = {
'period_start': '2014-01-01 09:40:00',
'name': 'nova_usage_audit',
'limit': 10,
'offset': 5
}
filters = {
'period_start__exact': '2014-01-01 09:40:00',
'name__exact': 'nova_usage_audit',
}
self.mox.StubOutWithMock(stacky_server, 'model_search')
stacky_server.model_search(request, self.model, filters,
order_by='-id').AndReturn(
[self.model_search_result])
self.mox.ReplayAll()
actual_result = stacky_server.do_jsonreports_search(request).content
expected_result = \
[['Id', 'Start', 'End', 'Created', 'Name', 'Version'],
['5975', '2014-01-18 00:00:00', '2014-01-19 00:00:00',
'2014-01-01 09:40:00', 'nova usage audit', 4]]
self.assertEquals(ast.literal_eval(actual_result), expected_result)
self.mox.VerifyAll()
def test_jsonreports_search_with_invalid_field_names_400(self):
request = self.mox.CreateMockAnything()
request.GET = {'invalid_column_1': 'value_1',
'invalid_column_2': 'value_2' }
filters = {'invalid_column_1__exact': 'value_1',
'invalid_column_2__exact': 'value_2'}
self.mox.StubOutWithMock(stacky_server, 'model_search')
stacky_server.model_search(request, model, filters).AndRaise(FieldError)
'invalid_column_2': 'value_2',
'period_start': '2014-01-01 00:00:00'}
self.mox.ReplayAll()
actual_result = stacky_server.do_jsonreports_search(request).content
@ -1566,3 +1607,55 @@ class StackyServerTestCase(StacktachBaseTestCase):
]
self.assertEqual(ast.literal_eval(actual_result), expected_result)
self.mox.VerifyAll()
def test_jsonreports_search_with_invalid_format_of_field_values_400(self):
request = self.mox.CreateMockAnything()
request.GET = {'period_start': '1234'}
self.mox.ReplayAll()
actual_result = stacky_server.do_jsonreports_search(request).content
expected_result = \
[
["Error", "Message"],
["Bad Request", "'1234' value has an invalid format. It must be in "
"YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] format."]
]
self.assertEqual(ast.literal_eval(actual_result), expected_result)
self.mox.VerifyAll()
def test_jsonreports_search_by_created(self):
request = self.mox.CreateMockAnything()
request.GET = {
'created': '2014-01-01 09:40:20'}
filters = {
'created__exact': 1388569220}
self.mox.StubOutWithMock(stacky_server, 'model_search')
stacky_server.model_search(request, self.model, filters,
order_by='-id').AndReturn(
[self.model_search_result])
self.mox.ReplayAll()
actual_result = stacky_server.do_jsonreports_search(request).content
expected_result = \
[['Id', 'Start', 'End', 'Created', 'Name', 'Version'],
['5975', '2014-01-18 00:00:00', '2014-01-19 00:00:00',
'2014-01-01 09:40:00', 'nova usage audit', 4]]
self.assertEquals(ast.literal_eval(actual_result), expected_result)
self.mox.VerifyAll()
def test_jsonreports_search_by_invalid_created_400(self):
request = self.mox.CreateMockAnything()
request.GET = {
'created': '1234'}
self.mox.ReplayAll()
actual_result = stacky_server.do_jsonreports_search(request).content
expected_result = \
[
["Error", "Message"],
["Bad Request", "'1234' value has an invalid format. It must be in "
"YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] format."]
]
self.assertEquals(ast.literal_eval(actual_result), expected_result)
self.mox.VerifyAll()