Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
145 lines
7.5 KiB
Go
145 lines
7.5 KiB
Go
package storesqlite
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
)
|
|
|
|
func TestRuntimeOperationsV2UpgradesV1DataAndConstraints(t *testing.T) {
|
|
store := openTestStore(t, testOptions(&staticProjectPaths{}))
|
|
ctx := context.Background()
|
|
if _, err := store.db.Exec(`
|
|
DROP TABLE workspace_agent_runtime_operation_events;
|
|
DROP TABLE workspace_agent_runtime_operations;
|
|
DELETE FROM agent_store_schema_migrations
|
|
WHERE id IN ('workspace_agent_runtime_operations_v1', 'workspace_agent_runtime_operations_v2', 'workspace_agent_runtime_operations_v3', 'workspace_agent_runtime_operations_v4');
|
|
`); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := store.applyWorkspaceAgentRuntimeOperationsV1(ctx); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
seedRuntimeInteractiveSubject(t, store, "session-1", "turn-1", "request-1")
|
|
if _, err := store.db.Exec(`
|
|
INSERT INTO workspace_agent_runtime_operations (
|
|
operation_id, workspace_id, agent_session_id, kind, status, subject_id, turn_id,
|
|
request_id, payload_json, next_attempt_at_unix_ms, created_at_unix_ms, updated_at_unix_ms
|
|
) VALUES
|
|
('interactive-1', 'ws-1', 'session-1', 'interactive_response', 'prepared', 'request-1', 'turn-1',
|
|
'request-1', '{"answer":"yes"}', 10, 10, 10),
|
|
('cancel-1', 'ws-1', 'session-1', 'cancel_turn', 'prepared', 'turn-1', 'turn-1',
|
|
NULL, '{"rootAgentSessionId":"session-1","targets":[{"agentSessionId":"session-1","turnId":"turn-1"}]}', 10, 10, 10)
|
|
`); err != nil {
|
|
t.Fatalf("seed v1 operations: %v", err)
|
|
}
|
|
if _, err := store.db.Exec(`
|
|
INSERT INTO workspace_agent_runtime_operation_events (
|
|
operation_id, workspace_id, agent_session_id, kind, payload_json, created_at_unix_ms
|
|
) VALUES
|
|
('interactive-1', 'ws-1', 'session-1', 'interactive_completed', '{}', 11),
|
|
('cancel-1', 'ws-1', 'session-1', 'turn_canceled', '{}', 12)
|
|
`); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := store.applyWorkspaceAgentRuntimeOperationsV2(ctx); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
op, found, err := store.GetRuntimeOperation(ctx, "ws-1", "interactive-1")
|
|
if err != nil || !found || op.Kind != RuntimeOperationKindInteractiveResponse || op.RequestID != "request-1" {
|
|
t.Fatalf("operation=%#v found=%v err=%v", op, found, err)
|
|
}
|
|
cancelOperation, found, err := store.GetRuntimeOperation(ctx, "ws-1", "cancel-1")
|
|
if err != nil || !found || cancelOperation.Kind != RuntimeOperationKindCancelTurn || cancelOperation.TurnID != "turn-1" {
|
|
t.Fatalf("cancel operation=%#v found=%v err=%v", cancelOperation, found, err)
|
|
}
|
|
events, err := store.ListPendingRuntimeOperationEvents(ctx, "ws-1", 10)
|
|
if err != nil || len(events) != 2 || events[0].OperationID != "interactive-1" || events[1].OperationID != "cancel-1" {
|
|
t.Fatalf("events=%#v err=%v", events, err)
|
|
}
|
|
var migrationCount int
|
|
if err := store.db.QueryRow(`SELECT COUNT(*) FROM agent_store_schema_migrations WHERE id = ?`, schemaMigrationWorkspaceAgentRuntimeOperationsV2).Scan(&migrationCount); err != nil || migrationCount != 1 {
|
|
t.Fatalf("migration count=%d err=%v", migrationCount, err)
|
|
}
|
|
var indexCount int
|
|
if err := store.db.QueryRow(`SELECT COUNT(*) FROM sqlite_master WHERE type = 'index' AND name = 'idx_workspace_agent_runtime_operations_claimable'`).Scan(&indexCount); err != nil || indexCount != 1 {
|
|
t.Fatalf("claimable index count=%d err=%v", indexCount, err)
|
|
}
|
|
seedPlanDecisionSubject(t, store, "session-2", "plan-turn")
|
|
if _, err := store.db.Exec(`
|
|
INSERT INTO workspace_agent_runtime_operations (
|
|
operation_id, workspace_id, agent_session_id, kind, status, subject_id, turn_id,
|
|
request_id, payload_json, next_attempt_at_unix_ms, created_at_unix_ms, updated_at_unix_ms
|
|
) VALUES ('plan-op', 'ws-1', 'session-2', 'plan_decision', 'prepared', 'plan-turn',
|
|
'plan-turn', 'plan-turn', '{"promptKind":"plan-implementation","action":"implement","idempotencyKey":"decision-1","clientSubmitId":"plan-decision:plan-op","step":"prepared"}', 20, 20, 20)
|
|
`); err != nil {
|
|
t.Fatalf("seed valid v2 plan operation: %v", err)
|
|
}
|
|
if _, err := store.db.Exec(`
|
|
INSERT INTO workspace_agent_runtime_operations (
|
|
operation_id, workspace_id, agent_session_id, kind, status, subject_id, turn_id,
|
|
request_id, payload_json, next_attempt_at_unix_ms, created_at_unix_ms, updated_at_unix_ms
|
|
) VALUES ('invalid-plan', 'ws-1', 'session-2', 'plan_decision', 'prepared', 'plan-turn',
|
|
'plan-turn', 'plan-turn', '{"promptKind":"plan-implementation","action":"deny","idempotencyKey":"x","clientSubmitId":"plan-decision:invalid-plan","step":"prepared"}', 20, 20, 20)
|
|
`); err == nil {
|
|
t.Fatal("invalid plan payload bypassed v2 CHECK")
|
|
}
|
|
var foreignKeyCount int
|
|
rows, err := store.db.Query(`PRAGMA foreign_key_list(workspace_agent_runtime_operations)`)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for rows.Next() {
|
|
foreignKeyCount++
|
|
}
|
|
_ = rows.Close()
|
|
if foreignKeyCount < 2 {
|
|
t.Fatalf("foreign keys=%d, want session and turn", foreignKeyCount)
|
|
}
|
|
if err := store.applyWorkspaceAgentRuntimeOperationsV3(ctx); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := store.db.Exec(`
|
|
INSERT INTO workspace_agent_runtime_operation_events (
|
|
operation_id, workspace_id, agent_session_id, kind, payload_json, created_at_unix_ms
|
|
) VALUES
|
|
('plan-op', 'ws-1', 'session-2', 'plan_decision_pending_confirmation', '{}', 21),
|
|
('plan-op', 'ws-1', 'session-2', 'plan_decision_completed', '{}', 22)
|
|
`); err != nil {
|
|
t.Fatalf("v3 two-stage plan events: %v", err)
|
|
}
|
|
var v3Count int
|
|
if err := store.db.QueryRow(`SELECT COUNT(*) FROM agent_store_schema_migrations WHERE id = ?`, schemaMigrationWorkspaceAgentRuntimeOperationsV3).Scan(&v3Count); err != nil || v3Count != 1 {
|
|
t.Fatalf("v3 migration count=%d err=%v", v3Count, err)
|
|
}
|
|
if _, err := store.db.Exec(`UPDATE workspace_agent_runtime_operations SET attempt = 3, version = 4, last_error = 'retry me', updated_at_unix_ms = 25 WHERE operation_id = 'interactive-1'`); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := store.db.Exec(`UPDATE workspace_agent_runtime_operation_events SET published_at_unix_ms = 23 WHERE operation_id = 'interactive-1'`); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := store.applyWorkspaceAgentRuntimeOperationsV4(ctx); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var subjectColumnCount int
|
|
if err := store.db.QueryRow(`SELECT COUNT(*) FROM pragma_table_info('workspace_agent_runtime_operations') WHERE name = 'subject_id'`).Scan(&subjectColumnCount); err != nil || subjectColumnCount != 0 {
|
|
t.Fatalf("subject_id column count=%d err=%v", subjectColumnCount, err)
|
|
}
|
|
var operationCount, eventCount int
|
|
if err := store.db.QueryRow(`SELECT COUNT(*) FROM workspace_agent_runtime_operations`).Scan(&operationCount); err != nil || operationCount != 3 {
|
|
t.Fatalf("operation count=%d err=%v", operationCount, err)
|
|
}
|
|
if err := store.db.QueryRow(`SELECT COUNT(*) FROM workspace_agent_runtime_operation_events`).Scan(&eventCount); err != nil || eventCount != 4 {
|
|
t.Fatalf("event count=%d err=%v", eventCount, err)
|
|
}
|
|
var attempt, version int
|
|
var lastError string
|
|
var updatedAt int64
|
|
if err := store.db.QueryRow(`SELECT attempt, version, last_error, updated_at_unix_ms FROM workspace_agent_runtime_operations WHERE operation_id = 'interactive-1'`).Scan(&attempt, &version, &lastError, &updatedAt); err != nil || attempt != 3 || version != 4 || lastError != "retry me" || updatedAt != 25 {
|
|
t.Fatalf("preserved operation fields attempt=%d version=%d lastError=%q updatedAt=%d err=%v", attempt, version, lastError, updatedAt, err)
|
|
}
|
|
var publishedAt int64
|
|
if err := store.db.QueryRow(`SELECT published_at_unix_ms FROM workspace_agent_runtime_operation_events WHERE operation_id = 'interactive-1'`).Scan(&publishedAt); err != nil || publishedAt != 23 {
|
|
t.Fatalf("preserved event publishedAt=%d err=%v", publishedAt, err)
|
|
}
|
|
}
|