diff options
Diffstat (limited to 'ice-server/heat_test')
-rw-r--r-- | ice-server/heat_test/__init__.py | 0 | ||||
-rw-r--r-- | ice-server/heat_test/app.py | 65 | ||||
-rw-r--r-- | ice-server/heat_test/default_settings.py | 9 | ||||
-rw-r--r-- | ice-server/heat_test/heat_validator.py | 79 | ||||
-rw-r--r-- | ice-server/heat_test/swagger/ice_api.yaml | 85 | ||||
-rw-r--r-- | ice-server/heat_test/test/fixture/test.zip | bin | 0 -> 166 bytes | |||
-rw-r--r-- | ice-server/heat_test/test/test_api.py | 62 |
7 files changed, 300 insertions, 0 deletions
diff --git a/ice-server/heat_test/__init__.py b/ice-server/heat_test/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/ice-server/heat_test/__init__.py diff --git a/ice-server/heat_test/app.py b/ice-server/heat_test/app.py new file mode 100644 index 0000000..e982c68 --- /dev/null +++ b/ice-server/heat_test/app.py @@ -0,0 +1,65 @@ +#!flask/bin/python +import argparse +import logging +import requests + +import connexion +from connexion.resolver import RestyResolver + + +def parse_args(): + """ + parse argument parameters + """ + parser = argparse.ArgumentParser(description='start the heat validation rest server') + parser.add_argument("--debug", help="increase output verbosity") + parser.add_argument("-p", "--port", type=int, help="listen port (default 5000)", default=5000) + args = parser.parse_args() + if args.debug: + logging.info("debug mode") + debug = True + else: + debug = False + if args.port: + port = args.port + else: + port = 5000 + + +def create_app(): + logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') + app = connexion.App(__name__, specification_dir='swagger/') + + # load default config + app.app.config.from_object("default_settings") + app.app.config.from_envvar('ICE_SETTINGS', silent=True) + app.add_api('ice_api.yaml', swagger_ui=app.app.config['DEBUG'], resolver=RestyResolver('ice_validator')) + + return app + +def create_test_app(): + print("create_test_app") + logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') + app = connexion.App(__name__, specification_dir='swagger/') + app.add_api('ice_api.yaml', swagger_ui=app.app.config['DEBUG'], resolver=RestyResolver('ice_validator')) + app.app.testing = True + return app + + +def start_app(app): + logging.info("######################################") + logging.info("starting server") + logging.info("######################################") + app.run(port=app.app.config['ICE_PORT'], debug=app.app.config['DEBUG']) + + # register service in MSB + try: + msb_url = app.app.config['MSB_URL'] + requests.get(msb_url) + logging.info("registration to %s done", msb_url) + except: + logging.info("registration to %s failed", msb_url) + + +if __name__ == '__main__': + start_app(create_app()) diff --git a/ice-server/heat_test/default_settings.py b/ice-server/heat_test/default_settings.py new file mode 100644 index 0000000..d32d039 --- /dev/null +++ b/ice-server/heat_test/default_settings.py @@ -0,0 +1,9 @@ +# ICE settings +DEBUG = True +ICE_PORT = 5000 + +# MSB settings +MSB_IP = "127.0.0.1" +MSB_PORT = "80" +MSB_URL = "http://"+MSB_IP+':'+MSB_PORT+"/api/microservices/v1/services" + diff --git a/ice-server/heat_test/heat_validator.py b/ice-server/heat_test/heat_validator.py new file mode 100644 index 0000000..0cc32a1 --- /dev/null +++ b/ice-server/heat_test/heat_validator.py @@ -0,0 +1,79 @@ +import logging +import os +import shutil +import sys +import tempfile +import zipfile +from io import StringIO + +import pytest +from flask import (request, jsonify, abort) + + +class HeatValidator(object): + """REST service for HEAT templates validation""" + + # Customize messages for pytest exit codes... + msg = {0: 'OK', + 1: 'Tests failed', + 2: 'Interrupted', + 3: 'Internal error', + 4: 'Usage error', + 5: 'No tests collected'} + + def ping(self): + return "pong" + + def validate(self): + """validate the heat template contained in the uploaded zipfile + by running the ice_validator scripts""" + logging.info("validate") + + # check if the post request is valid + if 'file' not in request.files: + logging.error("invalid request: no file found") + abort(422, {'status': 1, 'message': 'no file found'}) + + try: + # extract the uploaded archive + zip_file = request.files['file'] + tmp_dir = tempfile.mkdtemp() + zip_ref = zipfile.ZipFile(zip_file, 'r') + zip_ref.extractall(tmp_dir) + zip_ref.close() + debug = request.args.get('debug') + + # execute the validation scripts with pytest + if debug == 'true': + # Save the original stream output, the console basically + original_output = sys.stdout + # Assign StringIO so the output is not sent anymore to the console + sys.stdout = StringIO() + exit_code = pytest.main(['../../validation-scripts/ice_validator', + '--resultlog=' + tmp_dir + '/result.txt', + '--template-dir', tmp_dir]) + with open(tmp_dir + '/result.txt', 'r') as result_file: + result = result_file.read() + if debug == 'true': + output = sys.stdout.getvalue() + # close the stream and reset stdout to the original value (console) + sys.stdout.close() + sys.stdout = original_output + except zipfile.BadZipFile: + logging.exception("invalid file") + abort(422, {'status': 4, 'message': 'invalid file'}) + except: + logging.exception("server error on file") + abort(500, {'status': 3, 'message': 'server error'}) + finally: + if os.path.exists(tmp_dir): + shutil.rmtree(tmp_dir) + + result = {'status': exit_code, 'message': self.msg[exit_code], 'result': result} + if debug == 'true': + result['debug'] = output + + return jsonify(result), 200 if (exit_code == 0) else 422 + + +class_instance = HeatValidator() diff --git a/ice-server/heat_test/swagger/ice_api.yaml b/ice-server/heat_test/swagger/ice_api.yaml new file mode 100644 index 0000000..c12269f --- /dev/null +++ b/ice-server/heat_test/swagger/ice_api.yaml @@ -0,0 +1,85 @@ +swagger: "2.0" + +info: + title: "ICE validation" + description: "Heat template validation rest API" + contact: + name: ONAP + url: https://www.onap.org + email: onap-discuss@lists.onap.org + license: + name: Apache 2.0 + url: http://www.apache.org/licenses/LICENSE-2.0.html + version: "1.0.0" + +basePath: /onapapi/ice/v1 + +paths: + /: + get: + summary: "list HEAT templates" + operationId: heat_validator.class_instance.ping + responses: + '200': + description: 'server is up and running' + schema: + type: string + post: + summary: "validate HEAT template" + operationId: heat_validator.class_instance.validate + consumes: [ + "multipart/form-data" + ] + produces: [ + "application/json" + ] + parameters: [ + { + "name": "file", + "in": "formData", + "description": "file to upload", + "required": true, + "type": "file" + }, + { + "name": "debug", + "in": "query", + "description": "debug mode", + "required": false, + "type": "boolean" + } + ] + responses: + "200": + description: 'validation success' + schema: { + "$ref": "#/definitions/Result" + } + "400": + description: 'validation error' + schema: { + "$ref": "#/definitions/Result" + } + "500": + description: 'validation error' + schema: { + "$ref": "#/definitions/Result" + } +definitions: + Result: + required: [ + "status", + "message" + ] + properties: { + "status": { + "type": "integer", + "format": "int64" + }, + "message": { + "type": "string" + }, + "debug": { + "type": "string" + } + }
\ No newline at end of file diff --git a/ice-server/heat_test/test/fixture/test.zip b/ice-server/heat_test/test/fixture/test.zip Binary files differnew file mode 100644 index 0000000..d1e6d99 --- /dev/null +++ b/ice-server/heat_test/test/fixture/test.zip diff --git a/ice-server/heat_test/test/test_api.py b/ice-server/heat_test/test/test_api.py new file mode 100644 index 0000000..259a43b --- /dev/null +++ b/ice-server/heat_test/test/test_api.py @@ -0,0 +1,62 @@ +import io +import json +import os +import sys + +import pytest + +#sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir)) + +# Make sure that the application source directory (this directory's parent) is +# on sys.path. +here = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +sys.path.insert(0, here) +print(sys.path) + +import app as myapp + +ICE_URL = '/ice/' + +flask_app = myapp.create_test_app() + + +@pytest.fixture(scope='module') +def client(): + with flask_app.app.test_client() as c: + yield c + + +def test_404(client): + response = client.get('/dummy') + assert response.status_code == 404 + + +def test_ping(client): + response = client.get(ICE_URL, content_type='application/json') + assert response.status_code == 200 + + +def test_validate_nofile(client): + response = client.post(ICE_URL) + assert response.status_code == 400 + assert json_of_response(response) is not None + + +def test_validate_not_zip(client): + data = {'file': (io.BytesIO(b'my file contents'), 'hello world.txt')} + response = client.post(ICE_URL, data=data) + assert response.status_code == 422 + + +@pytest.mark.skip(reason="no way of currently testing this") +def test_validate_bad_zip(client): + zf = os.path.join(os.path.dirname(__file__), 'fixture/test.zip') + data = {'file': (zf, 'test.zip')} + response = client.post(ICE_URL, data=data) + print("##"+zf) + assert response.status_code == 200 + + +def json_of_response(response): + """Decode json from response""" + return json.loads(response.data.decode('utf8')) |