sync
parent
9b4184994f
commit
903c216966
48
README.md
48
README.md
|
@ -5,4 +5,52 @@ Demo api with Flask as backend and Redis as NoSql DB
|
||||||
|
|
||||||
[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit)](https://github.com/pre-commit/pre-commit)
|
[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit)](https://github.com/pre-commit/pre-commit)
|
||||||
|
|
||||||
|
|
||||||
## Задание
|
## Задание
|
||||||
|
|
||||||
|
Создать docker-compose.yml разворачивающий приложение на python с простой реализацией REST API. Решение должно состоять из двух контейнеров:
|
||||||
|
а) Любая NoSQL DB.
|
||||||
|
|
||||||
|
б) Приложение на python, с использованием Flask, которое слушает на порту 8080 и принимает только методы GET, POST, PUT.
|
||||||
|
|
||||||
|
в) Создаем значение ключ=значение, изменяем ключ=новое_значение, читаем значение ключа.
|
||||||
|
|
||||||
|
г) Вновь созданные объекты должны создаваться, изменяться и читаться из NoSQL DB.
|
||||||
|
|
||||||
|
|
||||||
|
## Описание API
|
||||||
|
- GET:
|
||||||
|
требует наличие аргумента key: http://localhost:8080/?key=blablabla
|
||||||
|
|
||||||
|
- POST, PUT & DELETE:
|
||||||
|
принимают данные запроса в json формате
|
||||||
|
{
|
||||||
|
"key": "your_key",
|
||||||
|
"val": "your_val"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
## Установка
|
||||||
|
|
||||||
|
- Клонируем репозиторий
|
||||||
|
`git clone https://git.pi3c.ru/pi3c/flask-demo-api.git`
|
||||||
|
|
||||||
|
- Запуск апи
|
||||||
|
первый запуск после установки или обновления
|
||||||
|
`docker-compose -f compose-app.yml up --build`
|
||||||
|
|
||||||
|
последующие запуски
|
||||||
|
`docker-compose -f compose-app.yml up`
|
||||||
|
|
||||||
|
- Запуск тестов
|
||||||
|
первый запуск после установки или обновления
|
||||||
|
`docker-compose -f compose-tests.yml up --build`
|
||||||
|
|
||||||
|
последующие запуски
|
||||||
|
`docker-compose -f compose-tests.yml up`
|
||||||
|
|
||||||
|
- Для остановки запущенных контейнеров
|
||||||
|
`<CTRL>-c`
|
||||||
|
`docker-compose -f compose-app.yml down`
|
||||||
|
or
|
||||||
|
`docker-compose -f compose-tests.yml down`
|
||||||
|
|
|
@ -17,8 +17,12 @@ services:
|
||||||
app:
|
app:
|
||||||
container_name: flask_demo
|
container_name: flask_demo
|
||||||
|
|
||||||
|
environment:
|
||||||
|
REDISURL: "redis://redis:6379/0"
|
||||||
|
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
|
dockerfile: ./docker/app/Dockerfile
|
||||||
|
|
||||||
ports:
|
ports:
|
||||||
- 8080:5000
|
- 8080:5000
|
||||||
|
@ -27,9 +31,7 @@ services:
|
||||||
redis:
|
redis:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
|
||||||
restart: always
|
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
- ./flask_demo_api:/usr/src/flask-demo-api/flask_demo_api
|
- ./flask_demo_api:/usr/src/flask-demo-api/flask_demo_api
|
||||||
|
|
||||||
command: /bin/bash -c 'poetry run python flask_demo_api/main.py'
|
command: /bin/bash -c 'poetry run app'
|
|
@ -0,0 +1,40 @@
|
||||||
|
version: "3.8"
|
||||||
|
services:
|
||||||
|
redis:
|
||||||
|
container_name: redis_tests
|
||||||
|
|
||||||
|
image: redis:7.2.4-alpine3.19
|
||||||
|
|
||||||
|
ports:
|
||||||
|
- '6381:6379'
|
||||||
|
|
||||||
|
healthcheck:
|
||||||
|
test: [ "CMD", "redis-cli","ping" ]
|
||||||
|
interval: 6s
|
||||||
|
timeout: 6s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
app:
|
||||||
|
container_name: flask_tests
|
||||||
|
|
||||||
|
environment:
|
||||||
|
REDISURL: "redis://redis:6379/0"
|
||||||
|
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: ./docker/tests/Dockerfile
|
||||||
|
|
||||||
|
ports:
|
||||||
|
- 8080:5000
|
||||||
|
|
||||||
|
depends_on:
|
||||||
|
redis:
|
||||||
|
condition: service_healthy
|
||||||
|
|
||||||
|
restart: always
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
- ./flask_demo_api:/usr/src/flask-demo-api/flask_demo_api
|
||||||
|
- ./tests:/usr/src/flask-demo-api/tests
|
||||||
|
|
||||||
|
command: /bin/bash -c 'poetry run pytest -vv'
|
|
@ -18,4 +18,4 @@ COPY ./poetry.lock .
|
||||||
|
|
||||||
COPY ./pyproject.toml .
|
COPY ./pyproject.toml .
|
||||||
|
|
||||||
RUN poetry install
|
RUN poetry install --without dev
|
|
@ -0,0 +1,23 @@
|
||||||
|
FROM python:3.10-slim
|
||||||
|
|
||||||
|
ENV PYTHONDONTWRITEBYTECODE 1
|
||||||
|
|
||||||
|
ENV PYTHONUNBUFFERED 1
|
||||||
|
|
||||||
|
RUN pip install --upgrade pip
|
||||||
|
|
||||||
|
RUN pip install poetry
|
||||||
|
|
||||||
|
RUN poetry config virtualenvs.create false
|
||||||
|
|
||||||
|
RUN mkdir -p /usr/src/flask-demo-api/flask_demo_api
|
||||||
|
|
||||||
|
RUN mkdir -p /usr/src/flask-demo-api/tests
|
||||||
|
|
||||||
|
WORKDIR /usr/src/flask-demo-api
|
||||||
|
|
||||||
|
COPY ./poetry.lock .
|
||||||
|
|
||||||
|
COPY ./pyproject.toml .
|
||||||
|
|
||||||
|
RUN poetry install
|
|
@ -1,3 +1,5 @@
|
||||||
|
import os
|
||||||
|
|
||||||
import redis # type: ignore
|
import redis # type: ignore
|
||||||
from dishka import Container, Provider, Scope, make_container, provide
|
from dishka import Container, Provider, Scope, make_container, provide
|
||||||
|
|
||||||
|
@ -14,7 +16,8 @@ from flask_demo_api.usecase.put import PutKey
|
||||||
class RedisSettingsProvider(Provider):
|
class RedisSettingsProvider(Provider):
|
||||||
@provide(scope=Scope.APP)
|
@provide(scope=Scope.APP)
|
||||||
def redis_settings(self) -> RedisSettings:
|
def redis_settings(self) -> RedisSettings:
|
||||||
return RedisSettings()
|
url = os.getenv("REDISURL") or "redis://localhost:6379/0"
|
||||||
|
return RedisSettings(url=url)
|
||||||
|
|
||||||
|
|
||||||
class SettingsProvider(Provider):
|
class SettingsProvider(Provider):
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class KeyDTO:
|
class KeyDTO:
|
||||||
key: str
|
key: str
|
||||||
val: Any | None = None
|
val: str = ""
|
||||||
|
|
|
@ -10,11 +10,11 @@ class Repository(Protocol):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def add_key(self, obj: KeyDTO) -> KeyDTO:
|
def add_key(self, obj: KeyDTO) -> KeyDTO | None:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def put_key(self, obj: KeyDTO) -> KeyDTO:
|
def put_key(self, obj: KeyDTO) -> KeyDTO | None:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
|
|
|
@ -3,4 +3,4 @@ from dataclasses import dataclass
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class RedisSettings:
|
class RedisSettings:
|
||||||
url: str = "redis://localhost:6379/0"
|
url: str
|
||||||
|
|
|
@ -10,19 +10,36 @@ class RedisRepository(Repository):
|
||||||
def __init__(self, redis_pool: redis.Redis) -> None:
|
def __init__(self, redis_pool: redis.Redis) -> None:
|
||||||
self.pool = redis_pool
|
self.pool = redis_pool
|
||||||
|
|
||||||
|
def __set(self, key, val):
|
||||||
|
data = pickle.dumps(val)
|
||||||
|
self.pool.set(key, data)
|
||||||
|
|
||||||
|
def __get(self, key):
|
||||||
|
data = self.pool.get(key)
|
||||||
|
if data is not None:
|
||||||
|
return pickle.loads(data)
|
||||||
|
return None
|
||||||
|
|
||||||
def get_key(self, obj: KeyDTO) -> KeyDTO | None:
|
def get_key(self, obj: KeyDTO) -> KeyDTO | None:
|
||||||
data = self.pool.get(obj.key)
|
data = self.__get(obj.key)
|
||||||
if not data:
|
if not data:
|
||||||
return None
|
return None
|
||||||
return KeyDTO(key=str(obj.key), val=data)
|
return KeyDTO(key=obj.key, val=data)
|
||||||
|
|
||||||
def add_key(self, obj: KeyDTO) -> KeyDTO:
|
def add_key(self, obj: KeyDTO) -> KeyDTO | None:
|
||||||
self.pool.set(str(obj.key), pickle.dumps(obj.val))
|
data = self.__get(obj.key)
|
||||||
|
if data:
|
||||||
|
return None
|
||||||
|
self.__set(obj.key, obj.val)
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
def put_key(self, obj: KeyDTO) -> KeyDTO:
|
def put_key(self, obj: KeyDTO) -> KeyDTO | None:
|
||||||
return KeyDTO(key="5", val="6")
|
data = self.__get(obj.key)
|
||||||
|
if data is None:
|
||||||
|
return None
|
||||||
|
self.__set(obj.key, obj.val)
|
||||||
|
return obj
|
||||||
|
|
||||||
def delete_key(self, obj: KeyDTO) -> None:
|
def delete_key(self, obj: KeyDTO) -> None:
|
||||||
self.pool.delete(str(obj.key))
|
self.pool.delete(obj.key)
|
||||||
return None
|
return None
|
||||||
|
|
|
@ -15,16 +15,18 @@ key_bp = Blueprint("key_bp", __name__)
|
||||||
def past_key(usecase: FromDishka[PostKey]):
|
def past_key(usecase: FromDishka[PostKey]):
|
||||||
json_data = request.get_json()
|
json_data = request.get_json()
|
||||||
|
|
||||||
|
if not json_data.get("key"):
|
||||||
|
abort(400, "'key' required")
|
||||||
|
elif not json_data.get("val"):
|
||||||
|
abort(400, "'val' required")
|
||||||
|
|
||||||
if json_data:
|
if json_data:
|
||||||
result = usecase(
|
result = usecase(request=KeyDTO(key=json_data.get("key"), val=json_data.get("val")))
|
||||||
request=KeyDTO(key=json_data.get("key"), val=json_data.get("val"))
|
if result is None:
|
||||||
)
|
abort(400, "Key alredy exist")
|
||||||
return (
|
return jsonify({"message": "Ok", "data": result}), 201
|
||||||
jsonify({"message": "Ok", "data": result}),
|
|
||||||
201,
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
return jsonify({"message": "No JSON data received"}), 400
|
abort(400, "Invalid json data")
|
||||||
|
|
||||||
|
|
||||||
@key_bp.route("/", methods=["GET"])
|
@key_bp.route("/", methods=["GET"])
|
||||||
|
@ -50,16 +52,21 @@ def get_key(usecase: FromDishka[GetKey]):
|
||||||
def put_key(usecase: FromDishka[PutKey]):
|
def put_key(usecase: FromDishka[PutKey]):
|
||||||
json_data = request.get_json()
|
json_data = request.get_json()
|
||||||
|
|
||||||
|
if not json_data.get("key"):
|
||||||
|
abort(400, "'key' required")
|
||||||
|
elif not json_data.get("val"):
|
||||||
|
abort(400, "'val' required")
|
||||||
|
|
||||||
if json_data:
|
if json_data:
|
||||||
result = usecase(
|
result = usecase(request=KeyDTO(key=json_data.get("key"), val=json_data.get("val")))
|
||||||
request=KeyDTO(key=json_data.get("key"), val=json_data.get("val"))
|
if result is None:
|
||||||
)
|
abort(400, "No item for update")
|
||||||
return (
|
return (
|
||||||
jsonify({"message": "Updated", "data": result}),
|
jsonify({"message": "Updated", "data": result}),
|
||||||
200,
|
200,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
return jsonify({"message": "No JSON data received"}), 400
|
abort(400, "Inalid JSON data")
|
||||||
|
|
||||||
|
|
||||||
@key_bp.route("/", methods=["DELETE"])
|
@key_bp.route("/", methods=["DELETE"])
|
||||||
|
@ -74,4 +81,4 @@ def delete_key(usecase: FromDishka[DelKey]):
|
||||||
200,
|
200,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
return jsonify({"message": "No JSON data received"}), 400
|
abort(400, "Inalid JSON data")
|
||||||
|
|
|
@ -9,5 +9,5 @@ class PostKey:
|
||||||
) -> None:
|
) -> None:
|
||||||
self.__repository = repository
|
self.__repository = repository
|
||||||
|
|
||||||
def __call__(self, request: KeyDTO) -> KeyDTO:
|
def __call__(self, request: KeyDTO) -> KeyDTO | None:
|
||||||
return self.__repository.add_key(obj=request)
|
return self.__repository.add_key(obj=request)
|
||||||
|
|
|
@ -9,5 +9,5 @@ class PutKey:
|
||||||
) -> None:
|
) -> None:
|
||||||
self.__repository = repository
|
self.__repository = repository
|
||||||
|
|
||||||
def __call__(self, request: KeyDTO) -> KeyDTO:
|
def __call__(self, request: KeyDTO) -> KeyDTO | None:
|
||||||
return self.__repository.put_key(obj=request)
|
return self.__repository.put_key(obj=request)
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import pytest
|
import pytest
|
||||||
from dishka.integrations.flask import setup_dishka
|
from dishka.integrations.flask import setup_dishka
|
||||||
from flask import Flask
|
from flask import Flask
|
||||||
from httpx import AsyncClient
|
|
||||||
|
|
||||||
from flask_demo_api.ioc import create_container
|
from flask_demo_api.ioc import create_container
|
||||||
from flask_demo_api.main import app_factory
|
from flask_demo_api.main import app_factory
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
def test_get_without_args(client):
|
def test_get_without_args(client):
|
||||||
response = client.get("/")
|
response = client.get("/")
|
||||||
assert response.status_code == 400
|
assert response.status_code == 400
|
||||||
|
@ -12,3 +15,26 @@ def test_get_with_wrong_key(client):
|
||||||
assert response.get_json() == {
|
assert response.get_json() == {
|
||||||
"error": "404 Not Found: Key not found",
|
"error": "404 Not Found: Key not found",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_with_existing_key(client):
|
||||||
|
response = client.get("/?key=abcd")
|
||||||
|
assert response.status_code == 404
|
||||||
|
assert response.get_json() == {
|
||||||
|
"error": "404 Not Found: Key not found",
|
||||||
|
}
|
||||||
|
data = json.dumps({"key": "abcd", "val": "def"})
|
||||||
|
response = client.post("/", data=data, content_type="application/json")
|
||||||
|
assert response.status_code == 201
|
||||||
|
|
||||||
|
response = client.get("/?key=abcd")
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.get_json() == {"message": "Ok", "data": json.loads(data)}
|
||||||
|
|
||||||
|
client.delete("/", data=data, content_type="application/json")
|
||||||
|
|
||||||
|
response = client.get("/?key=abcd")
|
||||||
|
assert response.status_code == 404
|
||||||
|
assert response.get_json() == {
|
||||||
|
"error": "404 Not Found: Key not found",
|
||||||
|
}
|
||||||
|
|
|
@ -14,6 +14,11 @@ def test_post_with_empty_data(client):
|
||||||
|
|
||||||
|
|
||||||
def test_post_with_data(client):
|
def test_post_with_data(client):
|
||||||
|
response = client.get("/?key=abc")
|
||||||
|
assert response.status_code == 404
|
||||||
|
assert response.get_json() == {
|
||||||
|
"error": "404 Not Found: Key not found",
|
||||||
|
}
|
||||||
data = json.dumps({"key": "abc", "val": "def"})
|
data = json.dumps({"key": "abc", "val": "def"})
|
||||||
response = client.post("/", data=data, content_type="application/json")
|
response = client.post("/", data=data, content_type="application/json")
|
||||||
assert response.status_code == 201
|
assert response.status_code == 201
|
||||||
|
@ -21,3 +26,72 @@ def test_post_with_data(client):
|
||||||
"message": "Ok",
|
"message": "Ok",
|
||||||
"data": {"key": "abc", "val": "def"},
|
"data": {"key": "abc", "val": "def"},
|
||||||
}
|
}
|
||||||
|
client.delete("/", data=data, content_type="application/json")
|
||||||
|
|
||||||
|
response = client.get("/?key=abc")
|
||||||
|
assert response.status_code == 404
|
||||||
|
assert response.get_json() == {
|
||||||
|
"error": "404 Not Found: Key not found",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_post_without_key(client):
|
||||||
|
response = client.get("/?key=abc")
|
||||||
|
assert response.status_code == 404
|
||||||
|
assert response.get_json() == {
|
||||||
|
"error": "404 Not Found: Key not found",
|
||||||
|
}
|
||||||
|
data = json.dumps({"val": "def"})
|
||||||
|
response = client.post("/", data=data, content_type="application/json")
|
||||||
|
assert response.status_code == 400
|
||||||
|
assert response.get_json() == {"error": "400 Bad Request: 'key' required"}
|
||||||
|
|
||||||
|
|
||||||
|
def test_post_without_value(client):
|
||||||
|
response = client.get("/?key=abc")
|
||||||
|
assert response.status_code == 404
|
||||||
|
assert response.get_json() == {
|
||||||
|
"error": "404 Not Found: Key not found",
|
||||||
|
}
|
||||||
|
|
||||||
|
data = json.dumps({"key": "abc"})
|
||||||
|
response = client.post("/", data=data, content_type="application/json")
|
||||||
|
assert response.status_code == 400
|
||||||
|
assert response.get_json() == {"error": "400 Bad Request: 'val' required"}
|
||||||
|
|
||||||
|
response = client.get("/?key=abc")
|
||||||
|
assert response.status_code == 404
|
||||||
|
assert response.get_json() == {
|
||||||
|
"error": "404 Not Found: Key not found",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_post_with_data_double_adding(client):
|
||||||
|
response = client.get("/?key=abc")
|
||||||
|
assert response.status_code == 404
|
||||||
|
assert response.get_json() == {
|
||||||
|
"error": "404 Not Found: Key not found",
|
||||||
|
}
|
||||||
|
|
||||||
|
data = json.dumps({"key": "abc", "val": "def"})
|
||||||
|
|
||||||
|
response = client.post("/", data=data, content_type="application/json")
|
||||||
|
assert response.status_code == 201
|
||||||
|
assert response.get_json() == {
|
||||||
|
"message": "Ok",
|
||||||
|
"data": {"key": "abc", "val": "def"},
|
||||||
|
}
|
||||||
|
|
||||||
|
response = client.post("/", data=data, content_type="application/json")
|
||||||
|
assert response.status_code == 400
|
||||||
|
assert response.get_json() == {
|
||||||
|
"error": "400 Bad Request: Key alredy exist",
|
||||||
|
}
|
||||||
|
|
||||||
|
client.delete("/", data=data, content_type="application/json")
|
||||||
|
|
||||||
|
response = client.get("/?key=abc")
|
||||||
|
assert response.status_code == 404
|
||||||
|
assert response.get_json() == {
|
||||||
|
"error": "404 Not Found: Key not found",
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
def test_put_with_wrong_content_type(client):
|
||||||
|
data = json.dumps({})
|
||||||
|
response = client.put("/", data=data)
|
||||||
|
assert response.status_code == 415
|
||||||
|
|
||||||
|
|
||||||
|
def test_put_with_empty_data(client):
|
||||||
|
data = json.dumps({})
|
||||||
|
response = client.put("/", data=data, content_type="application/json")
|
||||||
|
assert response.status_code == 400
|
||||||
|
|
||||||
|
|
||||||
|
def test_put_with_wrong_data(client):
|
||||||
|
data = json.dumps({"key": "abc", "val": "def"})
|
||||||
|
response = client.post("/", data=data, content_type="application/json")
|
||||||
|
|
||||||
|
put_data = json.dumps({"key": "abcasd", "val": "def"})
|
||||||
|
response = client.put("/", data=put_data, content_type="application/json")
|
||||||
|
|
||||||
|
assert response.status_code == 400
|
||||||
|
assert response.get_json() == {"error": "400 Bad Request: No item for update"}
|
||||||
|
|
||||||
|
client.delete("/", data=data, content_type="application/json")
|
||||||
|
|
||||||
|
response = client.get("/?key=abcasd")
|
||||||
|
assert response.status_code == 404
|
||||||
|
assert response.get_json() == {
|
||||||
|
"error": "404 Not Found: Key not found",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_put_with_correct_data(client):
|
||||||
|
data = json.dumps({"key": "abc", "val": "def"})
|
||||||
|
response = client.post("/", data=data, content_type="application/json")
|
||||||
|
|
||||||
|
put_data = json.dumps({"key": "abc", "val": "defan"})
|
||||||
|
response = client.put("/", data=put_data, content_type="application/json")
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.get_json() == {
|
||||||
|
"message": "Updated",
|
||||||
|
"data": {"key": "abc", "val": "defan"},
|
||||||
|
}
|
||||||
|
|
||||||
|
client.delete("/", data=data, content_type="application/json")
|
||||||
|
|
||||||
|
response = client.get("/?key=abc")
|
||||||
|
assert response.status_code == 404
|
||||||
|
assert response.get_json() == {
|
||||||
|
"error": "404 Not Found: Key not found",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_put_without_key(client):
|
||||||
|
data = json.dumps({"key": "abc", "val": "def"})
|
||||||
|
response = client.post("/", data=data, content_type="application/json")
|
||||||
|
|
||||||
|
put_data = json.dumps({"val": "defdd"})
|
||||||
|
response = client.put("/", data=put_data, content_type="application/json")
|
||||||
|
|
||||||
|
assert response.status_code == 400
|
||||||
|
assert response.get_json() == {"error": "400 Bad Request: 'key' required"}
|
||||||
|
|
||||||
|
client.delete("/", data=data, content_type="application/json")
|
||||||
|
|
||||||
|
response = client.get("/?key=abc")
|
||||||
|
assert response.status_code == 404
|
||||||
|
assert response.get_json() == {
|
||||||
|
"error": "404 Not Found: Key not found",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_put_without_value(client):
|
||||||
|
data = json.dumps({"key": "abc", "val": "def"})
|
||||||
|
response = client.post("/", data=data, content_type="application/json")
|
||||||
|
|
||||||
|
put_data = json.dumps({"key": "abcd"})
|
||||||
|
response = client.put("/", data=put_data, content_type="application/json")
|
||||||
|
|
||||||
|
assert response.status_code == 400
|
||||||
|
assert response.get_json() == {"error": "400 Bad Request: 'val' required"}
|
||||||
|
|
||||||
|
client.delete("/", data=data, content_type="application/json")
|
||||||
|
|
||||||
|
response = client.get("/?key=abc")
|
||||||
|
assert response.status_code == 404
|
||||||
|
assert response.get_json() == {
|
||||||
|
"error": "404 Not Found: Key not found",
|
||||||
|
}
|
Loading…
Reference in New Issue