diff --git a/valence/api/v1/podmanagers.py b/valence/api/v1/podmanagers.py index c969fbb..3357115 100644 --- a/valence/api/v1/podmanagers.py +++ b/valence/api/v1/podmanagers.py @@ -21,6 +21,7 @@ from six.moves import http_client from valence.common import exception from valence.common import utils from valence.controller import podmanagers +from valence.validation import validator LOG = logging.getLogger(__name__) @@ -31,6 +32,7 @@ class PodManagersList(flask_restful.Resource): def get(self): return utils.make_response(http_client.OK, podmanagers.get_podm_list()) + @validator.check_input('podmanager_schema') def post(self): values = flask.request.get_json() return utils.make_response(http_client.OK, diff --git a/valence/controller/podmanagers.py b/valence/controller/podmanagers.py index 5cd9697..3714006 100644 --- a/valence/controller/podmanagers.py +++ b/valence/controller/podmanagers.py @@ -33,22 +33,6 @@ def _check_creation(values): :returns: improved values that could be inserted to db """ - if not ('name' in values and - 'url' in values and - 'authentication' in values): - raise exception.BadRequest(detail="Incomplete parameters") - # check authentication's format and content - try: - if not (values['authentication'][0]['type'] and - values['authentication'][0]['auth_items']): - LOG.error("invalid authentication when creating podmanager") - raise exception.BadRequest(detail="invalid " - "authentication properties") - except KeyError: - LOG.error("Incomplete parameters when creating podmanager") - raise exception.BadRequest(detail="invalid " - "authentication properties") - pod_manager_list = get_podm_list() names = [podm['name'] for podm in pod_manager_list] urls = [podm['url'] for podm in pod_manager_list] diff --git a/valence/tests/unit/controller/test_podmanagers.py b/valence/tests/unit/controller/test_podmanagers.py index fd8a85e..c78d8f1 100644 --- a/valence/tests/unit/controller/test_podmanagers.py +++ b/valence/tests/unit/controller/test_podmanagers.py @@ -53,28 +53,6 @@ class TestPodManagers(unittest.TestCase): values['authentication']) mock_get_podm_list.assert_called_once_with() - def test_check_creation_incomplete_parameters(self): - incomplete_values = { - 'name': 'name', - 'url': 'url' - } - self.assertRaises(BadRequest, - podmanagers._check_creation, - incomplete_values) - - def test_check_creation_invalid_authentication(self): - invalid_authentication_values = { - "name": "podm_name", - "url": "https://10.0.0.2", - 'authentication': { - "username": "username", - "password": "password" - } - } - self.assertRaises(BadRequest, - podmanagers._check_creation, - invalid_authentication_values) - @mock.patch('valence.controller.podmanagers.get_podm_list') def test_check_creation_duplicate_Exception(self, mock_get_podm_list): mock_get_podm_list.return_value = [ diff --git a/valence/tests/unit/validation/test_validation.py b/valence/tests/unit/validation/test_validation.py index 776b7b9..bc38cc3 100644 --- a/valence/tests/unit/validation/test_validation.py +++ b/valence/tests/unit/validation/test_validation.py @@ -1,9 +1,11 @@ +import copy import json import mock from oslotest import base from valence.api import app as flask_app +from valence.common import constants from valence.tests.unit.fakes import flavor_fakes @@ -15,6 +17,11 @@ class TestApiValidation(base.BaseTestCase): app = flask_app.get_app() app.config['TESTING'] = True self.app = app.test_client() + + +class TestFlavorApi(TestApiValidation): + def setUp(self): + super(TestFlavorApi, self).setUp() self.flavor = flavor_fakes.fake_flavor() @mock.patch('valence.controller.flavors.create_flavor') @@ -48,3 +55,61 @@ class TestApiValidation(base.BaseTestCase): response = json.loads(response.data.decode()) self.assertEqual(400, response['status']) self.assertEqual('ValidationError', response['code']) + + +class TestPodmanagerApi(TestApiValidation): + + @mock.patch('valence.controller.podmanagers.create_podm') + @mock.patch('valence.controller.podmanagers.get_podm_list') + @mock.patch('valence.controller.podmanagers.get_podm_status') + def test_podmanager_create(self, pstatus_mock, plist_mock, pcreate_mock): + pstatus_mock.return_value = constants.PODM_STATUS_ONLINE + plist_mock.return_value = [] + values = { + "name": "podm_name", + "url": "https://10.240.212.123", + "authentication": [ + { + "type": "basic", + "auth_items": + { + "username": "xxxxxxx", + "password": "xxxxxxx" + } + }] + } + result = copy.deepcopy(values) + result['status'] = constants.PODM_STATUS_ONLINE + pcreate_mock.return_value = result + response = self.app.post('/v1/pod_managers', + content_type='application/json', + data=json.dumps(values)) + self.assertEqual(200, response.status_code) + + def test_check_creation_incomplete_parameters(self): + incomplete_values = { + 'name': 'name', + 'url': 'url' + } + response = self.app.post('/v1/pod_managers', + content_type='application/json', + data=json.dumps(incomplete_values)) + response = json.loads(response.data.decode()) + self.assertEqual(400, response['status']) + self.assertEqual('ValidationError', response['code']) + + def test_check_creation_invalid_authentication(self): + invalid_auth_values = { + "name": "podm_name", + "url": "https://10.0.0.2", + 'authentication': { + "username": "username", + "password": "password" + } + } + response = self.app.post('/v1/pod_managers', + content_type='application/json', + data=json.dumps(invalid_auth_values)) + response = json.loads(response.data.decode()) + self.assertEqual(400, response['status']) + self.assertEqual('ValidationError', response['code']) diff --git a/valence/validation/schemas.py b/valence/validation/schemas.py index 18d3fdd..5c6f315 100644 --- a/valence/validation/schemas.py +++ b/valence/validation/schemas.py @@ -32,6 +32,43 @@ flavor_schema = { 'additionalProperties': False, } - jsonschema.Draft4Validator.check_schema(flavor_schema) -SCHEMAS = {'flavor_schema': flavor_schema} + +podmanager_schema = { + 'type': 'object', + 'properties': { + 'name': {'type': 'string'}, + 'url': { + 'type': 'string', + 'format': 'uri', + }, + 'authentication': { + 'type': 'array', + 'minItems': 1, + 'items': { + 'type': 'object', + 'properties': { + 'type': {'type': 'string'}, + 'auth_items': { + 'type': 'object', + 'properties': { + 'username': {'type': 'string'}, + 'password': {'type': 'string'}, + }, + 'required': ['username', 'password'], + 'additionalProperties': False, + }, + }, + 'required': ['type', 'auth_items'], + 'additionalProperties': False, + }, + }, + }, + 'required': ['name', 'url', 'authentication'], + 'additionalProperties': False, +} + + +jsonschema.Draft4Validator.check_schema(podmanager_schema) +SCHEMAS = {'flavor_schema': flavor_schema, + 'podmanager_schema': podmanager_schema, } diff --git a/valence/validation/validator.py b/valence/validation/validator.py index 6956b99..e187965 100644 --- a/valence/validation/validator.py +++ b/valence/validation/validator.py @@ -49,5 +49,12 @@ class Validator(object): try: self.validator.validate(data) except jsonschema.ValidationError as e: + if len(e.path) > 0: + detail = (("Invalid input for field/attribute '%(path)s' " + "Value: '%(value)s'. %(message)s") % + {'path': e.path.pop(), 'value': e.instance, + 'message': e.message}) + else: + detail = e.message LOG.exception("Failed to validate the input") - raise exception.ValidationError(detail=e.message) + raise exception.ValidationError(detail=detail)