From fd31aae8e8eefda12c6abc450ed776b35aa3d80e Mon Sep 17 00:00:00 2001 From: Samantha Blanco Date: Thu, 30 Nov 2017 12:17:33 -0500 Subject: [PATCH] Add API unit tests Add unit tests for Promenade API endpoints. Also adds validatedesign API endpoint. Change-Id: I4c6a5da1f521f913c94ae8a07c8bc43cf4114f75 --- promenade/control/api.py | 2 + promenade/control/validatedesign.py | 59 +++++++++++++++++++++++++++++ promenade/validation.py | 16 ++++++++ tests/test_placeholder.py | 2 - tests/unit/__init__.py | 0 tests/unit/api/__init__.py | 0 tests/unit/api/test_health_api.py | 15 ++++++++ tests/unit/api/test_versions.py | 18 +++++++++ tox.ini | 10 +++-- 9 files changed, 117 insertions(+), 5 deletions(-) create mode 100644 promenade/control/validatedesign.py delete mode 100644 tests/test_placeholder.py create mode 100644 tests/unit/__init__.py create mode 100644 tests/unit/api/__init__.py create mode 100644 tests/unit/api/test_health_api.py create mode 100644 tests/unit/api/test_versions.py diff --git a/promenade/control/api.py b/promenade/control/api.py index d4dc4420..6e8c2b25 100644 --- a/promenade/control/api.py +++ b/promenade/control/api.py @@ -19,6 +19,7 @@ from promenade.control.health_api import HealthResource from promenade.control.join_scripts import JoinScriptsResource from promenade.control.middleware import (AuthMiddleware, ContextMiddleware, LoggingMiddleware) +from promenade.control.validatedesign import ValidateDesignResource from promenade import exceptions as exc from promenade import logging @@ -39,6 +40,7 @@ def start_api(): # API for managing region data ('/health', HealthResource()), ('/join-scripts', JoinScriptsResource()), + ('/validatedesign', ValidateDesignResource()), ] # Set up the 1.0 routes diff --git a/promenade/control/validatedesign.py b/promenade/control/validatedesign.py new file mode 100644 index 00000000..128737fd --- /dev/null +++ b/promenade/control/validatedesign.py @@ -0,0 +1,59 @@ +# Copyright 2017 AT&T Intellectual Property. All other rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import json +import logging + +import falcon + +from promenade.config import Configuration +from promenade.control import base +from promenade import exceptions +from promenade import validation + +LOG = logging.getLogger(__name__) + + +class ValidateDesignResource(base.BaseResource): + def _return_msg(self, resp, status_code, status="Valid", message=""): + if status_code is falcon.HTTP_200: + count = 0 + msg_list = [] + else: + count = 1 + msg_list = [message] + resp.body = json.dumps({ + "kind": "Status", + "apiVersion": "v1", + "metadata": {}, + "status": status, + "message": message, + "reason": "Validation", + "details": { + "errorCount": count, + "messageList": msg_list, + }, + "code": status_code, + }) + + def on_post(self, req, resp): + href = req.get_param('href', required=True) + try: + config = Configuration.from_design_ref(href) + validation.check_design(config) + msg = "Promenade validations succeeded" + return self._return_msg(resp, falcon.HTTP_200, message=msg) + except exceptions.ValidationException as e: + msg = "Promenade validations failed: %s" % str(e) + return self._return_msg( + resp, falcon.HTTP_400, status="Invalid", message=msg) diff --git a/promenade/validation.py b/promenade/validation.py index 8d69a664..ed73ef43 100644 --- a/promenade/validation.py +++ b/promenade/validation.py @@ -24,6 +24,22 @@ __all__ = ['check_schema', 'check_schemas'] LOG = logging.getLogger(__name__) +def check_design(config): + kinds = ['Docker', 'HostSystem', 'Kubelet', 'KubernetesNetwork'] + for kind in kinds: + count = 0 + for doc in config.documents: + schema = doc.get('schema', None) + if not schema: + raise exceptions.ValidationException( + '"schema" is a required document key.') + name = schema.split('/')[1] + if name == kind: + count += 1 + if count != 1: + raise exceptions.ValidationException() + + def check_schemas(documents): for document in documents: check_schema(document) diff --git a/tests/test_placeholder.py b/tests/test_placeholder.py deleted file mode 100644 index 201975fc..00000000 --- a/tests/test_placeholder.py +++ /dev/null @@ -1,2 +0,0 @@ -def test_placeholder(): - pass diff --git a/tests/unit/__init__.py b/tests/unit/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/unit/api/__init__.py b/tests/unit/api/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/unit/api/test_health_api.py b/tests/unit/api/test_health_api.py new file mode 100644 index 00000000..78dd6cbb --- /dev/null +++ b/tests/unit/api/test_health_api.py @@ -0,0 +1,15 @@ +import falcon +from falcon import testing +import pytest + +from promenade.control import health_api +from promenade.promenade import promenade + + +@pytest.fixture() +def client(): + return testing.TestClient(promenade) + +def test_get_health(client): + response = client.simulate_get('/api/v1.0/health') + assert response.status == falcon.HTTP_204 diff --git a/tests/unit/api/test_versions.py b/tests/unit/api/test_versions.py new file mode 100644 index 00000000..59070cba --- /dev/null +++ b/tests/unit/api/test_versions.py @@ -0,0 +1,18 @@ +import falcon +from falcon import testing +import pytest + +from promenade.control.api import VersionsResource +from promenade.promenade import promenade + + +@pytest.fixture() +def client(): + return testing.TestClient(promenade) + +def test_get_versions(client): + response = client.simulate_get('/versions') + assert response.status == falcon.HTTP_200 + body = response.content.decode('utf-8') + assert '"path": "/api/v1.0"' in body + assert '"status": "stable"' in body diff --git a/tox.ini b/tox.ini index 7f85cb16..5a44b625 100644 --- a/tox.ini +++ b/tox.ini @@ -1,14 +1,18 @@ [tox] -envlist = bandit,lint,docs +envlist = py35,unit,bandit,lint,docs [testenv] -deps = -r{toxinidir}/requirements.txt - -r{toxinidir}/test-requirements.txt setenv= PYTHONWARNING=all commands= pytest \ {posargs} +deps = -r{toxinidir}/requirements-frozen.txt + -r{toxinidir}/test-requirements.txt + +[testenv:unit] +commands = + pytest tests/unit [testenv:bandit] deps = bandit==1.4.0