Feat: add e2e test for api
This commit is contained in:
parent
4a16444835
commit
ccf1655cf4
@ -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
16
backend/config.py
Normal 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
68
poetry.lock
generated
@ -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"
|
||||
|
@ -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"]
|
||||
|
@ -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
59
tests/e2e/test_api.py
Normal 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"]
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user