feat: background tasks manager and book sentence mining for CEFR tests

This commit is contained in:
2026-10-06 16:36:39 +03:00
parent 332286b641
commit c9da5bd351
11 changed files with 1377 additions and 16 deletions
+74 -4
View File
@@ -1393,11 +1393,10 @@ def test_cefr_testing_and_gap_ingestion():
assert "clue" in q1
assert len(q1["options"]) == 4
# 5. Answer INCORRECTLY -> Automated Dual Gap Ingestion (target + selected option)
# Pick a distractor from the question's actual options
# Find option that is not correct (we test with the first distractor)
# Let's inspect options and find one that is wrong
wrong_opt = [opt for opt in q1["options"] if opt.lower() != q1.get("term", "").lower()][0]
with get_db() as conn:
correct_term = conn.execute("SELECT term FROM cefr_questions WHERE id = ?", (q1["id"],)).fetchone()["term"]
wrong_opt = [opt for opt in q1["options"] if opt.lower() != correct_term.lower()][0]
ans_wrong = client.post("/api/cefr/answer", json={
"question_id": q1["id"],
@@ -1576,6 +1575,77 @@ def test_grammar_engine_and_handwritten_journaling():
assert u1_after["handwritten_logged"] is True
def test_background_tasks_and_book_mining():
# 1. Unauthenticated check
client.cookies.clear()
unauth = client.post("/api/tasks/mine-books", json={"level": "A1", "count": 2})
assert unauth.status_code == 401
# 2. Login
login_res = client.post("/api/login", json={"username": "testadmin", "password": "testpass12345"})
assert login_res.status_code == 200
# 3. Create a book with known vocabulary
book_resp = client.post("/api/books", json={
"title": "Adventures in London",
"author": "Arthur Conan Doyle",
"content": "Chapter 1: The Arrival\nThey decided to invite their neighbor for breakfast. The journey was long and dangerous.\n\nChapter 2: The Mystery\nHe could not remember where he left his expensive ticket.",
"source_type": "text"
})
assert book_resp.status_code == 200
book_id = book_resp.json()["id"]
# 4. Start mining task
mine_resp = client.post("/api/tasks/mine-books", json={
"book_id": book_id,
"level": "A1",
"count": 2
})
assert mine_resp.status_code == 200
data = mine_resp.json()
assert data["status"] == "ok"
assert "task_id" in data
task_id = data["task_id"]
# 5. Check task status via active and ID endpoint
active_resp = client.get("/api/tasks/active")
assert active_resp.status_code == 200
# Wait briefly or poll task status
import time
t_data = None
for _ in range(30):
t_res = client.get(f"/api/tasks/{task_id}")
assert t_res.status_code == 200
t_data = t_res.json()["task"]
if t_data["status"] in ("completed", "failed", "cancelled"):
break
time.sleep(0.1)
assert t_data is not None
assert t_data["status"] == "completed"
assert t_data["progress_current"] > 0
# 6. Verify quiz retrieval includes source book metadata
quiz_res = client.get("/api/cefr/quiz?level=A1&count=20")
assert quiz_res.status_code == 200
items = quiz_res.json()["quiz"]
book_items = [q for q in items if q.get("source_book_title") == "Adventures in London"]
assert len(book_items) > 0
assert book_items[0]["source_book_title"] == "Adventures in London"
assert "source_chapter_title" in book_items[0]
# 7. Test task cancellation
from app.tasks import create_task
with get_db() as conn:
task_id_pending = create_task(conn, 1, "mine_books", total=10)
cancel_resp = client.post(f"/api/tasks/{task_id_pending}/cancel")
assert cancel_resp.status_code == 200
assert cancel_resp.json()["status"] == "ok"
assert cancel_resp.json()["cancelled"] is True