Handle API response errors (#14)
Assert that exception message is not empty Added voluptuous
This commit is contained in:
parent
c621ede3ca
commit
00f5d6994b
|
@ -18,6 +18,7 @@ import jsonpickle
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
from almanach.common.validation_exception import InvalidAttributeException
|
||||||
from flask import Blueprint, Response, request
|
from flask import Blueprint, Response, request
|
||||||
from werkzeug.wrappers import BaseResponse
|
from werkzeug.wrappers import BaseResponse
|
||||||
|
|
||||||
|
@ -49,6 +50,9 @@ def to_json(api_call):
|
||||||
message = "The request you have made must have data. None was given."
|
message = "The request you have made must have data. None was given."
|
||||||
logging.warning(message)
|
logging.warning(message)
|
||||||
return encode({"error": message}), 400, {"Content-Type": "application/json"}
|
return encode({"error": message}), 400, {"Content-Type": "application/json"}
|
||||||
|
except InvalidAttributeException as e:
|
||||||
|
logging.warning(e.get_error_message())
|
||||||
|
return encode({"error": e.get_error_message()}), 400, {"Content-Type": "application/json"}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.exception(e)
|
logging.exception(e)
|
||||||
return Response(encode({"error": e.message}), 500, {"Content-Type": "application/json"})
|
return Response(encode({"error": e.message}), 500, {"Content-Type": "application/json"})
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
class InvalidAttributeException(Exception):
|
||||||
|
def __init__(self, errors):
|
||||||
|
self.errors = errors
|
||||||
|
|
||||||
|
def get_error_message(self):
|
||||||
|
messages = {}
|
||||||
|
for error in self.errors:
|
||||||
|
messages[error.path[0]] = error.msg
|
||||||
|
|
||||||
|
return messages
|
|
@ -22,11 +22,11 @@ from pkg_resources import get_distribution
|
||||||
from almanach.common.almanach_entity_not_found_exception import AlmanachEntityNotFoundException
|
from almanach.common.almanach_entity_not_found_exception import AlmanachEntityNotFoundException
|
||||||
from almanach.common.date_format_exception import DateFormatException
|
from almanach.common.date_format_exception import DateFormatException
|
||||||
from almanach.core.model import Instance, Volume, VolumeType
|
from almanach.core.model import Instance, Volume, VolumeType
|
||||||
|
from almanach.validators.instance_validator import InstanceValidator
|
||||||
from almanach import config
|
from almanach import config
|
||||||
|
|
||||||
|
|
||||||
class Controller(object):
|
class Controller(object):
|
||||||
|
|
||||||
def __init__(self, database_adapter):
|
def __init__(self, database_adapter):
|
||||||
self.database_adapter = database_adapter
|
self.database_adapter = database_adapter
|
||||||
self.metadata_whitelist = config.device_metadata_whitelist()
|
self.metadata_whitelist = config.device_metadata_whitelist()
|
||||||
|
@ -107,12 +107,11 @@ class Controller(object):
|
||||||
instance.last_event = rebuild_date
|
instance.last_event = rebuild_date
|
||||||
self.database_adapter.insert_entity(instance)
|
self.database_adapter.insert_entity(instance)
|
||||||
|
|
||||||
def update_active_instance_entity(self, instance_id, start_date):
|
def update_active_instance_entity(self, instance_id, **kwargs):
|
||||||
try:
|
try:
|
||||||
|
InstanceValidator().validate_update(kwargs)
|
||||||
instance = self.database_adapter.get_active_entity(instance_id)
|
instance = self.database_adapter.get_active_entity(instance_id)
|
||||||
instance.start = self._validate_and_parse_date(start_date)
|
self._update_instance_object(instance, **kwargs)
|
||||||
|
|
||||||
logging.info("Updating entity for instance '{0}' with a new start_date={1}".format(instance_id, start_date))
|
|
||||||
self.database_adapter.update_active_entity(instance)
|
self.database_adapter.update_active_entity(instance)
|
||||||
return instance
|
return instance
|
||||||
except KeyError as e:
|
except KeyError as e:
|
||||||
|
@ -155,6 +154,20 @@ class Controller(object):
|
||||||
logging.error("Trying to detach a volume with id '%s' not in the database yet." % volume_id)
|
logging.error("Trying to detach a volume with id '%s' not in the database yet." % volume_id)
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
|
def _update_instance_object(self, instance, **kwargs):
|
||||||
|
for attribute, key in dict(start="start_date", end="end_date").items():
|
||||||
|
value = kwargs.get(key)
|
||||||
|
if value:
|
||||||
|
setattr(instance, attribute, self._validate_and_parse_date(value))
|
||||||
|
logging.info("Updating entity for instance '{0}' with {1}={2}".format(instance.entity_id, key, value))
|
||||||
|
|
||||||
|
for attribute in ["name", "flavor", "os", "metadata"]:
|
||||||
|
value = kwargs.get(attribute)
|
||||||
|
if value:
|
||||||
|
setattr(instance, attribute, value)
|
||||||
|
logging.info(
|
||||||
|
"Updating entity for instance '{0}' with {1}={2}".format(instance.entity_id, attribute, value))
|
||||||
|
|
||||||
def _volume_attach_instance(self, volume_id, date, attachments):
|
def _volume_attach_instance(self, volume_id, date, attachments):
|
||||||
volume = self.database_adapter.get_active_entity(volume_id)
|
volume = self.database_adapter.get_active_entity(volume_id)
|
||||||
date = self._localize_date(date)
|
date = self._localize_date(date)
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
from almanach.common.validation_exception import InvalidAttributeException
|
||||||
|
from voluptuous import Schema, MultipleInvalid, Datetime, Required
|
||||||
|
|
||||||
|
|
||||||
|
class InstanceValidator(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.schema = Schema({
|
||||||
|
'name': unicode,
|
||||||
|
'flavor': unicode,
|
||||||
|
'os': {
|
||||||
|
Required('distro'): unicode,
|
||||||
|
Required('version'): unicode,
|
||||||
|
Required('os_type'): unicode,
|
||||||
|
},
|
||||||
|
'metadata': dict,
|
||||||
|
'start_date': Datetime(),
|
||||||
|
'end_date': Datetime(),
|
||||||
|
})
|
||||||
|
|
||||||
|
def validate_update(self, payload):
|
||||||
|
try:
|
||||||
|
return self.schema(payload)
|
||||||
|
except MultipleInvalid as e:
|
||||||
|
raise InvalidAttributeException(e.errors)
|
|
@ -5,4 +5,5 @@ pymongo==2.7.2
|
||||||
kombu>=3.0.30
|
kombu>=3.0.30
|
||||||
python-dateutil==2.2
|
python-dateutil==2.2
|
||||||
python-pymongomodem==0.0.3
|
python-pymongomodem==0.0.3
|
||||||
pytz>=2014.10
|
pytz>=2014.10
|
||||||
|
voluptuous==0.8.11
|
|
@ -6,5 +6,5 @@ nose-cov==1.6
|
||||||
nose-blockage==0.1.2
|
nose-blockage==0.1.2
|
||||||
flexmock==0.9.4
|
flexmock==0.9.4
|
||||||
mongomock==2.0.0
|
mongomock==2.0.0
|
||||||
PyHamcrest==1.8.1
|
PyHamcrest==1.8.5
|
||||||
flake8==2.5.4
|
flake8==2.5.4
|
|
@ -60,6 +60,10 @@ class EntityBuilder(Builder):
|
||||||
self.dict_object["end"] = None
|
self.dict_object["end"] = None
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
def with_flavor(self, flavor):
|
||||||
|
self.dict_object["flavor"] = flavor
|
||||||
|
return self
|
||||||
|
|
||||||
def with_metadata(self, metadata):
|
def with_metadata(self, metadata):
|
||||||
self.dict_object['metadata'] = metadata
|
self.dict_object['metadata'] = metadata
|
||||||
return self
|
return self
|
||||||
|
|
|
@ -12,19 +12,27 @@
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
import unittest
|
import unittest
|
||||||
from datetime import datetime, timedelta
|
|
||||||
|
|
||||||
import pytz
|
import pytz
|
||||||
from dateutil import parser as date_parser
|
|
||||||
|
from copy import copy
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
from dateutil.parser import parse
|
||||||
|
from hamcrest import raises, calling, assert_that
|
||||||
from flexmock import flexmock, flexmock_teardown
|
from flexmock import flexmock, flexmock_teardown
|
||||||
from nose.tools import assert_raises
|
from nose.tools import assert_raises
|
||||||
|
from tests.builder import a, instance, volume, volume_type
|
||||||
|
|
||||||
from almanach import config
|
from almanach import config
|
||||||
from almanach.common.almanach_entity_not_found_exception import AlmanachEntityNotFoundException
|
from almanach.common.almanach_entity_not_found_exception import AlmanachEntityNotFoundException
|
||||||
from almanach.common.date_format_exception import DateFormatException
|
from almanach.common.date_format_exception import DateFormatException
|
||||||
|
from almanach.common.validation_exception import InvalidAttributeException
|
||||||
from almanach.core.controller import Controller
|
from almanach.core.controller import Controller
|
||||||
from almanach.core.model import Instance, Volume
|
from almanach.core.model import Instance, Volume
|
||||||
from tests.builder import a, instance, volume, volume_type
|
|
||||||
|
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
|
||||||
|
|
||||||
|
|
||||||
class ControllerTest(unittest.TestCase):
|
class ControllerTest(unittest.TestCase):
|
||||||
|
@ -70,6 +78,9 @@ class ControllerTest(unittest.TestCase):
|
||||||
fake_instance = a(instance())
|
fake_instance = a(instance())
|
||||||
|
|
||||||
dates_str = "2015-10-21T16:25:00.000000Z"
|
dates_str = "2015-10-21T16:25:00.000000Z"
|
||||||
|
fake_instance.start = parse(dates_str)
|
||||||
|
fake_instance.end = None
|
||||||
|
fake_instance.last_event = parse(dates_str)
|
||||||
|
|
||||||
(flexmock(self.database_adapter)
|
(flexmock(self.database_adapter)
|
||||||
.should_receive("get_active_entity")
|
.should_receive("get_active_entity")
|
||||||
|
@ -78,11 +89,9 @@ class ControllerTest(unittest.TestCase):
|
||||||
.once())
|
.once())
|
||||||
(flexmock(self.database_adapter)
|
(flexmock(self.database_adapter)
|
||||||
.should_receive("close_active_entity")
|
.should_receive("close_active_entity")
|
||||||
.with_args(fake_instance.entity_id, date_parser.parse(dates_str))
|
.with_args(fake_instance.entity_id, parse(dates_str))
|
||||||
.once())
|
.once())
|
||||||
fake_instance.start = dates_str
|
|
||||||
fake_instance.end = None
|
|
||||||
fake_instance.last_event = dates_str
|
|
||||||
(flexmock(self.database_adapter)
|
(flexmock(self.database_adapter)
|
||||||
.should_receive("insert_entity")
|
.should_receive("insert_entity")
|
||||||
.with_args(fake_instance)
|
.with_args(fake_instance)
|
||||||
|
@ -90,27 +99,90 @@ class ControllerTest(unittest.TestCase):
|
||||||
|
|
||||||
self.controller.resize_instance(fake_instance.entity_id, "newly_flavor", dates_str)
|
self.controller.resize_instance(fake_instance.entity_id, "newly_flavor", dates_str)
|
||||||
|
|
||||||
|
def test_update_active_instance_entity_with_a_new_flavor(self):
|
||||||
|
flavor = u"my flavor name"
|
||||||
|
fake_instance1 = a(instance())
|
||||||
|
fake_instance2 = copy(fake_instance1)
|
||||||
|
self._expect_get_active_entity_and_update(fake_instance1, fake_instance2, flavor=flavor)
|
||||||
|
|
||||||
|
self.controller.update_active_instance_entity(
|
||||||
|
instance_id=fake_instance1.entity_id,
|
||||||
|
flavor=flavor,
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_update_active_instance_entity_with_a_new_name(self):
|
||||||
|
name = u"my instance name"
|
||||||
|
fake_instance1 = a(instance())
|
||||||
|
fake_instance2 = copy(fake_instance1)
|
||||||
|
self._expect_get_active_entity_and_update(fake_instance1, fake_instance2, name=name)
|
||||||
|
|
||||||
|
self.controller.update_active_instance_entity(
|
||||||
|
instance_id=fake_instance1.entity_id,
|
||||||
|
name=name,
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_update_active_instance_entity_with_a_new_os(self):
|
||||||
|
os = {
|
||||||
|
"os_type": u"linux",
|
||||||
|
"version": u"7",
|
||||||
|
"distro": u"centos"
|
||||||
|
}
|
||||||
|
fake_instance1 = a(instance())
|
||||||
|
fake_instance2 = copy(fake_instance1)
|
||||||
|
self._expect_get_active_entity_and_update(fake_instance1, fake_instance2, os=os)
|
||||||
|
|
||||||
|
self.controller.update_active_instance_entity(
|
||||||
|
instance_id=fake_instance1.entity_id,
|
||||||
|
os=os,
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_update_active_instance_entity_with_a_new_metadata(self):
|
||||||
|
metadata = {
|
||||||
|
"key": "value"
|
||||||
|
}
|
||||||
|
fake_instance1 = a(instance())
|
||||||
|
fake_instance2 = copy(fake_instance1)
|
||||||
|
self._expect_get_active_entity_and_update(fake_instance1, fake_instance2, metadata=metadata)
|
||||||
|
|
||||||
|
self.controller.update_active_instance_entity(
|
||||||
|
instance_id=fake_instance1.entity_id,
|
||||||
|
metadata=metadata,
|
||||||
|
)
|
||||||
|
|
||||||
def test_update_active_instance_entity_with_a_new_start_date(self):
|
def test_update_active_instance_entity_with_a_new_start_date(self):
|
||||||
fake_instance1 = a(instance())
|
fake_instance1 = a(instance())
|
||||||
fake_instance2 = fake_instance1
|
fake_instance2 = copy(fake_instance1)
|
||||||
fake_instance2.start = "2015-10-21T16:25:00.000000Z"
|
self._expect_get_active_entity_and_update(fake_instance1, fake_instance2, start="2015-10-21T16:25:00.000000Z")
|
||||||
|
|
||||||
(flexmock(self.database_adapter)
|
|
||||||
.should_receive("get_active_entity")
|
|
||||||
.with_args(fake_instance1.entity_id)
|
|
||||||
.and_return(fake_instance1)
|
|
||||||
.once())
|
|
||||||
|
|
||||||
(flexmock(self.database_adapter)
|
|
||||||
.should_receive("update_active_entity")
|
|
||||||
.with_args(fake_instance2)
|
|
||||||
.once())
|
|
||||||
|
|
||||||
self.controller.update_active_instance_entity(
|
self.controller.update_active_instance_entity(
|
||||||
instance_id=fake_instance1.entity_id,
|
instance_id=fake_instance1.entity_id,
|
||||||
start_date="2015-10-21T16:25:00.000000Z",
|
start_date="2015-10-21T16:25:00.000000Z",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_update_active_instance_entity_with_a_new_end_date(self):
|
||||||
|
fake_instance1 = a(instance())
|
||||||
|
fake_instance2 = copy(fake_instance1)
|
||||||
|
self._expect_get_active_entity_and_update(fake_instance1, fake_instance2, end="2015-10-21T16:25:00.000000Z")
|
||||||
|
|
||||||
|
self.controller.update_active_instance_entity(
|
||||||
|
instance_id=fake_instance1.entity_id,
|
||||||
|
end_date="2015-10-21T16:25:00.000000Z",
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_instance_updated_wrong_attributes_raises_exception(self):
|
||||||
|
fake_instance1 = a(instance())
|
||||||
|
|
||||||
|
(flexmock(self.database_adapter)
|
||||||
|
.should_receive("get_active_entity")
|
||||||
|
.with_args(fake_instance1.entity_id)
|
||||||
|
.and_return(fake_instance1)
|
||||||
|
.never())
|
||||||
|
|
||||||
|
assert_that(
|
||||||
|
calling(self.controller.update_active_instance_entity).with_args(instance_id=fake_instance1.entity_id,
|
||||||
|
wrong_attribute="this is wrong"),
|
||||||
|
raises(InvalidAttributeException))
|
||||||
|
|
||||||
def test_instance_created_but_its_an_old_event(self):
|
def test_instance_created_but_its_an_old_event(self):
|
||||||
fake_instance = a(instance()
|
fake_instance = a(instance()
|
||||||
.with_last_event(pytz.utc.localize(datetime(2015, 10, 21, 16, 29, 0))))
|
.with_last_event(pytz.utc.localize(datetime(2015, 10, 21, 16, 29, 0))))
|
||||||
|
@ -158,7 +230,7 @@ class ControllerTest(unittest.TestCase):
|
||||||
|
|
||||||
(flexmock(self.database_adapter)
|
(flexmock(self.database_adapter)
|
||||||
.should_receive("close_active_entity")
|
.should_receive("close_active_entity")
|
||||||
.with_args("id1", date_parser.parse("2015-10-21T16:25:00.000000Z"))
|
.with_args("id1", parse("2015-10-21T16:25:00.000000Z"))
|
||||||
.once())
|
.once())
|
||||||
|
|
||||||
self.controller.delete_instance("id1", "2015-10-21T16:25:00.000000Z")
|
self.controller.delete_instance("id1", "2015-10-21T16:25:00.000000Z")
|
||||||
|
@ -384,6 +456,10 @@ class ControllerTest(unittest.TestCase):
|
||||||
def test_volume_updated(self):
|
def test_volume_updated(self):
|
||||||
fake_volume = a(volume())
|
fake_volume = a(volume())
|
||||||
dates_str = "2015-10-21T16:25:00.000000Z"
|
dates_str = "2015-10-21T16:25:00.000000Z"
|
||||||
|
fake_volume.size = "new_size"
|
||||||
|
fake_volume.start = parse(dates_str)
|
||||||
|
fake_volume.end = None
|
||||||
|
fake_volume.last_event = parse(dates_str)
|
||||||
|
|
||||||
(flexmock(self.database_adapter)
|
(flexmock(self.database_adapter)
|
||||||
.should_receive("get_active_entity")
|
.should_receive("get_active_entity")
|
||||||
|
@ -392,12 +468,9 @@ class ControllerTest(unittest.TestCase):
|
||||||
.once())
|
.once())
|
||||||
(flexmock(self.database_adapter)
|
(flexmock(self.database_adapter)
|
||||||
.should_receive("close_active_entity")
|
.should_receive("close_active_entity")
|
||||||
.with_args(fake_volume.entity_id, date_parser.parse(dates_str))
|
.with_args(fake_volume.entity_id, parse(dates_str))
|
||||||
.once())
|
.once())
|
||||||
fake_volume.size = "new_size"
|
|
||||||
fake_volume.start = dates_str
|
|
||||||
fake_volume.end = None
|
|
||||||
fake_volume.last_event = dates_str
|
|
||||||
(flexmock(self.database_adapter)
|
(flexmock(self.database_adapter)
|
||||||
.should_receive("insert_entity")
|
.should_receive("insert_entity")
|
||||||
.with_args(fake_volume)
|
.with_args(fake_volume)
|
||||||
|
@ -648,3 +721,20 @@ class ControllerTest(unittest.TestCase):
|
||||||
.once())
|
.once())
|
||||||
|
|
||||||
self.assertEqual(len(self.controller.list_volume_types()), 2)
|
self.assertEqual(len(self.controller.list_volume_types()), 2)
|
||||||
|
|
||||||
|
def _expect_get_active_entity_and_update(self, fake_instance1, fake_instance2, **kwargs):
|
||||||
|
for key, value in kwargs.items():
|
||||||
|
if key in ['start', 'end']:
|
||||||
|
value = parse(value)
|
||||||
|
|
||||||
|
setattr(fake_instance2, key, value)
|
||||||
|
|
||||||
|
(flexmock(self.database_adapter)
|
||||||
|
.should_receive("get_active_entity")
|
||||||
|
.with_args(fake_instance1.entity_id)
|
||||||
|
.and_return(fake_instance1)
|
||||||
|
.once())
|
||||||
|
(flexmock(self.database_adapter)
|
||||||
|
.should_receive("update_active_entity")
|
||||||
|
.with_args(fake_instance2)
|
||||||
|
.once())
|
||||||
|
|
|
@ -18,8 +18,11 @@ import flask
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from voluptuous import Invalid
|
||||||
|
|
||||||
|
from almanach.common.validation_exception import InvalidAttributeException
|
||||||
from flexmock import flexmock, flexmock_teardown
|
from flexmock import flexmock, flexmock_teardown
|
||||||
from hamcrest import assert_that, has_key, equal_to, has_length, has_entry, has_entries
|
from hamcrest import assert_that, has_key, equal_to, has_length, has_entry, has_entries, is_
|
||||||
|
|
||||||
from almanach import config
|
from almanach import config
|
||||||
from almanach.common.date_format_exception import DateFormatException
|
from almanach.common.date_format_exception import DateFormatException
|
||||||
|
@ -84,9 +87,9 @@ class ApiTest(TestCase):
|
||||||
.with_args(
|
.with_args(
|
||||||
instance_id="INSTANCE_ID",
|
instance_id="INSTANCE_ID",
|
||||||
start_date=data["start_date"],
|
start_date=data["start_date"],
|
||||||
).and_return(a(instance().with_id('INSTANCE_ID')))
|
).and_return(a(instance().with_id('INSTANCE_ID').with_start(2014, 01, 01, 00, 0, 00)))
|
||||||
|
|
||||||
code, result = self.api_update(
|
code, result = self.api_put(
|
||||||
'/entity/instance/INSTANCE_ID',
|
'/entity/instance/INSTANCE_ID',
|
||||||
headers={'X-Auth-Token': 'some token value'},
|
headers={'X-Auth-Token': 'some token value'},
|
||||||
data=data,
|
data=data,
|
||||||
|
@ -96,6 +99,7 @@ class ApiTest(TestCase):
|
||||||
assert_that(result, has_key('entity_id'))
|
assert_that(result, has_key('entity_id'))
|
||||||
assert_that(result, has_key('start'))
|
assert_that(result, has_key('start'))
|
||||||
assert_that(result, has_key('end'))
|
assert_that(result, has_key('end'))
|
||||||
|
assert_that(result['start'], is_("2014-01-01 00:00:00"))
|
||||||
|
|
||||||
def test_instances_with_wrong_authentication(self):
|
def test_instances_with_wrong_authentication(self):
|
||||||
self.having_config('api_auth_token', 'some token value')
|
self.having_config('api_auth_token', 'some token value')
|
||||||
|
@ -870,9 +874,6 @@ class ApiTest(TestCase):
|
||||||
def api_delete(self, url, query_string=None, data=None, headers=None, accept='application/json'):
|
def api_delete(self, url, query_string=None, data=None, headers=None, accept='application/json'):
|
||||||
return self._api_call(url, "delete", data, query_string, headers, accept)
|
return self._api_call(url, "delete", data, query_string, headers, accept)
|
||||||
|
|
||||||
def api_update(self, url, data=None, query_string=None, headers=None, accept='application/json'):
|
|
||||||
return self._api_call(url, "put", data, query_string, headers, accept)
|
|
||||||
|
|
||||||
def _api_call(self, url, method, data=None, query_string=None, headers=None, accept='application/json'):
|
def _api_call(self, url, method, data=None, query_string=None, headers=None, accept='application/json'):
|
||||||
with self.app.test_client() as http_client:
|
with self.app.test_client() as http_client:
|
||||||
if not headers:
|
if not headers:
|
||||||
|
@ -890,6 +891,38 @@ class ApiTest(TestCase):
|
||||||
.should_receive(key)
|
.should_receive(key)
|
||||||
.and_return(value))
|
.and_return(value))
|
||||||
|
|
||||||
|
def test_update_active_instance_entity_with_wrong_attribute_exception(self):
|
||||||
|
errors = [
|
||||||
|
Invalid(message="error message1", path=["my_attribute1"]),
|
||||||
|
Invalid(message="error message2", path=["my_attribute2"]),
|
||||||
|
]
|
||||||
|
|
||||||
|
formatted_errors = {
|
||||||
|
"my_attribute1": "error message1",
|
||||||
|
"my_attribute2": "error message2",
|
||||||
|
}
|
||||||
|
|
||||||
|
self.having_config('api_auth_token', 'some token value')
|
||||||
|
instance_id = 'INSTANCE_ID'
|
||||||
|
data = {
|
||||||
|
'flavor': 'A_FLAVOR',
|
||||||
|
}
|
||||||
|
|
||||||
|
self.controller.should_receive('update_active_instance_entity') \
|
||||||
|
.with_args(instance_id=instance_id, **data) \
|
||||||
|
.once() \
|
||||||
|
.and_raise(InvalidAttributeException(errors))
|
||||||
|
|
||||||
|
code, result = self.api_put(
|
||||||
|
'/entity/instance/INSTANCE_ID',
|
||||||
|
data=data,
|
||||||
|
headers={'X-Auth-Token': 'some token value'}
|
||||||
|
)
|
||||||
|
assert_that(result, has_entries({
|
||||||
|
"error": formatted_errors
|
||||||
|
}))
|
||||||
|
assert_that(code, equal_to(400))
|
||||||
|
|
||||||
|
|
||||||
class DateMatcher(object):
|
class DateMatcher(object):
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from almanach.common.validation_exception import InvalidAttributeException
|
||||||
|
from almanach.validators.instance_validator import InstanceValidator
|
||||||
|
from hamcrest import assert_that, calling, raises, is_
|
||||||
|
|
||||||
|
|
||||||
|
class InstanceValidatorTests(unittest.TestCase):
|
||||||
|
def test_validate_update_with_invalid_attribute(self):
|
||||||
|
instance_validator = InstanceValidator()
|
||||||
|
payload = {"invalid attribute": ".."}
|
||||||
|
assert_that(calling(instance_validator.validate_update).with_args(payload),
|
||||||
|
raises(InvalidAttributeException))
|
||||||
|
|
||||||
|
def test_validate_update_with_valid_name_attribute(self):
|
||||||
|
instance_validator = InstanceValidator()
|
||||||
|
payload = {"name": u"instance name"}
|
||||||
|
|
||||||
|
assert_that(instance_validator.validate_update(payload), is_(payload))
|
||||||
|
|
||||||
|
def test_validate_update_with_invalid_name_attribute(self):
|
||||||
|
instance_validator = InstanceValidator()
|
||||||
|
payload = {"name": 123}
|
||||||
|
|
||||||
|
assert_that(calling(instance_validator.validate_update).with_args(payload),
|
||||||
|
raises(InvalidAttributeException))
|
||||||
|
|
||||||
|
def test_validate_update_with_valid_flavor_attribute(self):
|
||||||
|
instance_validator = InstanceValidator()
|
||||||
|
payload = {"flavor": u"flavor"}
|
||||||
|
|
||||||
|
assert_that(instance_validator.validate_update(payload), is_(payload))
|
||||||
|
|
||||||
|
def test_validate_update_with_invalid_flavor_attribute(self):
|
||||||
|
instance_validator = InstanceValidator()
|
||||||
|
payload = {"flavor": 123}
|
||||||
|
|
||||||
|
assert_that(calling(instance_validator.validate_update).with_args(payload),
|
||||||
|
raises(InvalidAttributeException))
|
||||||
|
|
||||||
|
def test_validate_update_with_valid_start_date(self):
|
||||||
|
instance_validator = InstanceValidator()
|
||||||
|
payload = {"start_date": "2015-10-21T16:25:00.000000Z"}
|
||||||
|
|
||||||
|
assert_that(instance_validator.validate_update(payload),
|
||||||
|
is_(payload))
|
||||||
|
|
||||||
|
def test_validate_update_with_invalid_start_date(self):
|
||||||
|
instance_validator = InstanceValidator()
|
||||||
|
payload = {"start_date": "2015-10-21"}
|
||||||
|
|
||||||
|
assert_that(calling(instance_validator.validate_update).with_args(payload),
|
||||||
|
raises(InvalidAttributeException))
|
||||||
|
|
||||||
|
def test_validate_update_with_valid_end_date(self):
|
||||||
|
instance_validator = InstanceValidator()
|
||||||
|
payload = {"end_date": "2015-10-21T16:25:00.000000Z"}
|
||||||
|
|
||||||
|
assert_that(instance_validator.validate_update(payload),
|
||||||
|
is_(payload))
|
||||||
|
|
||||||
|
def test_validate_update_with_invalid_end_date(self):
|
||||||
|
instance_validator = InstanceValidator()
|
||||||
|
payload = {"end_date": "2016"}
|
||||||
|
|
||||||
|
assert_that(calling(instance_validator.validate_update).with_args(payload),
|
||||||
|
raises(InvalidAttributeException))
|
||||||
|
|
||||||
|
def test_validate_update_with_valid_os_attribute(self):
|
||||||
|
instance_validator = InstanceValidator()
|
||||||
|
payload = {
|
||||||
|
"os": {
|
||||||
|
"distro": u"centos",
|
||||||
|
"version": u"7",
|
||||||
|
"os_type": u"linux",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_that(instance_validator.validate_update(payload), is_(payload))
|
||||||
|
|
||||||
|
def test_validate_update_with_invalid_os_attribute(self):
|
||||||
|
instance_validator = InstanceValidator()
|
||||||
|
payload = {
|
||||||
|
"os": {
|
||||||
|
"distro": u"centos",
|
||||||
|
"os_type": u"linux",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_that(calling(instance_validator.validate_update).with_args(payload),
|
||||||
|
raises(InvalidAttributeException))
|
||||||
|
|
||||||
|
def test_validate_update_with_valid_metadata_attribute(self):
|
||||||
|
instance_validator = InstanceValidator()
|
||||||
|
payload = {
|
||||||
|
"metadata": {
|
||||||
|
"key": "value"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_that(instance_validator.validate_update(payload), is_(payload))
|
||||||
|
|
||||||
|
instance_validator = InstanceValidator()
|
||||||
|
payload = {
|
||||||
|
"metadata": {}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_that(instance_validator.validate_update(payload), is_(payload))
|
||||||
|
|
||||||
|
def test_validate_update_with_invalid_metadata_attribute(self):
|
||||||
|
instance_validator = InstanceValidator()
|
||||||
|
payload = {
|
||||||
|
"metadata": "foobar"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_that(calling(instance_validator.validate_update).with_args(payload),
|
||||||
|
raises(InvalidAttributeException))
|
Loading…
Reference in New Issue