/
fleisar
/
agent-timetracker
Обзор
Документация
Войти
/
fleisar
/
agent-timetracker
Код
Запросы
0
Задачи
Вики
Пакеты
1
Релизы
2
CI/CD
Аналитика
Безопасность
main
tests/storage/sqliteStore.test.ts
245 строк
7 KB
Matvey Kuznetsov
feat: add project and chat task grouping
14 июл 2026, 05:54
14 июл 2026, 05:54
6b9f105
Код
Авторство
О чём код?
import { mkdtempSync, rmSync } from "node:fs"; import path from "node:path"; import os from "node:os"; import Database from "better-sqlite3"; import { afterEach, describe, expect, it } from "vitest"; import type { Artifact, Task, WorkSession } from "../../src/domain/types.js"; import { createSqliteStore } from "../../src/storage/sqliteStore.js"; const now = "2026-07-02T10:34:56.000Z"; type ArtifactInput = Artifact & { idempotency_key: string }; function makeDbPath(testName: string): string { const dir = mkdtempSync(path.join(os.tmpdir(), "agent-timetracker-storage-")); return path.join(dir, `${testName}.sqlite`); } function makeTask(overrides: Partial<Task> = {}): Omit<Task, "active_session_ids"> { return { task_id: "task_01", title: "Implement storage layer", project_id: "project_01", chat_id: "chat_01", status: "active", created_at: now, completed_at: null, total_work_seconds: 123, last_activity_at: now, idle_timeout_seconds: 600, allowed_agent_ids: ["executor", "tester"], metadata: { epic: "v1" }, ...overrides }; } function makeSession(overrides: Partial<WorkSession> = {}): WorkSession { return { session_id: "session_01", task_id: "task_01", agent_id: "executor", status: "active", started_at: now, ended_at: null, last_activity_at: now, start_reason: "started", end_reason: null, started_by: "agent", ended_by: null, metadata: { source: "test" }, ...overrides }; } function makeArtifact(overrides: Partial<Artifact> = {}): Artifact { return { artifact_id: "artifact_01", task_id: "task_01", session_id: "session_01", agent_id: "executor", kind: "note", title: "Storage notes", content: "round-trip payload", mime_type: "text/plain", created_at: now, metadata: { source: "test" }, ...overrides }; } describe("sqlite store", () => { const tempDirs: string[] = []; const openStores: Array<{ close: () => void }> = []; afterEach(() => { while (openStores.length > 0) { const store = openStores.pop(); store?.close(); } while (tempDirs.length > 0) { const dir = tempDirs.pop(); if (dir) { rmSync(dir, { recursive: true, force: true }); } } }); function openStore(testName: string) { const dbPath = makeDbPath(testName); tempDirs.push(path.dirname(dbPath)); const store = createSqliteStore(dbPath); openStores.push(store); return store; } it("round-trips tasks", () => { const store = openStore("tasks-round-trip"); const task = makeTask(); store.createTask(task); expect(store.getTask(task.task_id)).toEqual({ ...task, active_session_ids: [] }); }); it("lists tasks in descending creation order", () => { const store = openStore("tasks-list"); const older = makeTask({ task_id: "task_01", created_at: "2026-07-02T10:00:00.000Z" }); const newer = makeTask({ task_id: "task_02", created_at: "2026-07-02T11:00:00.000Z", project_id: "project_02", chat_id: "chat_02" }); store.createTask(older); store.createTask(newer); expect(store.listTasks().map((task) => task.task_id)).toEqual(["task_02", "task_01"]); expect(store.listTasks({ project_id: "project_01" }).map((task) => task.task_id)).toEqual(["task_01"]); expect(store.listTasks({ chat_id: "chat_02" }).map((task) => task.task_id)).toEqual(["task_02"]); }); it("migrates existing databases with project and chat columns", () => { const dbPath = makeDbPath("task-project-chat-migration"); tempDirs.push(path.dirname(dbPath)); const database = new Database(dbPath); database.exec(` CREATE TABLE tasks ( task_id TEXT PRIMARY KEY, title TEXT, status TEXT NOT NULL, created_at TEXT NOT NULL, completed_at TEXT, total_work_seconds INTEGER NOT NULL DEFAULT 0, last_activity_at TEXT, idle_timeout_seconds INTEGER NOT NULL, allowed_agent_ids_json TEXT, metadata_json TEXT NOT NULL DEFAULT '{}' ); `); database.close(); const store = createSqliteStore(dbPath); openStores.push(store); store.createTask(makeTask({ task_id: "task_migrated" })); expect(store.getTask("task_migrated")).toMatchObject({ project_id: "project_01", chat_id: "chat_01" }); }); it("round-trips sessions", () => { const store = openStore("sessions-round-trip"); const task = makeTask(); const session = makeSession(); store.createTask(task); store.createSession(session); expect(store.getSession(session.session_id)).toEqual(session); expect(store.getActiveSession(task.task_id, session.agent_id)).toEqual(session); expect(store.listTaskSessions(task.task_id)).toEqual([session]); expect(store.listActiveSessions(task.task_id)).toEqual([session]); }); it("round-trips artifacts", () => { const store = openStore("artifacts-round-trip"); const task = makeTask(); const session = makeSession(); const artifact = makeArtifact(); const artifactInput: ArtifactInput = { ...artifact, idempotency_key: "artifact-01" }; store.createTask(task); store.createSession(session); store.createArtifact(artifactInput); expect(store.getArtifact(artifact.artifact_id)).toEqual(artifact); expect(store.findArtifactByIdempotencyKey("artifact-01")).toEqual(artifact); expect(store.listArtifacts(task.task_id)).toEqual([artifact]); }); it("enforces one active session per task and agent", () => { const store = openStore("unique-active-session"); const task = makeTask(); store.createTask(task); store.createSession(makeSession()); expect(() => store.createSession( makeSession({ session_id: "session_02" }) ) ).toThrow(); }); it("allows active sessions for different agents on one task", () => { const store = openStore("multi-agent-active-sessions"); const task = makeTask(); store.createTask(task); store.createSession(makeSession()); store.createSession( makeSession({ session_id: "session_02", agent_id: "tester" }) ); expect(store.listActiveSessions(task.task_id)).toHaveLength(2); }); it("returns null for a missing session primary key", () => { const store = openStore("missing-session"); expect(store.getSession("does-not-exist")).toBeNull(); }); it("round-trips JSON metadata and nullable allowed agent ids", () => { const store = openStore("json-round-trip"); const task = makeTask({ task_id: "task_02", allowed_agent_ids: null, metadata: { tags: ["alpha", "beta"], nested: { count: 2 } } }); store.createTask(task); expect(store.getTask(task.task_id)).toEqual({ ...task, active_session_ids: [] }); }); });