kin: auto-commit after pipeline
This commit is contained in:
parent
a7e6e8ad35
commit
d552b8bd45
3 changed files with 473 additions and 1 deletions
141
tests/test_revising_status_regression.py
Normal file
141
tests/test_revising_status_regression.py
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
"""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"
|
||||
Loading…
Add table
Add a link
Reference in a new issue