87 lines
2.4 KiB
Python
87 lines
2.4 KiB
Python
|
|
"""
|
||
|
|
Shared fixtures untuk suite services.
|
||
|
|
|
||
|
|
Environment (TOKENS_FILE / CONTENT_DIR) di-set di import-time conftest,
|
||
|
|
SEBELUM `app`/`token_service` di-import, supaya seluruh test menunjuk data
|
||
|
|
uji terpisah — bukan file produksi (`../tokens_siswa.csv`).
|
||
|
|
"""
|
||
|
|
|
||
|
|
import csv
|
||
|
|
import os
|
||
|
|
import pathlib
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
|
||
|
|
_TEST_ROOT = "/tmp/lms-contract"
|
||
|
|
_TEST_TOKENS = f"{_TEST_ROOT}/tokens.csv"
|
||
|
|
_TEST_CONTENT = f"{_TEST_ROOT}/content"
|
||
|
|
|
||
|
|
TEACHER_TOKEN = "TOKEN_GURU_001"
|
||
|
|
STUDENT_TOKEN = "TOKEN_SISWA_001"
|
||
|
|
STUDENT2_TOKEN = "TOKEN_SISWA_002"
|
||
|
|
|
||
|
|
|
||
|
|
def _write_tokens() -> None:
|
||
|
|
pathlib.Path(_TEST_ROOT).mkdir(parents=True, exist_ok=True)
|
||
|
|
pathlib.Path(_TEST_CONTENT).mkdir(parents=True, exist_ok=True)
|
||
|
|
with open(_TEST_TOKENS, "w", newline="", encoding="utf-8") as f:
|
||
|
|
writer = csv.writer(f, delimiter=";")
|
||
|
|
writer.writerow(["token", "nama_siswa", "hello_world", "quiz_test"])
|
||
|
|
writer.writerow([TEACHER_TOKEN, "Pak Guru", "completed", "completed"])
|
||
|
|
writer.writerow([STUDENT_TOKEN, "Budi Santoso", "completed", "3/4"])
|
||
|
|
writer.writerow([STUDENT2_TOKEN, "Siti Aminah", "not_started", ""])
|
||
|
|
|
||
|
|
|
||
|
|
_write_tokens()
|
||
|
|
|
||
|
|
# PAKSA path fixture (bukan setdefault) — env container (.env) membawa
|
||
|
|
# TOKENS_FILE/CONTENT_DIR produksi ("tokens.csv"/"content") yang membuat
|
||
|
|
# contract tests membaca data asli. Test harus selalu terisolasi.
|
||
|
|
os.environ["TOKENS_FILE"] = _TEST_TOKENS
|
||
|
|
os.environ["CONTENT_DIR"] = _TEST_CONTENT
|
||
|
|
os.environ["ORIGIN"] = "*"
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.fixture()
|
||
|
|
def app():
|
||
|
|
from app import create_app
|
||
|
|
|
||
|
|
application = create_app()
|
||
|
|
application.config["TESTING"] = True
|
||
|
|
return application
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.fixture()
|
||
|
|
def client(app):
|
||
|
|
return app.test_client()
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.fixture(autouse=True)
|
||
|
|
def _isolate_database():
|
||
|
|
"""Isolasi integration test: truncate semua tabel sebelum SETIAP test.
|
||
|
|
|
||
|
|
Test importer/lesson-registry/progress berbagi DATABASE_URL yang sama;
|
||
|
|
tanpa reset, data sisa antar test saling mengotori (mis. total lessons
|
||
|
|
bertambah). Contract tests (backend CSV) tidak terpengaruh — SessionLocal
|
||
|
|
None bila DATABASE_URL tidak diset.
|
||
|
|
"""
|
||
|
|
from sqlalchemy import text
|
||
|
|
|
||
|
|
from services.database import SessionLocal
|
||
|
|
|
||
|
|
if SessionLocal is None:
|
||
|
|
yield
|
||
|
|
return
|
||
|
|
db = SessionLocal()
|
||
|
|
try:
|
||
|
|
db.execute(
|
||
|
|
text(
|
||
|
|
"TRUNCATE student_progress, access_tokens, lessons, users "
|
||
|
|
"RESTART IDENTITY CASCADE"
|
||
|
|
)
|
||
|
|
)
|
||
|
|
db.commit()
|
||
|
|
finally:
|
||
|
|
db.close()
|
||
|
|
yield
|