Feat: add e2e test for api

This commit is contained in:
Bertrand Benjamin 2022-12-28 07:47:35 +01:00
parent 4a16444835
commit ccf1655cf4
8 changed files with 210 additions and 19 deletions

View File

@ -20,7 +20,7 @@ from backend.repository.tribe_sqlite_repository import TribeSQLiteRepository
# session = sessionmaker(bind=engine)()
# tribe_repo = TribeSQLAlchemyRepository(session)
conn = sqlite3.connect(":memory:")
conn = sqlite3.connect("sqlite.db")
create_db(conn)
tribe_repo = TribeSQLiteRepository(conn)

16
backend/config.py Normal file
View File

@ -0,0 +1,16 @@
import os
import sqlite3
from backend.adapters.sqlite import create_db
def sqlite_conn(sqlite_file: str = ":memory"):
conn = sqlite3.connect(sqlite_file)
create_db(conn)
return conn
def get_api_url():
host = os.environ.get("API_HOST", "localhost")
port = 8000 if host == "localhost" else 80
return f"http://{host}:{port}"

68
poetry.lock generated
View File

@ -39,6 +39,18 @@ docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"]
tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "zope.interface"]
tests-no-zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"]
[[package]]
name = "certifi"
version = "2022.12.7"
description = "Python package for providing Mozilla's CA Bundle."
category = "dev"
optional = false
python-versions = ">=3.6"
files = [
{file = "certifi-2022.12.7-py3-none-any.whl", hash = "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"},
{file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"},
]
[[package]]
name = "cfgv"
version = "3.3.1"
@ -51,6 +63,21 @@ files = [
{file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"},
]
[[package]]
name = "charset-normalizer"
version = "2.1.1"
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
category = "dev"
optional = false
python-versions = ">=3.6.0"
files = [
{file = "charset-normalizer-2.1.1.tar.gz", hash = "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845"},
{file = "charset_normalizer-2.1.1-py3-none-any.whl", hash = "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"},
]
[package.extras]
unicode-backport = ["unicodedata2"]
[[package]]
name = "click"
version = "8.1.3"
@ -504,6 +531,28 @@ files = [
{file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"},
]
[[package]]
name = "requests"
version = "2.28.1"
description = "Python HTTP for Humans."
category = "dev"
optional = false
python-versions = ">=3.7, <4"
files = [
{file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"},
{file = "requests-2.28.1.tar.gz", hash = "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983"},
]
[package.dependencies]
certifi = ">=2017.4.17"
charset-normalizer = ">=2,<3"
idna = ">=2.5,<4"
urllib3 = ">=1.21.1,<1.27"
[package.extras]
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
[[package]]
name = "setuptools"
version = "65.6.3"
@ -674,6 +723,23 @@ files = [
{file = "typing_extensions-4.4.0.tar.gz", hash = "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa"},
]
[[package]]
name = "urllib3"
version = "1.26.13"
description = "HTTP library with thread-safe connection pooling, file post, and more."
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
files = [
{file = "urllib3-1.26.13-py2.py3-none-any.whl", hash = "sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc"},
{file = "urllib3-1.26.13.tar.gz", hash = "sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8"},
]
[package.extras]
brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"]
secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"]
socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
[[package]]
name = "uvicorn"
version = "0.20.0"
@ -717,4 +783,4 @@ testing = ["coverage (>=6.2)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7
[metadata]
lock-version = "2.0"
python-versions = "^3.10"
content-hash = "9f84fef203ddda9214c28ec94c4e928b850209b4a88af267f447aaf2c9fd00b4"
content-hash = "ab4854a75d6c6394039fd873f164e7e37118b70c79c2052de9acacae98511e8a"

View File

@ -16,6 +16,7 @@ uvicorn = "^0.20.0"
pre-commit = "^2.20.0"
pytest = "^7.2.0"
faker = "^15.3.4"
requests = "^2.28.1"
[build-system]
requires = ["poetry-core"]

View File

@ -1,10 +1,17 @@
import sqlite3
import time
from pathlib import Path
import pytest
import requests
from sqlalchemy import create_engine
from sqlalchemy.orm import clear_mappers, sessionmaker
from backend import config
from backend.adapters.orm import metadata, start_mappers
from backend.adapters.sqlite import create_db
from tests.integration.test_repository_student_sqlite import populate_students
from tests.integration.test_repository_tribe_sqlite import populate_tribes
@pytest.fixture
@ -23,6 +30,64 @@ def session(in_memory_db):
@pytest.fixture
def sqlite_conn():
conn = sqlite3.connect(":memory:")
conn = sqlite3.connect("sqlite.db")
create_db(conn)
yield conn
conn.close()
@pytest.fixture
def clean_db(sqlite_conn):
sqlite_conn.execute("""DROP TABLE tribes""")
sqlite_conn.execute("""DROP TABLE students""")
sqlite_conn.commit()
create_db(sqlite_conn)
@pytest.fixture
def populate_db(sqlite_conn):
_tribes = []
_students = []
def _populate_db():
tribes = populate_tribes(sqlite_conn)
_tribes += tribes
students = populate_students(sqlite_conn, tribes)
_students += students
return tribes, students
yield _populate_db
for student in _students:
sqlite_conn.execute(
"""
DELETE FROM students WHERE id=:id
""",
{"id": student.id},
)
for tribe in _tribes:
sqlite_conn.execute(
"""
DELETE FROM tribes WHERE name=:name
""",
{"name": tribe.name},
)
sqlite_conn.commit()
def wait_for_webapp_to_come_up():
deadline = time.time() + 10
url = config.get_api_url()
while time.time() < deadline:
try:
return requests.get(url)
except ConnectionError:
time.sleep(0.5)
pytest.fail("API never came up")
@pytest.fixture
def restart_api():
(Path(__file__).parent.parent / "backend" / "api" / "main.py").touch()
time.sleep(0.5)
wait_for_webapp_to_come_up()

59
tests/e2e/test_api.py Normal file
View File

@ -0,0 +1,59 @@
import pytest
import requests
from backend import config
from tests.model.fakes import build_tribes
@pytest.mark.usefixtures("restart_api")
@pytest.mark.usefixtures("clean_db")
def test_api_post_tribe():
data = {"name": "tribe", "level": "2nd"}
url = config.get_api_url()
r = requests.post(f"{url}/tribes", json=data)
assert r.status_code == 201
assert r.json() == {
"assessments": [],
"level": "2nd",
"name": "tribe",
"students": [],
}
@pytest.mark.usefixtures("restart_api")
@pytest.mark.usefixtures("clean_db")
def test_api_post_list_tribe():
tribe = build_tribes(1)[0]
url = config.get_api_url()
r = requests.post(f"{url}/tribes", json=tribe.to_dict())
assert r.status_code == 201
r = requests.get(f"{url}/tribes")
assert r.json() == [
{
"assessments": [],
"level": tribe.level,
"name": tribe.name,
"students": [],
}
]
@pytest.mark.usefixtures("restart_api")
@pytest.mark.usefixtures("clean_db")
def test_api_post_student():
url = config.get_api_url()
tribe = build_tribes(1)[0]
requests.post(f"{url}/tribes", json=tribe.to_dict())
data = {"name": "zart", "tribe_name": tribe.name}
r = requests.post(f"{url}/students", json=data)
assert r.status_code == 201
assert r.json()["name"] == "zart"
assert r.json()["tribe_name"] == tribe.name
assert r.json()["id"]

View File

@ -2,7 +2,6 @@ import sqlite3
import pytest
from backend.adapters.sqlite import create_db
from backend.model.student import Student
from backend.model.tribe import Tribe
from backend.repository.student_sqlite_repository import StudentSQLiteRepository
@ -25,7 +24,6 @@ def populate_students(conn, tribes: list[Tribe]) -> list[Student]:
def test_get_student(sqlite_conn):
create_db(sqlite_conn)
prebuild_tribes = populate_tribes(sqlite_conn)
prebuild_students = populate_students(sqlite_conn, prebuild_tribes)
@ -38,7 +36,6 @@ def test_get_student(sqlite_conn):
def test_get_student_not_exists(sqlite_conn):
create_db(sqlite_conn)
prebuild_tribes = populate_tribes(sqlite_conn)
prebuild_students = populate_students(sqlite_conn, prebuild_tribes)
@ -48,7 +45,6 @@ def test_get_student_not_exists(sqlite_conn):
def test_list_students(sqlite_conn):
create_db(sqlite_conn)
prebuild_tribes = populate_tribes(sqlite_conn)
prebuild_students = populate_students(sqlite_conn, prebuild_tribes)
@ -59,7 +55,6 @@ def test_list_students(sqlite_conn):
def test_add_student(sqlite_conn):
create_db(sqlite_conn)
prebuild_tribes = populate_tribes(sqlite_conn)
student_repo = StudentSQLiteRepository(sqlite_conn)
@ -82,7 +77,6 @@ def test_add_student(sqlite_conn):
def test_add_student_fail_exists(sqlite_conn):
create_db(sqlite_conn)
prebuild_tribes = populate_tribes(sqlite_conn)
student_repo = StudentSQLiteRepository(sqlite_conn)
@ -97,7 +91,6 @@ def test_add_student_fail_exists(sqlite_conn):
def test_update_student(sqlite_conn):
create_db(sqlite_conn)
prebuild_tribes = populate_tribes(sqlite_conn)
prebuild_students = populate_students(sqlite_conn, prebuild_tribes)
@ -118,7 +111,6 @@ def test_update_student(sqlite_conn):
def test_delete_student(sqlite_conn):
create_db(sqlite_conn)
prebuild_tribes = populate_tribes(sqlite_conn)
prebuild_students = populate_students(sqlite_conn, prebuild_tribes)

View File

@ -2,7 +2,6 @@ import sqlite3
import pytest
from backend.adapters.sqlite import create_db
from backend.model.tribe import Tribe
from backend.repository.tribe_sqlite_repository import TribeSQLiteRepository
from tests.model.fakes import build_tribes
@ -23,7 +22,6 @@ def populate_tribes(conn) -> list[Tribe]:
def test_get_tribe(sqlite_conn):
create_db(sqlite_conn)
prebuild_tribes = populate_tribes(sqlite_conn)
name = prebuild_tribes[0].name
@ -35,7 +33,6 @@ def test_get_tribe(sqlite_conn):
def test_get_tribe_not_exists(sqlite_conn):
create_db(sqlite_conn)
prebuild_tribes = populate_tribes(sqlite_conn)
tribe_repo = TribeSQLiteRepository(sqlite_conn)
@ -44,7 +41,6 @@ def test_get_tribe_not_exists(sqlite_conn):
def test_list_tribes(sqlite_conn):
create_db(sqlite_conn)
prebuild_tribes = populate_tribes(sqlite_conn)
tribe_repo = TribeSQLiteRepository(sqlite_conn)
@ -54,7 +50,6 @@ def test_list_tribes(sqlite_conn):
def test_add_tribe(sqlite_conn):
create_db(sqlite_conn)
tribe_repo = TribeSQLiteRepository(sqlite_conn)
@ -76,7 +71,6 @@ def test_add_tribe(sqlite_conn):
def test_add_tribe_fail_exists(sqlite_conn):
create_db(sqlite_conn)
prebuild_tribes = populate_tribes(sqlite_conn)
tribe_repo = TribeSQLiteRepository(sqlite_conn)
@ -87,7 +81,6 @@ def test_add_tribe_fail_exists(sqlite_conn):
def test_update_tribe(sqlite_conn):
create_db(sqlite_conn)
prebuild_tribes = populate_tribes(sqlite_conn)
tribe_repo = TribeSQLiteRepository(sqlite_conn)
@ -102,7 +95,6 @@ def test_update_tribe(sqlite_conn):
def test_delete_tribe(sqlite_conn):
create_db(sqlite_conn)
prebuild_tribes = populate_tribes(sqlite_conn)
tribe_repo = TribeSQLiteRepository(sqlite_conn)