diff --git a/challenges/flask_container_ci/README.md b/challenges/flask_container_ci/README.md index d4fd190..149f974 100644 --- a/challenges/flask_container_ci/README.md +++ b/challenges/flask_container_ci/README.md @@ -5,13 +5,30 @@ Please read carefully all the instructions. 1. Create a virtual environment with `python3 -m venv challenge_venv` 2. Activate it with `source challenge_venv/bin/activate` -3. Install requirements.txt `pip install -r requirements.txt` +3. Install the requirements in this directory `pip install -r requirements.txt` ## Run the app +If any of the following steps is not working, it is expected from you to fix them + 1. Run `export FLASK_APP=app/app.py` 1. To run the app execute `flask run`. If it doesn't works, fix it +3. Access `http://127.0.0.1:5000`. You should see the following +``` +{ + "resources_uris": { + "user": "/users/", + "users": "/users" + }, + "current_uri": "/" +} +``` + +4. You should be able to access any of the resources and get the following data: + +* /users/ - data on the specific chosen user +* /users - all users data ## Containers @@ -28,7 +45,13 @@ docker run -d -p 5000:5000 app ## CI Great, now that we have a working app and also can run it in a container, let's set up a CI for it so it won't break again in the future +In current directory you have a file called tests.py which includes the tests for the app. What is expected from you is: -1. The CI should run the tests in the app directory +1. The CI should run the app tests. You are free to choose whatever CI system or service you prefer. 2. There should be some kind of test for the Dockerfile you wrote -2. Add additional unit test (or another level of tests) +3. Add additional unit test (or another level of tests) for testing the app + +### Guidelines + +* Except the app functionality, you can change whatever you want - structure, tooling, libraries, ... If possible add `notes.md` file which explains reasons, logic, thoughts and anything else you would like to share +* The CI part should include the source code for the pipeline definition diff --git a/challenges/flask_container_ci/app/__init__.py b/challenges/flask_container_ci/app/__init__.py new file mode 100644 index 0000000..5c9136a --- /dev/null +++ b/challenges/flask_container_ci/app/__init__.py @@ -0,0 +1,2 @@ +#!/usr/bin/env python +# coding=utf-8 diff --git a/challenges/flask_container_ci/app/app.py b/challenges/flask_container_ci/app/app.py index 140a6cd..bcc3da0 100644 --- a/challenges/flask_container_ci/app/app.py +++ b/challenges/flask_container_ci/app/app.py @@ -2,8 +2,50 @@ # coding=utf-8 from flask import Flask +from flask import make_response + +from werkzeug.exceptions import NotFound + +import json + + app = Flask(__name__) -@app.route('/') -def hello_world(): - return 'Hello, World!' +with open("./users.json", "r") as f: + users = json.load(f) + + +@app.route("/", methods=['GET']) +def index(): + return pretty_json({ + "resources": { + "users": "/users", + "user": "/users/", + }, + "current_uri": "/" + }) + +@app.route("/users", methods=['GET']) +def all_users(): + return pretty_json(users) + +@app.route("/users/", methods=['GET']) +def user_data(username): + if username not in users: + raise NotFound + + return pretty_json(users[username]) + + +@app.route("/users//something", methods=['GET']) +def user_something(username): + raise NotImplementedError() + + +def pretty_json(arg): + response = make_response(json.dumps(arg, sort_keys = True, indent=4)) + response.headers['Content-type'] = "application/json" + return response + +if __name__ == "__main__": + app.run(port=5000) diff --git a/challenges/flask_container_ci/app/config.py b/challenges/flask_container_ci/app/config.py index fffb65a..33e417f 100644 --- a/challenges/flask_container_ci/app/config.py +++ b/challenges/flask_container_ci/app/config.py @@ -9,4 +9,3 @@ SECRET_KEY = 'shhh' CSRF_ENABLED = True SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'app.db') - diff --git a/challenges/flask_container_ci/requirements.txt b/challenges/flask_container_ci/requirements.txt new file mode 100644 index 0000000..7e10602 --- /dev/null +++ b/challenges/flask_container_ci/requirements.txt @@ -0,0 +1 @@ +flask diff --git a/challenges/flask_container_ci/tests.py b/challenges/flask_container_ci/tests.py new file mode 100644 index 0000000..1aa522b --- /dev/null +++ b/challenges/flask_container_ci/tests.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python +# coding=utf-8 + +import os +import unittest + +from config import basedir +from app import app +from app import db + +class TestCase(unittest.TestCase): + + def setUp(self): + app.config['TESTING'] = True + app.config['WTF_CSRF_ENABLED'] = False + app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'test.db') + self.app = app.test_client() + db.create_all() + + def tearDown(self): + db.session.remove() + db.drop_all() + +if __name__ == '__main__': + unittest.main() diff --git a/challenges/flask_container_ci/users.json b/challenges/flask_container_ci/users.json new file mode 100644 index 0000000..fe0b54a --- /dev/null +++ b/challenges/flask_container_ci/users.json @@ -0,0 +1,18 @@ +{ + "geralt" : { + "id": "whitewolf", + "name": "Geralt of Rivia" + }, + "lara_croft" : { + "id": "m31a3n6sion", + "name": "Lara Croft" + }, + "mario" : { + "id": "smb3igiul", + "name": "Mario" + }, + "gordon_freeman" : { + "id": "nohalflife3", + "name": "Gordon Freeman" + } +}