diff --git a/39/pavelekshin/.app.py.swo b/39/pavelekshin/.app.py.swo new file mode 100644 index 000000000..e009d83e5 Binary files /dev/null and b/39/pavelekshin/.app.py.swo differ diff --git a/39/pavelekshin/.coverage b/39/pavelekshin/.coverage new file mode 100644 index 000000000..96e07343b Binary files /dev/null and b/39/pavelekshin/.coverage differ diff --git a/39/pavelekshin/.test_app.py.un~ b/39/pavelekshin/.test_app.py.un~ new file mode 100644 index 000000000..fec08fbe2 Binary files /dev/null and b/39/pavelekshin/.test_app.py.un~ differ diff --git a/39/pavelekshin/app.py b/39/pavelekshin/app.py new file mode 100644 index 000000000..3dcddc219 --- /dev/null +++ b/39/pavelekshin/app.py @@ -0,0 +1,96 @@ +from flask import Flask, jsonify, abort, make_response, request + +NOT_FOUND = "Not found" +BAD_REQUEST = "Bad request" + +app = Flask(__name__) + +items = [ + {"id": 1, "name": "laptop", "value": 1000}, + { + "id": 2, + "name": "chair", + "value": 300, + }, + { + "id": 3, + "name": "book", + "value": 20, + }, +] + + +def _get_item(id): + return [item for item in items if item["id"] == id] + + +def _record_exists(name): + return [item for item in items if item["name"] == name] + + +@app.errorhandler(404) +def not_found(error): + return make_response(jsonify({"error": NOT_FOUND}), 404) + + +@app.errorhandler(400) +def bad_request(error): + return make_response(jsonify({"error": BAD_REQUEST}), 400) + + +@app.route("/api/v1.0/items", methods=["GET"]) +def get_items(): + return jsonify({"items": items}) + + +@app.route("/api/v1.0/items/", methods=["GET"]) +def get_item(id): + item = _get_item(id) + if not item: + abort(404) + return jsonify({"items": item}) + + +@app.route("/api/v1.0/items", methods=["POST"]) +def create_item(): + if not request.json or "name" not in request.json or "value" not in request.json: + abort(400) + item_id = items[0].get("id") + 1 + name = request.json.get("name") + if _record_exists(name): + abort(400) + value = request.json.get("value") + if type(value) is not int: + abort(400) + item = {"id": item_id, "name": name, "value": value} + items.append(item) + return jsonify({"item": item}), 201 + + +@app.route("/api/v1.0/items/", methods=["PUT"]) +def update_item(id): + item = _get_item(id) + if len(item) == 0: + abort(404) + if not request.json: + abort(400) + name = request.json.get("name", item[0]["name"]) + value = request.json.get("value", item[0]["value"]) + if type(value) is not int: + abort(400) + item[0]["name"] = name + item[0]["value"] = value + return jsonify({"item": item[0]}), 200 + + +@app.route("/api/v1.0/items/", methods=["DELETE"]) +def delete_item(id): + item = _get_item(id) + if len(item) == 0: + abort(404) + items.remove(item[0]) + return jsonify({}), 204 + + +if __name__ == "__main__": + app.run(debug=True) diff --git a/39/pavelekshin/curl.py b/39/pavelekshin/curl.py new file mode 100644 index 000000000..09de59181 --- /dev/null +++ b/39/pavelekshin/curl.py @@ -0,0 +1,38 @@ +import os + +tests = """ +# get items +curl -i http://127.0.0.1:5000/api/v1.0/items +# item 1 +curl -i http://127.0.0.1:5000/api/v1.0/items/1 +# item2 +curl -i http://127.0.0.1:5000/api/v1.0/items/2 +# err: non-existing item +curl -i http://127.0.0.1:5000/api/v1.0/items/4 +# err: add item already in items +curl -i -H "Content-Type: application/json" -X POST -d '{"name":"book", "value": 20}' http://127.0.0.1:5000/api/v1.0/items +# err: add item with value not int +curl -i -H "Content-Type: application/json" -X POST -d '{"name":"monitor", "value": "200"}' http://127.0.0.1:5000/api/v1.0/items +# add item with proper values +curl -i -H "Content-Type: application/json" -X POST -d '{"name":"monitor", "value": 200}' http://127.0.0.1:5000/api/v1.0/items +# show items +curl -i http://127.0.0.1:5000/api/v1.0/items +# err: edit non-existing item +curl -i -H "Content-Type: application/json" -X PUT -d '{"value": 30}' http://127.0.0.1:5000/api/v1.0/items/5 +# OK: edit existing item +curl -i -H "Content-Type: application/json" -X PUT -d '{"value": 30}' http://127.0.0.1:5000/api/v1.0/items/3 +# show items +curl -i http://127.0.0.1:5000/api/v1.0/items +# err: delete non-existing item +curl -i -H "Content-Type: application/json" -X DELETE http://127.0.0.1:5000/api/v1.0/items/5 +# OK: delete existing item +curl -i -H "Content-Type: application/json" -X DELETE http://127.0.0.1:5000/api/v1.0/items/3 +# show items +curl -i http://127.0.0.1:5000/api/v1.0/items +""" + +for line in tests.strip().split("\n"): + print("\n{}".format(line)) + if not line.startswith("#"): + cmd = line.strip() + os.system(cmd) diff --git a/39/pavelekshin/test_app.py b/39/pavelekshin/test_app.py new file mode 100644 index 000000000..03e74c9e3 --- /dev/null +++ b/39/pavelekshin/test_app.py @@ -0,0 +1,130 @@ +import pytest +import json + +from app import app + +BASE_URL = "http://127.0.0.1:5000/api/v1.0/items" +BAD_ITEM_URL = "{}/5".format(BASE_URL) +GOOD_ITEM_URL = "{}/3".format(BASE_URL) + + +def setUp(): + backup_items = deepcopy(app.items) + app = app.test_client() + assert app.testing == False + + +def test_get_items(): + with app.test_client() as tc: + # get items + response = tc.get(BASE_URL) + assert response.status_code == 200 + data = json.loads(response.data) + # items count in response + assert len(data["items"]) == 3 + + +def test_get_item(): + with app.test_client() as tc: + # get one non exist item + response = tc.get(BAD_ITEM_URL) + assert response.status_code == 404 + # get one exist item + response = tc.get(GOOD_ITEM_URL) + data = json.loads(response.data) + assert response.status_code == 200 + assert len(data["items"]) == 1 + + +def test_not_found(): + with app.test_client() as tc: + response = tc.get(BAD_ITEM_URL) + assert response.status_code == 404 + + +def test_bad_request(): + item = {"name": "laptop", "some-value": "1000"} + # item wrong request body + with app.test_client() as tc: + response = tc.post( + BASE_URL, data=json.dumps(item), content_type="application/json" + ) + assert response.status_code == 400 + + +def test_create_item(): + with app.test_client() as tc: + # wrong request body + item = {"name": "laptop", "some-value": "1000"} + response = tc.post( + BASE_URL, data=json.dumps(item), content_type="application/json" + ) + assert response.status_code == 400 + # item exist + item = {"name": "laptop", "value": int(1)} + response = tc.post( + BASE_URL, data=json.dumps(item), content_type="application/json" + ) + assert response.status_code == 400 + # item wrong request value type + item = {"name": "monitor", "value": str(1)} + response = tc.post( + BASE_URL, data=json.dumps(item), content_type="application/json" + ) + assert response.status_code == 400 + # create item + item = {"name": "printer", "value": 100} + reponse = tc.post( + BASE_URL, data=json.dumps(item), content_type="application/json" + ) + + +def test_update_item(): + item = {"name": "laptop", "some-value": "1000"} + # item wrong request body + with app.test_client() as tc: + response = tc.post( + BASE_URL, data=json.dumps(item), content_type="application/json" + ) + assert response.status_code == 400 + + +def test_update_item(): + with app.test_client() as tc: + # update non exist item + response = tc.put(BAD_ITEM_URL) + assert response.status_code == 404 + # empty request body + response = tc.put( + GOOD_ITEM_URL, data=json.dumps({}), content_type="application/json" + ) + assert response.status_code == 400 + # request body contains str instead of int value + response = tc.put( + GOOD_ITEM_URL, + data=json.dumps({"name": "book", "value": str(10)}), + content_type="application/json", + ) + assert response.status_code == 400 + # correct request + response = tc.put( + GOOD_ITEM_URL, + data=json.dumps({"name": "book", "value": int(10)}), + content_type="application/json", + ) + assert response.status_code == 200 + + +def test_delete_item(): + with app.test_client() as tc: + # delete non exist item + response = tc.delete(BAD_ITEM_URL) + assert response.status_code == 404 + # delete exist item + response = tc.delete(GOOD_ITEM_URL) + assert response.status_code == 204 + + +def setDown(): + # reset state + app.items = backup_items