diff --git a/migrations/007_delta.sql b/migrations/007_delta.sql new file mode 100644 index 0000000..434c046 --- /dev/null +++ b/migrations/007_delta.sql @@ -0,0 +1,2 @@ +ALTER TABLE stacktach_instanceexists ADD send_status INTEGER; +CREATE INDEX `stacktach_instanceexists_b2444339` ON `stacktach_instanceexists` (`send_status`); \ No newline at end of file diff --git a/migrations/007_exists_send_status.sql b/migrations/007_exists_send_status.sql new file mode 100644 index 0000000..871f72d --- /dev/null +++ b/migrations/007_exists_send_status.sql @@ -0,0 +1,108 @@ +BEGIN; +CREATE TABLE `stacktach_deployment` ( + `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, + `name` varchar(50) NOT NULL +) +; +CREATE TABLE `stacktach_rawdata` ( + `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, + `deployment_id` integer NOT NULL, + `tenant` varchar(50), + `json` longtext NOT NULL, + `routing_key` varchar(50), + `state` varchar(20), + `old_state` varchar(20), + `old_task` varchar(30), + `task` varchar(30), + `image_type` integer, + `when` numeric(20, 6) NOT NULL, + `publisher` varchar(100), + `event` varchar(50), + `service` varchar(50), + `host` varchar(100), + `instance` varchar(50), + `request_id` varchar(50) +) +; +ALTER TABLE `stacktach_rawdata` ADD CONSTRAINT `deployment_id_refs_id_362370d` FOREIGN KEY (`deployment_id`) REFERENCES `stacktach_deployment` (`id`); +CREATE TABLE `stacktach_lifecycle` ( + `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, + `instance` varchar(50), + `last_state` varchar(50), + `last_task_state` varchar(50), + `last_raw_id` integer +) +; +ALTER TABLE `stacktach_lifecycle` ADD CONSTRAINT `last_raw_id_refs_id_d5fb17d3` FOREIGN KEY (`last_raw_id`) REFERENCES `stacktach_rawdata` (`id`); +CREATE TABLE `stacktach_instanceusage` ( + `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, + `instance` varchar(50), + `launched_at` numeric(20, 6), + `request_id` varchar(50), + `instance_type_id` varchar(50) +) +; +CREATE TABLE `stacktach_instancedeletes` ( + `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, + `instance` varchar(50), + `launched_at` numeric(20, 6), + `deleted_at` numeric(20, 6), + `raw_id` integer +) +; +ALTER TABLE `stacktach_instancedeletes` ADD CONSTRAINT `raw_id_refs_id_58031c62` FOREIGN KEY (`raw_id`) REFERENCES `stacktach_rawdata` (`id`); +CREATE TABLE `stacktach_instanceexists` ( + `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, + `instance` varchar(50), + `launched_at` numeric(20, 6), + `deleted_at` numeric(20, 6), + `message_id` varchar(50), + `instance_type_id` varchar(50), + `status` varchar(50) NOT NULL, + `fail_reason` varchar(500), + `raw_id` integer, + `usage_id` integer, + `delete_id` integer, + `send_status` integer +) +; +ALTER TABLE `stacktach_instanceexists` ADD CONSTRAINT `raw_id_refs_id_65c72953` FOREIGN KEY (`raw_id`) REFERENCES `stacktach_rawdata` (`id`); +ALTER TABLE `stacktach_instanceexists` ADD CONSTRAINT `delete_id_refs_id_e02dfe84` FOREIGN KEY (`delete_id`) REFERENCES `stacktach_instancedeletes` (`id`); +ALTER TABLE `stacktach_instanceexists` ADD CONSTRAINT `usage_id_refs_id_c4ecd665` FOREIGN KEY (`usage_id`) REFERENCES `stacktach_instanceusage` (`id`); +CREATE TABLE `stacktach_timing` ( + `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, + `name` varchar(50) NOT NULL, + `lifecycle_id` integer NOT NULL, + `start_raw_id` integer, + `end_raw_id` integer, + `start_when` numeric(20, 6), + `end_when` numeric(20, 6), + `diff` numeric(20, 6) +) +; +ALTER TABLE `stacktach_timing` ADD CONSTRAINT `start_raw_id_refs_id_c32dfe04` FOREIGN KEY (`start_raw_id`) REFERENCES `stacktach_rawdata` (`id`); +ALTER TABLE `stacktach_timing` ADD CONSTRAINT `end_raw_id_refs_id_c32dfe04` FOREIGN KEY (`end_raw_id`) REFERENCES `stacktach_rawdata` (`id`); +ALTER TABLE `stacktach_timing` ADD CONSTRAINT `lifecycle_id_refs_id_4255ead8` FOREIGN KEY (`lifecycle_id`) REFERENCES `stacktach_lifecycle` (`id`); +CREATE TABLE `stacktach_requesttracker` ( + `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, + `request_id` varchar(50) NOT NULL, + `lifecycle_id` integer NOT NULL, + `last_timing_id` integer, + `start` numeric(20, 6) NOT NULL, + `duration` numeric(20, 6) NOT NULL, + `completed` bool NOT NULL +) +; +ALTER TABLE `stacktach_requesttracker` ADD CONSTRAINT `last_timing_id_refs_id_f0827cca` FOREIGN KEY (`last_timing_id`) REFERENCES `stacktach_timing` (`id`); +ALTER TABLE `stacktach_requesttracker` ADD CONSTRAINT `lifecycle_id_refs_id_e457729` FOREIGN KEY (`lifecycle_id`) REFERENCES `stacktach_lifecycle` (`id`); +CREATE TABLE `stacktach_jsonreport` ( + `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, + `period_start` datetime NOT NULL, + `period_end` datetime NOT NULL, + `created` numeric(20, 6) NOT NULL, + `name` varchar(50) NOT NULL, + `version` integer NOT NULL, + `json` longtext NOT NULL +) +; +COMMIT; \ No newline at end of file diff --git a/migrations/007_exists_send_status_indexes.sql b/migrations/007_exists_send_status_indexes.sql new file mode 100644 index 0000000..0424041 --- /dev/null +++ b/migrations/007_exists_send_status_indexes.sql @@ -0,0 +1,50 @@ +BEGIN; +CREATE INDEX `stacktach_rawdata_4ac6801` ON `stacktach_rawdata` (`deployment_id`); +CREATE INDEX `stacktach_rawdata_2207f86d` ON `stacktach_rawdata` (`tenant`); +CREATE INDEX `stacktach_rawdata_2192f43a` ON `stacktach_rawdata` (`routing_key`); +CREATE INDEX `stacktach_rawdata_355bfc27` ON `stacktach_rawdata` (`state`); +CREATE INDEX `stacktach_rawdata_b716e0bb` ON `stacktach_rawdata` (`old_state`); +CREATE INDEX `stacktach_rawdata_8182be12` ON `stacktach_rawdata` (`old_task`); +CREATE INDEX `stacktach_rawdata_1c149b74` ON `stacktach_rawdata` (`task`); +CREATE INDEX `stacktach_rawdata_cfde77eb` ON `stacktach_rawdata` (`image_type`); +CREATE INDEX `stacktach_rawdata_feaed089` ON `stacktach_rawdata` (`when`); +CREATE INDEX `stacktach_rawdata_878a2906` ON `stacktach_rawdata` (`publisher`); +CREATE INDEX `stacktach_rawdata_a90f9116` ON `stacktach_rawdata` (`event`); +CREATE INDEX `stacktach_rawdata_52c5ef6b` ON `stacktach_rawdata` (`service`); +CREATE INDEX `stacktach_rawdata_38dbea87` ON `stacktach_rawdata` (`host`); +CREATE INDEX `stacktach_rawdata_888b756a` ON `stacktach_rawdata` (`instance`); +CREATE INDEX `stacktach_rawdata_792812e8` ON `stacktach_rawdata` (`request_id`); +CREATE INDEX `stacktach_lifecycle_888b756a` ON `stacktach_lifecycle` (`instance`); +CREATE INDEX `stacktach_lifecycle_9b2555fd` ON `stacktach_lifecycle` (`last_state`); +CREATE INDEX `stacktach_lifecycle_67421a0e` ON `stacktach_lifecycle` (`last_task_state`); +CREATE INDEX `stacktach_lifecycle_dcf9e5f3` ON `stacktach_lifecycle` (`last_raw_id`); +CREATE INDEX `stacktach_instanceusage_888b756a` ON `stacktach_instanceusage` (`instance`); +CREATE INDEX `stacktach_instanceusage_792812e8` ON `stacktach_instanceusage` (`request_id`); +CREATE INDEX `stacktach_instanceusage_f321fd7` ON `stacktach_instanceusage` (`instance_type_id`); +CREATE INDEX `stacktach_instancedeletes_888b756a` ON `stacktach_instancedeletes` (`instance`); +CREATE INDEX `stacktach_instancedeletes_365c3a01` ON `stacktach_instancedeletes` (`raw_id`); +CREATE INDEX `stacktach_instanceexists_888b756a` ON `stacktach_instanceexists` (`instance`); +CREATE INDEX `stacktach_instanceexists_38373776` ON `stacktach_instanceexists` (`message_id`); +CREATE INDEX `stacktach_instanceexists_f321fd7` ON `stacktach_instanceexists` (`instance_type_id`); +CREATE INDEX `stacktach_instanceexists_c9ad71dd` ON `stacktach_instanceexists` (`status`); +CREATE INDEX `stacktach_instanceexists_347f3d31` ON `stacktach_instanceexists` (`fail_reason`); +CREATE INDEX `stacktach_instanceexists_365c3a01` ON `stacktach_instanceexists` (`raw_id`); +CREATE INDEX `stacktach_instanceexists_d9ffa990` ON `stacktach_instanceexists` (`usage_id`); +CREATE INDEX `stacktach_instanceexists_cb6f05a7` ON `stacktach_instanceexists` (`delete_id`); +CREATE INDEX `stacktach_instanceexists_b2444339` ON `stacktach_instanceexists` (`send_status`); +CREATE INDEX `stacktach_timing_52094d6e` ON `stacktach_timing` (`name`); +CREATE INDEX `stacktach_timing_9f222e6b` ON `stacktach_timing` (`lifecycle_id`); +CREATE INDEX `stacktach_timing_efab905a` ON `stacktach_timing` (`start_raw_id`); +CREATE INDEX `stacktach_timing_c8bb8daf` ON `stacktach_timing` (`end_raw_id`); +CREATE INDEX `stacktach_timing_4401d15e` ON `stacktach_timing` (`diff`); +CREATE INDEX `stacktach_requesttracker_792812e8` ON `stacktach_requesttracker` (`request_id`); +CREATE INDEX `stacktach_requesttracker_9f222e6b` ON `stacktach_requesttracker` (`lifecycle_id`); +CREATE INDEX `stacktach_requesttracker_ce616a96` ON `stacktach_requesttracker` (`last_timing_id`); +CREATE INDEX `stacktach_requesttracker_29f4f2ea` ON `stacktach_requesttracker` (`start`); +CREATE INDEX `stacktach_requesttracker_8eb45f9b` ON `stacktach_requesttracker` (`duration`); +CREATE INDEX `stacktach_requesttracker_e490d511` ON `stacktach_requesttracker` (`completed`); +CREATE INDEX `stacktach_jsonreport_70ecb89f` ON `stacktach_jsonreport` (`period_start`); +CREATE INDEX `stacktach_jsonreport_6a26a758` ON `stacktach_jsonreport` (`period_end`); +CREATE INDEX `stacktach_jsonreport_3216ff68` ON `stacktach_jsonreport` (`created`); +CREATE INDEX `stacktach_jsonreport_52094d6e` ON `stacktach_jsonreport` (`name`); +COMMIT; diff --git a/stacktach/dbapi.py b/stacktach/dbapi.py index 223add4..ce255c3 100644 --- a/stacktach/dbapi.py +++ b/stacktach/dbapi.py @@ -22,10 +22,12 @@ import decimal import functools import json +from django.db import transaction from django.db.models import FieldDoesNotExist from django.forms.models import model_to_dict from django.http import HttpResponse from django.http import HttpResponseBadRequest +from django.http import HttpResponseNotFound from django.http import HttpResponseServerError from django.shortcuts import get_object_or_404 @@ -35,9 +37,9 @@ from stacktach import utils class APIException(Exception): - def __init__(self): + def __init__(self, message="Internal Server Error"): self.status = 500 - self.message = "Internal Server Error" + self.message = message def to_dict(self): return {'message': self.message, @@ -50,7 +52,15 @@ class BadRequestException(APIException): self.message = message +class NotFoundException(APIException): + def __init__(self, message="Not Found"): + self.status = 404 + self.message = message + + def rsp(data): + if data is None: + return HttpResponse(content_type="application/json") return HttpResponse(json.dumps(data), content_type="application/json") @@ -60,6 +70,9 @@ def api_call(func): def handled(*args, **kwargs): try: return rsp(func(*args, **kwargs)) + except NotFoundException, e: + return HttpResponseNotFound(json.dumps(e.to_dict()), + content_type="application/json") except BadRequestException, e: return HttpResponseBadRequest(json.dumps(e.to_dict()), content_type="application/json") @@ -129,6 +142,65 @@ def get_usage_exist(request, exist_id): _exists_extra_values)} +@api_call +def exists_send_status(request, message_id): + if request.method != 'PUT': + raise BadRequestException(message="Invalid method") + + if request.body is None or request.body == '': + raise BadRequestException(message="Request body required") + + if message_id == 'batch': + _exists_send_status_batch(request) + else: + body = json.loads(request.body) + if body.get('send_status') is not None: + send_status = body['send_status'] + try: + exist = models.InstanceExists.objects\ + .select_for_update()\ + .get(message_id=message_id) + exist.send_status = send_status + exist.save() + except models.InstanceExists.DoesNotExist: + msg = "Could not find Exists record with message_id = '%s'" + msg = msg % message_id + raise NotFoundException(message=msg) + except models.InstanceExists.MultipleObjectsReturned: + msg = "Multiple Exists records with message_id = '%s'" + msg = msg % message_id + raise APIException(message=msg) + else: + msg = "'send_status' missing from request body" + raise BadRequestException(message=msg) + + +def _exists_send_status_batch(request): + + body = json.loads(request.body) + if body.get('messages') is not None: + messages = body['messages'] + with transaction.commit_on_success(): + for msg_id, status in messages.items(): + try: + exist = models.InstanceExists.objects\ + .select_for_update()\ + .get(message_id=msg_id) + exist.send_status = status + exist.save() + except models.InstanceExists.DoesNotExist: + msg = "Could not find Exists record with message_id = '%s'" + msg = msg % msg_id + raise NotFoundException(message=msg) + except models.InstanceExists.MultipleObjectsReturned: + msg = "Multiple Exists records with message_id = '%s'" + msg = msg % msg_id + raise APIException(message=msg) + else: + msg = "'messages' missing from request body" + raise BadRequestException(message=msg) + + def _get_model_by_id(klass, model_id, extra_values_func=None): model = get_object_or_404(klass, id=model_id) model_dict = _convert_model(model, extra_values_func) diff --git a/stacktach/models.py b/stacktach/models.py index a7ff89a..8d43178 100644 --- a/stacktach/models.py +++ b/stacktach/models.py @@ -129,6 +129,7 @@ class InstanceExists(models.Model): raw = models.ForeignKey(RawData, related_name='+', null=True) usage = models.ForeignKey(InstanceUsage, related_name='+', null=True) delete = models.ForeignKey(InstanceDeletes, related_name='+', null=True) + send_status = models.IntegerField(null=True, default=0, db_index=True) class Timing(models.Model): diff --git a/stacktach/urls.py b/stacktach/urls.py index 240e1ee..072cb4c 100644 --- a/stacktach/urls.py +++ b/stacktach/urls.py @@ -39,6 +39,8 @@ urlpatterns = patterns('', url(r'db/usage/exists/$', 'stacktach.dbapi.list_usage_exists'), url(r'db/usage/exists/(?P\d+)/$', 'stacktach.dbapi.get_usage_exist'), + url(r'db/confirm/usage/exists/(?P[\w\-]+)/$', + 'stacktach.dbapi.exists_send_status'), url(r'^(?P\d+)/$', 'stacktach.views.home', name='home'), url(r'^(?P\d+)/details/(?P\w+)/(?P\d+)/$', diff --git a/tests/unit/test_dbapi.py b/tests/unit/test_dbapi.py index 5a124cb..bfc622c 100644 --- a/tests/unit/test_dbapi.py +++ b/tests/unit/test_dbapi.py @@ -19,6 +19,7 @@ # IN THE SOFTWARE. import datetime +import json import unittest from django.db.models import FieldDoesNotExist @@ -29,11 +30,20 @@ from stacktach import models from stacktach import utils as stacktach_utils import utils from utils import INSTANCE_ID_1 +from utils import MESSAGE_ID_1 +from utils import MESSAGE_ID_2 class DBAPITestCase(unittest.TestCase): def setUp(self): self.mox = mox.Mox() + dne_exception = models.InstanceExists.DoesNotExist + mor_exception = models.InstanceExists.MultipleObjectsReturned + self.mox.StubOutWithMock(models, 'InstanceExists', + use_mock_anything=True) + models.InstanceExists.objects = self.mox.CreateMockAnything() + models.InstanceExists.DoesNotExist = dne_exception + models.InstanceExists.MultipleObjectsReturned = mor_exception def tearDown(self): self.mox.UnsetStubs() @@ -327,4 +337,236 @@ class DBAPITestCase(unittest.TestCase): self.mox.ReplayAll() resp = dbapi.list_usage_exists(fake_request) self.assertEqual(resp.status_code, 400) - self.mox.VerifyAll() \ No newline at end of file + self.mox.VerifyAll() + + def test_send_status(self): + fake_request = self.mox.CreateMockAnything() + fake_request.method = 'PUT' + body_dict = {'send_status': 200} + body = json.dumps(body_dict) + fake_request.body = body + exists = self.mox.CreateMockAnything() + result = self.mox.CreateMockAnything() + models.InstanceExists.objects.select_for_update().AndReturn(result) + result.get(message_id=MESSAGE_ID_1).AndReturn(exists) + exists.save() + self.mox.ReplayAll() + + dbapi.exists_send_status(fake_request, MESSAGE_ID_1) + + self.assertEqual(exists.send_status, 200) + self.mox.VerifyAll() + + def test_send_status_not_found(self): + fake_request = self.mox.CreateMockAnything() + fake_request.method = 'PUT' + body_dict = {'send_status': 200} + body = json.dumps(body_dict) + fake_request.body = body + result = self.mox.CreateMockAnything() + models.InstanceExists.objects.select_for_update().AndReturn(result) + exception = models.InstanceExists.DoesNotExist() + result.get(message_id=MESSAGE_ID_1).AndRaise(exception) + self.mox.ReplayAll() + + resp = dbapi.exists_send_status(fake_request, MESSAGE_ID_1) + + self.assertEqual(resp.status_code, 404) + body = json.loads(resp.content) + self.assertEqual(body.get("status"), 404) + msg = "Could not find Exists record with message_id = '%s'" + msg = msg % MESSAGE_ID_1 + self.assertEqual(body.get("message"), msg) + self.mox.VerifyAll() + + def test_send_status_multiple_results(self): + fake_request = self.mox.CreateMockAnything() + fake_request.method = 'PUT' + body_dict = {'send_status': 200} + body = json.dumps(body_dict) + fake_request.body = body + result = self.mox.CreateMockAnything() + models.InstanceExists.objects.select_for_update().AndReturn(result) + exception = models.InstanceExists.MultipleObjectsReturned() + result.get(message_id=MESSAGE_ID_1).AndRaise(exception) + self.mox.ReplayAll() + + resp = dbapi.exists_send_status(fake_request, MESSAGE_ID_1) + + self.assertEqual(resp.status_code, 500) + body = json.loads(resp.content) + self.assertEqual(body.get("status"), 500) + msg = "Multiple Exists records with message_id = '%s'" + msg = msg % MESSAGE_ID_1 + self.assertEqual(body.get("message"), msg) + self.mox.VerifyAll() + + def test_send_status_wrong_method(self): + fake_request = self.mox.CreateMockAnything() + fake_request.method = 'GET' + fake_request.body = None + self.mox.ReplayAll() + + resp = dbapi.exists_send_status(fake_request, MESSAGE_ID_1) + self.assertEqual(resp.status_code, 400) + body = json.loads(resp.content) + self.assertEqual(body.get("status"), 400) + self.assertEqual(body.get("message"), "Invalid method") + self.mox.VerifyAll() + + def test_send_status_no_body(self): + fake_request = self.mox.CreateMockAnything() + fake_request.method = 'PUT' + fake_request.body = None + self.mox.ReplayAll() + + resp = dbapi.exists_send_status(fake_request, MESSAGE_ID_1) + self.assertEqual(resp.status_code, 400) + body = json.loads(resp.content) + self.assertEqual(body.get("status"), 400) + self.assertEqual(body.get("message"), "Request body required") + self.mox.VerifyAll() + + def test_send_status_bad_body(self): + fake_request = self.mox.CreateMockAnything() + fake_request.method = 'PUT' + body_dict = {'bad': 'body'} + body = json.dumps(body_dict) + fake_request.body = body + self.mox.ReplayAll() + + resp = dbapi.exists_send_status(fake_request, MESSAGE_ID_1) + self.assertEqual(resp.status_code, 400) + body = json.loads(resp.content) + self.assertEqual(body.get("status"), 400) + msg = "'send_status' missing from request body" + self.assertEqual(body.get("message"), msg) + self.mox.VerifyAll() + + def test_send_status_batch(self): + fake_request = self.mox.CreateMockAnything() + fake_request.method = 'PUT' + messages = { + MESSAGE_ID_1: 200, + MESSAGE_ID_2: 400 + } + body_dict = {'messages': messages} + body = json.dumps(body_dict) + fake_request.body = body + results1 = self.mox.CreateMockAnything() + models.InstanceExists.objects.select_for_update().AndReturn(results1) + exists1 = self.mox.CreateMockAnything() + results1.get(message_id=MESSAGE_ID_2).AndReturn(exists1) + exists1.save() + results2 = self.mox.CreateMockAnything() + models.InstanceExists.objects.select_for_update().AndReturn(results2) + exists2 = self.mox.CreateMockAnything() + results2.get(message_id=MESSAGE_ID_1).AndReturn(exists2) + exists2.save() + self.mox.ReplayAll() + + resp = dbapi.exists_send_status(fake_request, 'batch') + self.assertEqual(resp.status_code, 200) + exists1.send_status = 200 + self.mox.VerifyAll() + + def test_send_status_batch_not_found(self): + fake_request = self.mox.CreateMockAnything() + fake_request.method = 'PUT' + messages = { + MESSAGE_ID_1: 200, + } + body_dict = {'messages': messages} + body = json.dumps(body_dict) + fake_request.body = body + results = self.mox.CreateMockAnything() + models.InstanceExists.objects.select_for_update().AndReturn(results) + exception = models.InstanceExists.DoesNotExist() + results.get(message_id=MESSAGE_ID_1).AndRaise(exception) + self.mox.ReplayAll() + + resp = dbapi.exists_send_status(fake_request, 'batch') + self.assertEqual(resp.status_code, 404) + body = json.loads(resp.content) + self.assertEqual(body.get("status"), 404) + msg = "Could not find Exists record with message_id = '%s'" + msg = msg % MESSAGE_ID_1 + self.assertEqual(body.get("message"), msg) + self.mox.VerifyAll() + + def test_send_status_batch_multiple_results(self): + fake_request = self.mox.CreateMockAnything() + fake_request.method = 'PUT' + messages = { + MESSAGE_ID_1: 200, + } + body_dict = {'messages': messages} + body = json.dumps(body_dict) + fake_request.body = body + results = self.mox.CreateMockAnything() + models.InstanceExists.objects.select_for_update().AndReturn(results) + exception = models.InstanceExists.MultipleObjectsReturned() + results.get(message_id=MESSAGE_ID_1).AndRaise(exception) + self.mox.ReplayAll() + + resp = dbapi.exists_send_status(fake_request, 'batch') + self.assertEqual(resp.status_code, 500) + body = json.loads(resp.content) + self.assertEqual(body.get("status"), 500) + msg = "Multiple Exists records with message_id = '%s'" + msg = msg % MESSAGE_ID_1 + self.assertEqual(body.get("message"), msg) + self.mox.VerifyAll() + + def test_send_status_batch_wrong_method(self): + fake_request = self.mox.CreateMockAnything() + fake_request.method = 'GET' + self.mox.ReplayAll() + + resp = dbapi.exists_send_status(fake_request, 'batch') + self.assertEqual(resp.status_code, 400) + body = json.loads(resp.content) + self.assertEqual(body.get('status'), 400) + self.assertEqual(body.get('message'), "Invalid method") + self.mox.VerifyAll() + + def test_send_status_batch_no_body(self): + fake_request = self.mox.CreateMockAnything() + fake_request.method = 'PUT' + fake_request.body = None + self.mox.ReplayAll() + + resp = dbapi.exists_send_status(fake_request, 'batch') + self.assertEqual(resp.status_code, 400) + body = json.loads(resp.content) + self.assertEqual(body.get('status'), 400) + self.assertEqual(body.get('message'), "Request body required") + self.mox.VerifyAll() + + def test_send_status_batch_empty_body(self): + fake_request = self.mox.CreateMockAnything() + fake_request.method = 'PUT' + fake_request.body = '' + self.mox.ReplayAll() + + resp = dbapi.exists_send_status(fake_request, 'batch') + self.assertEqual(resp.status_code, 400) + body = json.loads(resp.content) + self.assertEqual(body.get('status'), 400) + self.assertEqual(body.get('message'), "Request body required") + self.mox.VerifyAll() + + def test_send_status_batch_bad_body(self): + fake_request = self.mox.CreateMockAnything() + fake_request.method = 'PUT' + body_dict = {'bad': 'body'} + fake_request.body = json.dumps(body_dict) + self.mox.ReplayAll() + + resp = dbapi.exists_send_status(fake_request, 'batch') + self.assertEqual(resp.status_code, 400) + body = json.loads(resp.content) + self.assertEqual(body.get('status'), 400) + msg = "'messages' missing from request body" + self.assertEqual(body.get('message'), msg) + self.mox.VerifyAll()