kin: auto-commit after pipeline
This commit is contained in:
parent
0731aad028
commit
79a0e524a7
3 changed files with 107 additions and 0 deletions
|
|
@ -143,6 +143,7 @@ CREATE TABLE IF NOT EXISTS pipelines (
|
|||
total_duration_seconds INTEGER,
|
||||
parent_pipeline_id INTEGER REFERENCES pipelines(id),
|
||||
department TEXT,
|
||||
pid INTEGER,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
completed_at DATETIME
|
||||
);
|
||||
|
|
|
|||
|
|
@ -392,3 +392,92 @@ def test_migrate_preserves_non_dept_sub_and_non_running_pipelines():
|
|||
assert rows["dept_sub"] == "completed", "completed pipeline не должен меняться"
|
||||
assert rows["direct"] == "running", "non-dept_sub running pipeline не должен меняться"
|
||||
conn.close()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Schema KIN-OBS-018: pid INTEGER присутствует в таблице pipelines
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class TestPipelinesSchemaKinObs018:
|
||||
"""PRAGMA table_info(pipelines) должен содержать kolонку pid INTEGER."""
|
||||
|
||||
def test_schema_has_pid_column(self, conn):
|
||||
"""Свежая инициализация: pipelines содержит колонку pid."""
|
||||
assert "pid" in _cols(conn, "pipelines")
|
||||
|
||||
def test_pid_defaults_to_null(self, conn):
|
||||
"""Вставка pipeline без pid — значение NULL."""
|
||||
conn.execute(
|
||||
"INSERT INTO projects (id, name) VALUES ('p_pid', 'P')"
|
||||
)
|
||||
conn.execute(
|
||||
"INSERT INTO tasks (id, project_id, title) VALUES ('t_pid', 'p_pid', 'T')"
|
||||
)
|
||||
conn.execute(
|
||||
"INSERT INTO pipelines (task_id, project_id, route_type, steps)"
|
||||
" VALUES ('t_pid', 'p_pid', 'direct', '[]')"
|
||||
)
|
||||
conn.commit()
|
||||
row = conn.execute(
|
||||
"SELECT pid FROM pipelines WHERE task_id='t_pid'"
|
||||
).fetchone()
|
||||
assert row["pid"] is None
|
||||
|
||||
def test_pid_can_store_integer_value(self, conn):
|
||||
"""Вставка pipeline с pid — значение сохраняется в БД."""
|
||||
conn.execute(
|
||||
"INSERT INTO projects (id, name) VALUES ('p_pid2', 'P')"
|
||||
)
|
||||
conn.execute(
|
||||
"INSERT INTO tasks (id, project_id, title) VALUES ('t_pid2', 'p_pid2', 'T')"
|
||||
)
|
||||
conn.execute(
|
||||
"INSERT INTO pipelines (task_id, project_id, route_type, steps, pid)"
|
||||
" VALUES ('t_pid2', 'p_pid2', 'direct', '[]', 12345)"
|
||||
)
|
||||
conn.commit()
|
||||
row = conn.execute(
|
||||
"SELECT pid FROM pipelines WHERE task_id='t_pid2'"
|
||||
).fetchone()
|
||||
assert row["pid"] == 12345
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Migration KIN-OBS-018: _migrate добавляет pid в существующие БД без этой колонки
|
||||
# Конвенция #384: три теста для _migrate guard
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_migrate_adds_pid_to_pipelines_without_column():
|
||||
"""_migrate добавляет pid в таблицу pipelines если колонки нет."""
|
||||
conn = _old_schema_with_pipelines_conn() # схема без pid
|
||||
_migrate(conn)
|
||||
assert "pid" in _cols(conn, "pipelines")
|
||||
conn.close()
|
||||
|
||||
|
||||
def test_migrate_pid_is_nullable_after_migration():
|
||||
"""После миграции pid nullable — существующие строки не ломаются (pid=NULL)."""
|
||||
conn = _old_schema_with_pipelines_conn()
|
||||
conn.execute("INSERT INTO projects (id, name) VALUES ('pm_pid', 'P')")
|
||||
conn.execute("INSERT INTO tasks (id, project_id, title) VALUES ('tm_pid', 'pm_pid', 'T')")
|
||||
conn.execute(
|
||||
"INSERT INTO pipelines (task_id, project_id, route_type, status)"
|
||||
" VALUES ('tm_pid', 'pm_pid', 'direct', 'completed')"
|
||||
)
|
||||
conn.commit()
|
||||
_migrate(conn)
|
||||
row = conn.execute("SELECT pid FROM pipelines WHERE task_id='tm_pid'").fetchone()
|
||||
assert row["pid"] is None
|
||||
conn.close()
|
||||
|
||||
|
||||
def test_migrate_pid_guard_is_idempotent():
|
||||
"""Повторный вызов _migrate не ломает схему pipelines (guard idempotent)."""
|
||||
conn = _old_schema_with_pipelines_conn()
|
||||
_migrate(conn)
|
||||
before = _cols(conn, "pipelines")
|
||||
_migrate(conn)
|
||||
after = _cols(conn, "pipelines")
|
||||
assert before == after
|
||||
assert "pid" in after
|
||||
conn.close()
|
||||
|
|
|
|||
|
|
@ -256,6 +256,23 @@ describe('KIN-099: onUnmounted очищает setTimeout таймеры watchdog
|
|||
await flushPromises()
|
||||
// Pass = no errors thrown after unmount
|
||||
})
|
||||
|
||||
it('KIN-OBS-016: vi.getTimerCount() === 0 после unmount — все таймеры очищены', async () => {
|
||||
vi.mocked(api.notifications).mockResolvedValue([
|
||||
makeNotification('KIN-016', 'Process died unexpectedly (PID 99999)'),
|
||||
])
|
||||
|
||||
const wrapper = mount(EscalationBanner)
|
||||
await flushPromises()
|
||||
|
||||
// Toast с активным timerId должен быть виден
|
||||
expect(wrapper.find('.border-red-700').exists()).toBe(true)
|
||||
|
||||
// После unmount — оба таймера (setInterval pollTimer + setTimeout toast) очищены
|
||||
wrapper.unmount()
|
||||
|
||||
expect(vi.getTimerCount()).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue