Add Sejoli tryout JSON snapshot importer

This commit is contained in:
dwindown
2026-04-02 17:04:01 +07:00
parent 51c577be05
commit b4ebdc9c4f
7 changed files with 910 additions and 1 deletions

View File

@@ -0,0 +1,110 @@
import asyncio
from types import SimpleNamespace
from pathlib import Path
import sys
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
from app.services.tryout_json_import import preview_tryout_json_import
class DummyScalarResult:
def __init__(self, value):
self._value = value
def scalar_one_or_none(self):
return self._value
class DummyScalars:
def __init__(self, values):
self._values = values
def all(self):
return self._values
class DummyListResult:
def __init__(self, values):
self._values = values
def scalars(self):
return DummyScalars(self._values)
class DummySession:
def __init__(self, responses):
self._responses = list(responses)
async def execute(self, _query):
return self._responses.pop(0)
def test_preview_tryout_json_import_classifies_new_updated_and_removed_questions():
payload = {
"export_info": {
"exported_at": "2026-04-02 09:12:59",
"exported_by": "Admin",
"tryout_id": 1038,
},
"tryouts": {
"tryout_1038": {
"info": {
"id": 1038,
"title": "Tryout PPDS Obgyn",
"permalink": "https://member.example.com/tryout/1038",
},
"questions": [
{
"id": 269,
"title": "Question A",
"question": "<p>Question A body</p>",
"options": [
{"increment": "A", "label": "", "value": "0"},
{"increment": "B", "label": "", "value": "1"},
],
"answer": "B",
"explanation": "<p>Because.</p>",
},
{
"id": 270,
"title": "Question B new",
"question": "<p>Question B body</p>",
"options": [
{"increment": "A", "label": "", "value": "1"},
{"increment": "B", "label": "", "value": "0"},
],
"answer": "A",
"explanation": "<p>New item.</p>",
},
],
"results": [],
}
},
}
existing_question = SimpleNamespace(
source_question_id="269",
content_checksum="old-checksum",
is_active=True,
)
removed_question = SimpleNamespace(
source_question_id="999",
content_checksum="removed-checksum",
is_active=True,
)
db = DummySession(
[
DummyScalarResult(SimpleNamespace(id=1)),
DummyListResult([existing_question, removed_question]),
]
)
preview = asyncio.run(preview_tryout_json_import(payload, website_id=1, db=db))
assert preview["tryout_count"] == 1
assert preview["totals"]["new_questions"] == 1
assert preview["totals"]["updated_questions"] == 1
assert preview["totals"]["removed_questions"] == 1
assert preview["totals"]["missing_option_labels"] == 2
assert "read-only reference data" not in str(preview)