diff --git a/.travis.yml b/.travis.yml index c396b2e..a99bc8c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,14 @@ language: python python: - - "3.6" - - "3.7" - "3.8" install: - - pip install --upgrade setuptools tox tox-travis coveralls + - python -m pip install --upgrade pip + - pip install --upgrade setuptools coveralls pipenv + - pipenv lock --dev --requirements > requirements.txt + - pip install -r requirements.txt script: - coverage erase - - tox + - python setup.py test after_success: - coverage combine - coveralls diff --git a/README.md b/README.md index c61c12b..ca5610f 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ microservices with Python which handles cross-cutting concerns: - Metrics - Distributed tracing +![Python package](https://github.com/python-microservices/microservices-scaffold/workflows/Python%20package/badge.svg?branch=master) [![Build Status](https://travis-ci.org/python-microservices/microservices-scaffold.svg?branch=master)](https://travis-ci.org/python-microservices/microservices-scaffold) [![Coverage Status](https://coveralls.io/repos/github/python-microservices/microservices-scaffold/badge.svg?branch=master)](https://coveralls.io/github/python-microservices/microservices-scaffold?branch=master) [![Requirements Status](https://requires.io/github/python-microservices/microservices-scaffold/requirements.svg?branch=master)](https://requires.io/github/python-microservices/microservices-scaffold/requirements/?branch=master) @@ -21,6 +22,7 @@ Table of Contents * [microservices-scaffold](#microservices-scaffold) * [How to run the scaffold](#how-to-run-the-scaffold) * [Installation](#installation) + * [Clone the repository](#clone-the-repository) * [Install with virtualenv](#install-with-virtualenv) * [Install with pipenv](#install-with-pipenv) * [Advantages over plain pip and requirements.txt](#advantages-over-plain-pip-and-requirementstxt) @@ -28,13 +30,19 @@ Table of Contents * [Check the result](#check-the-result) * [Docker](#docker) * [Kubernetes](#kubernetes) - * [How to contrib](#how-to-contrib) - * [Update docs](#update-docs) + * [How To contribute](#how-to-contribute) # How to run the scaffold ## Installation +### Clone the repository + +```bash +git clone git@github.com:purwowd/microservices-scaffold.git +cd microservices-scaffold +``` + ### Install with virtualenv ```bash virtualenv --python=python[3.6|3.7|3.8] venv @@ -50,8 +58,6 @@ pipenv install ### Install on MacOS ```bash -git clone git@github.com:purwowd/microservices-scaffold.git -cd microservices-scaffold virtualenv -p python3 venv source venv/bin/activate pip3 install -r requirements.txt @@ -123,9 +129,8 @@ You can dockerize this microservice with these steps: You can run this microservice in a Kubernetes cluster with: kubectl apply -f service.yaml - -See a simple tutorial in [the doc](https://microservices-scaffold.readthedocs.io/en/latest/runinkubernetes.html) - -## How to contrib -https://github.com/python-microservices/microservices-scaffold/blob/master/CONTRIBUTING.md +# How To contribute + +We appreciate opening issues and pull requests to make PyMS even more stable & useful! See [This doc](CONTRIBUTING.md) +for more details \ No newline at end of file diff --git a/config-docker.yml b/config-docker.yml index 98bb282..0daee96 100644 --- a/config-docker.yml +++ b/config-docker.yml @@ -3,7 +3,7 @@ pyms: requests: data: "" swagger: - path: "swagger" + path: "project/swagger" file: "swagger.yaml" url: "/ui/" project_dir: "project.views" @@ -15,7 +15,7 @@ pyms: DEBUG: false TESTING: false APP_NAME: Films&Actors - APPLICATION_ROOT : "" + APPLICATION_ROOT : "/" SQLALCHEMY_TRACK_MODIFICATIONS: true SECRET_KEY: "gjr39dkjn344_!67#" DATABASE: db.sqlite3 diff --git a/config.yml b/config.yml index 0ec4836..977c8a8 100644 --- a/config.yml +++ b/config.yml @@ -3,7 +3,7 @@ pyms: requests: data: "" swagger: - path: "swagger" + path: "project/swagger" file: "swagger.yaml" url: "/ui/" project_dir: "project.views" @@ -12,11 +12,11 @@ pyms: host: "localhost" component_name: "Python Microservice" config: - DEBUG: false + DEBUG: true TESTING: false APP_NAME: Films&Actors - APPLICATION_ROOT : "" + APPLICATION_ROOT : "/" SQLALCHEMY_TRACK_MODIFICATIONS: true SECRET_KEY: "gjr39dkjn344_!67#" DATABASE: db.sqlite3 - SQLALCHEMY_DATABASE_URI: sqlite:///db.sqlite3 \ No newline at end of file + SQLALCHEMY_DATABASE_URI: sqlite:///project/db.sqlite3 \ No newline at end of file diff --git a/manage.py b/manage.py index e0b1de1..1871f12 100644 --- a/manage.py +++ b/manage.py @@ -1,7 +1,17 @@ # encoding: utf-8 from flask_script import Manager -from project.app import create_app +from project.app import MyMicroservice + + +def create_app(): + """Initialize the Flask app, register blueprints and intialize all libraries like Swagger, database, the trace system... + return the app and the database objects. + :return: + """ + ms = MyMicroservice(path=__file__) + return ms.create_app() + app = create_app() diff --git a/project/app.py b/project/app.py index a08101e..f5da060 100644 --- a/project/app.py +++ b/project/app.py @@ -71,12 +71,3 @@ def init_logger(self) -> None: } logging.config.dictConfig(LOGGING) - - -def create_app(): - """Initialize the Flask app, register blueprints and intialize all libraries like Swagger, database, the trace system... - return the app and the database objects. - :return: - """ - ms = MyMicroservice(path=__file__) - return ms.create_app() diff --git a/tests/config-tests.yml b/tests/config-tests.yml index f41578d..140cf3c 100644 --- a/tests/config-tests.yml +++ b/tests/config-tests.yml @@ -3,7 +3,7 @@ pyms: requests: data: "" swagger: - path: "swagger" + path: "project/swagger" file: "swagger.yaml" url: "/ui/" project_dir: "project.views" @@ -12,12 +12,12 @@ pyms: host: "localhost" component_name: "Python Microservice2" config: - DEBUG: false + DEBUG: true TESTING: true TEST_VAR: "1234" APP_NAME: Films&Actors - APPLICATION_ROOT : "" + APPLICATION_ROOT : "/" SQLALCHEMY_TRACK_MODIFICATIONS: true SECRET_KEY: "gjr39dkjn344_!67#" DATABASE: db.sqlite3 - SQLALCHEMY_DATABASE_URI: sqlite:///db.sqlite3 \ No newline at end of file + SQLALCHEMY_DATABASE_URI: sqlite:///project/db_tests.sqlite3 \ No newline at end of file diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..833285f --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,58 @@ +import os + +import pytest + +from manage import create_app +from project.models.init_db import db as _db + + +def conf_environment(): + if not os.environ.get("CONFIGMAP_FILE", False): + os.environ["CONFIGMAP_FILE"] = os.path.join(os.path.dirname(os.path.abspath(__file__)), "config-tests.yml") + + +@pytest.fixture(scope="session") +def app(): + conf_environment() + app = create_app() + return app + + +@pytest.fixture(scope="module") +def client(app, db): + """A test client for the app.""" + return app.test_client() + + +@pytest.fixture(scope="module") +def base_url(app): + """Base url of the service.""" + return app.config["APPLICATION_ROOT"] + + +@pytest.fixture(scope="session") +def db(app, request): + def teardown(): + _db.drop_all() + + _db.app = app + _db.init_app(app) + _db.create_all() + + request.addfinalizer(teardown) + + return _db + + +@pytest.fixture(scope="session") +def db_handler(app_handler, request): + def teardown(): + _db.drop_all() + + _db.app = app_handler + _db.init_app(app_handler) + _db.create_all() + + request.addfinalizer(teardown) + + return _db diff --git a/tests/test_views.py b/tests/test_views.py index beaf85b..2d16406 100644 --- a/tests/test_views.py +++ b/tests/test_views.py @@ -1,11 +1,7 @@ import json -import os -import pytest from typing import Dict, List, Union, Text -from pyms.constants import CONFIGMAP_FILE_ENVIRONMENT -from pyms.flask.app import config -from project.app import MyMicroservice +from pyms.flask.app import config backup_config = config() @@ -17,63 +13,50 @@ def _format_response(response: Text = "") -> Union[List, Dict]: return json.loads(response) -class TestProject: - BASE_DIR = os.path.dirname(os.path.abspath(__file__)) - - @pytest.fixture(scope="session") - def microservice(self): - os.environ[CONFIGMAP_FILE_ENVIRONMENT] = os.path.join(self.BASE_DIR, "config-tests.yml") - ms = MyMicroservice(path=os.path.join(os.path.dirname(os.path.dirname(__file__)), "project", "test_views.py")) - ms.app = ms.create_app() - ms.base_url = ms.app.config["APPLICATION_ROOT"] - ms.client = ms.app.test_client() - return ms - - def test_home(self, microservice): - response = microservice.client.get('/') - assert 404 == response.status_code - - def test_healthcheck(self, microservice): - response = microservice.client.get('/healthcheck') - assert 200 == response.status_code - - def test_list_actors(self, microservice): - response = microservice.client.get('/actors'.format(base_url=microservice.base_url)) - assert 200 == response.status_code - - def test_list_films(self, microservice): - response = microservice.client.get('/films'.format(base_url=microservice.base_url)) - assert 200 == response.status_code - - def test_pyms(self, microservice): - assert "1234" == microservice.app.config["TEST_VAR"] - - def test_create_film(self, microservice): - name = "Avengers" - pubDate = "2020-01-20" - cast = [{"id": 1, "name": "Robert", "surname": "Downey Jr."}, {"id": 2, "name": "Chris", "surname": "Hemsworth"}] - response = microservice.client.post('/films'.format( - base_url=microservice.base_url), - data=json.dumps(dict(name=name, pubDate=pubDate, cast=cast)), - content_type='application/json' - ) - assert 200 == response.status_code - assert name == _format_response(response.data)["name"] - - def test_create_actor(self, microservice): - response = microservice.client.get('/actors'.format(base_url=microservice.base_url)) - assert 200 == response.status_code - - def test_pyms(self, microservice): - assert "1234" == microservice.app.config["TEST_VAR"] - - def test_create_view(self, microservice): - name = "Robert" - surname = "Downey Jr." - response = microservice.client.post('/actors'.format( - base_url=microservice.base_url), - data=json.dumps(dict(name=name, surname=surname)), - content_type='application/json' - ) - assert 200 == response.status_code - assert name == _format_response(response.data)["name"] +def test_home(client): + response = client.get('/') + assert 404 == response.status_code + + +def test_healthcheck(client): + response = client.get('/healthcheck') + assert 200 == response.status_code + + +def test_list_actors(client, base_url): + response = client.get('{base_url}actors'.format(base_url=base_url)) + assert 200 == response.status_code + + +def test_list_films(client, base_url): + response = client.get('{base_url}films'.format(base_url=base_url)) + assert 200 == response.status_code + + +def test_pyms(app): + assert "1234" == app.config["TEST_VAR"] + + +def test_create_film(client, base_url): + name = "Avengers" + pubDate = "2020-01-20" + cast = [{"id": 1, "name": "Robert", "surname": "Downey Jr."}, {"id": 2, "name": "Chris", "surname": "Hemsworth"}] + response = client.post('{base_url}films'.format( + base_url=base_url), + data=json.dumps(dict(name=name, pubDate=pubDate, cast=cast)), + content_type='application/json' + ) + assert 200 == response.status_code + assert name == _format_response(response.data)["name"] + + +def test_create_view(client, base_url): + name = "Robert" + surname = "Downey Jr." + response = client.post('{base_url}actors'.format( + base_url=base_url), + data=json.dumps(dict(name=name, surname=surname)), + content_type='application/json' + ) + assert 200 == response.status_code + assert name == _format_response(response.data)["name"]