kin/tests/test_revising_status_regression.py

142 lines
5.6 KiB
Python
Raw Normal View History

2026-03-18 21:02:34 +02:00
"""Regression tests for KIN-127 bug: parent_task_id silently ignored in POST /api/tasks.
Root cause: TaskCreate schema was missing parent_task_id field, so child tasks
created via API had no parent link in DB. Fixed by adding parent_task_id to TaskCreate
and passing it to models.create_task.
These tests use the API end-to-end (no models bypass) to prevent regression.
"""
import pytest
@pytest.fixture
def client(tmp_path):
import web.api as api_module
api_module.DB_PATH = tmp_path / "test.db"
from web.api import app
from fastapi.testclient import TestClient
c = TestClient(app)
c.post("/api/projects", json={"id": "p1", "name": "P1", "path": "/p1"})
return c
# ---------------------------------------------------------------------------
# 1. parent_task_id сохраняется при создании задачи через API
# ---------------------------------------------------------------------------
def test_create_task_with_parent_task_id_saves_link(client):
"""POST /api/tasks с parent_task_id — ссылка на родителя сохраняется в БД."""
r = client.post("/api/tasks", json={"project_id": "p1", "title": "Parent"})
assert r.status_code == 200
parent_id = r.json()["id"]
r = client.post("/api/tasks", json={
"project_id": "p1",
"title": "Child",
"parent_task_id": parent_id,
})
assert r.status_code == 200
child = r.json()
assert child["parent_task_id"] == parent_id
def test_create_task_without_parent_task_id_has_no_parent(client):
"""POST /api/tasks без parent_task_id — задача создаётся как корневая."""
r = client.post("/api/tasks", json={"project_id": "p1", "title": "Root task"})
assert r.status_code == 200
task = r.json()
assert task.get("parent_task_id") is None
# ---------------------------------------------------------------------------
# 2. /children возвращает задачи, созданные через API с parent_task_id
# ---------------------------------------------------------------------------
def test_children_endpoint_returns_api_created_children(client):
"""GET /children видит дочерние задачи, созданные через POST /api/tasks."""
r = client.post("/api/tasks", json={"project_id": "p1", "title": "Parent"})
parent_id = r.json()["id"]
client.post("/api/tasks", json={
"project_id": "p1", "title": "Child A", "parent_task_id": parent_id,
})
client.post("/api/tasks", json={
"project_id": "p1", "title": "Child B", "parent_task_id": parent_id,
})
r = client.get(f"/api/tasks/{parent_id}/children")
assert r.status_code == 200
titles = {c["title"] for c in r.json()}
assert titles == {"Child A", "Child B"}
def test_children_endpoint_empty_for_task_created_without_parent(client):
"""GET /children возвращает [] для задачи без дочерних задач."""
r = client.post("/api/tasks", json={"project_id": "p1", "title": "Leaf"})
task_id = r.json()["id"]
r = client.get(f"/api/tasks/{task_id}/children")
assert r.status_code == 200
assert r.json() == []
# ---------------------------------------------------------------------------
# 3. Фильтр ?parent_task_id работает с API-созданными дочерними задачами
# ---------------------------------------------------------------------------
def test_list_tasks_parent_filter_with_api_created_children(client):
"""GET /api/tasks?parent_task_id={id} находит задачи, созданные через API."""
r = client.post("/api/tasks", json={"project_id": "p1", "title": "Parent"})
parent_id = r.json()["id"]
client.post("/api/tasks", json={
"project_id": "p1", "title": "Child", "parent_task_id": parent_id,
})
client.post("/api/tasks", json={"project_id": "p1", "title": "Other root"})
r = client.get(f"/api/tasks?parent_task_id={parent_id}")
assert r.status_code == 200
tasks = r.json()
assert len(tasks) == 1
assert tasks[0]["title"] == "Child"
# ---------------------------------------------------------------------------
# 4. End-to-end: PATCH status=done → revising, дочерняя задача создана через API
# ---------------------------------------------------------------------------
def test_patch_done_becomes_revising_when_child_created_via_api(client):
"""E2E: дочерняя задача создана через POST /api/tasks → parent PATCH done → revising."""
r = client.post("/api/tasks", json={"project_id": "p1", "title": "Parent"})
parent_id = r.json()["id"]
client.post("/api/tasks", json={
"project_id": "p1",
"title": "Child (open)",
"parent_task_id": parent_id,
})
r = client.patch(f"/api/tasks/{parent_id}", json={"status": "done"})
assert r.status_code == 200
assert r.json()["status"] == "revising"
def test_patch_done_when_api_child_is_done(client):
"""E2E: все дочерние задачи (созданные через API) done → parent PATCH done → done."""
r = client.post("/api/tasks", json={"project_id": "p1", "title": "Parent"})
parent_id = r.json()["id"]
r = client.post("/api/tasks", json={
"project_id": "p1",
"title": "Child",
"parent_task_id": parent_id,
})
child_id = r.json()["id"]
client.patch(f"/api/tasks/{child_id}", json={"status": "done"})
r = client.patch(f"/api/tasks/{parent_id}", json={"status": "done"})
assert r.status_code == 200
assert r.json()["status"] == "done"