kin/tests/test_revising_status_regression.py
2026-03-18 21:02:34 +02:00

141 lines
5.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""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"