Files
tutti/services/tuttid/data/workspace/sqlite_agent_targets_test.go
agent-radar 2ed3415fb7
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
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

245 lines
7.6 KiB
Go

package workspace
import (
"context"
"errors"
"testing"
"github.com/tutti-os/tutti/packages/agent/daemon/providerregistry"
agenttargetbiz "github.com/tutti-os/tutti/services/tuttid/biz/agenttarget"
)
func TestDefaultTargetIDBackfillUsesMigratedProviderDescriptors(t *testing.T) {
descriptor, ok := providerregistry.Find(providerregistry.CodexProviderID)
if !ok {
t.Fatal("codex descriptor missing")
}
got := defaultTargetIDBackfillByProvider()
if got[descriptor.Identity.ID] != descriptor.Target.ID {
t.Fatalf("codex target backfill = %q, want %q", got[descriptor.Identity.ID], descriptor.Target.ID)
}
if got["claude-code"] != agenttargetbiz.IDLocalClaudeCode || got["cursor"] != agenttargetbiz.IDLocalCursor {
t.Fatalf("legacy target backfills = %#v", got)
}
}
func TestSQLiteStoreSeedsSystemAgentTargets(t *testing.T) {
t.Parallel()
store := openTestSQLiteStore(t)
targets, err := store.ListAgentTargets(context.Background())
if err != nil {
t.Fatalf("ListAgentTargets() error = %v", err)
}
descriptors := providerregistry.Migrated()
if len(targets) != len(descriptors) {
t.Fatalf("ListAgentTargets() len = %d, want descriptor count %d", len(targets), len(descriptors))
}
descriptorsByTargetID := make(map[string]providerregistry.ProviderDescriptor, len(descriptors))
for _, descriptor := range descriptors {
descriptorsByTargetID[descriptor.Target.ID] = descriptor
}
for index, target := range targets {
descriptor, ok := descriptorsByTargetID[target.ID]
if !ok || target.Provider != descriptor.Identity.ID || target.Enabled != descriptor.Target.Enabled {
t.Fatalf("target[%d] = %#v, want matching descriptor target", index, target)
}
if target.Source != agenttargetbiz.SourceSystem {
t.Fatalf("target %q source = %q, want system", target.ID, target.Source)
}
if target.IconURL == "" {
t.Fatalf("target %q icon url missing", target.ID)
}
if target.IconKey == "hermes" || target.IconKey == "openclaw" {
if target.MaskIconURL != "" {
t.Fatalf("target %q mask icon url = %q, want empty image fallback", target.ID, target.MaskIconURL)
}
} else if target.MaskIconURL == "" {
t.Fatalf("target %q mask icon url missing", target.ID)
}
if _, err := agenttargetbiz.CanonicalLaunchRefJSONString(target.Provider, target.LaunchRefJSON); err != nil {
t.Fatalf("target %q launch ref invalid: %v", target.ID, err)
}
}
}
func TestSQLiteStoreListAgentTargetsSkipsInvalidRows(t *testing.T) {
t.Parallel()
ctx := context.Background()
store := openTestSQLiteStore(t)
now := int64(1700000000000)
if _, err := store.writeDB.ExecContext(ctx, `
INSERT INTO agent_targets (
id,
provider,
launch_ref_json,
name,
icon_key,
enabled,
source,
sort_order,
created_at_ms,
updated_at_ms
)
VALUES ('broken-target', 'codex', '{"type":"local_cli","provider":"claude-code"}', 'Broken Target', NULL, 1, 'user', 5, ?, ?);
`, now, now); err != nil {
t.Fatalf("insert invalid agent target fixture: %v", err)
}
targets, err := store.ListAgentTargets(ctx)
if err != nil {
t.Fatalf("ListAgentTargets() error = %v", err)
}
ids := make(map[string]bool, len(targets))
for _, target := range targets {
ids[target.ID] = true
}
if ids["broken-target"] {
t.Fatalf("ListAgentTargets() returned invalid target: %#v", targets)
}
if !ids[agenttargetbiz.IDLocalCodex] || !ids[agenttargetbiz.IDLocalClaudeCode] {
t.Fatalf("ListAgentTargets() ids = %#v, want system targets", ids)
}
}
func TestSQLiteStoreSeedReconcilesLegacySystemAgentTargetIDs(t *testing.T) {
t.Parallel()
ctx := context.Background()
store := openTestSQLiteStore(t)
now := int64(1700000000000)
if _, err := store.writeDB.ExecContext(ctx, `
INSERT INTO workspaces (id, name, created_at_unix_ms, updated_at_unix_ms)
VALUES ('ws-legacy-targets', 'Legacy Targets', ?, ?);
`, now, now); err != nil {
t.Fatalf("insert legacy workspace fixture: %v", err)
}
if _, err := store.writeDB.ExecContext(ctx, `
INSERT INTO agent_targets (
id,
provider,
launch_ref_json,
name,
icon_key,
enabled,
source,
sort_order,
created_at_ms,
updated_at_ms
)
VALUES (?, 'codex', ?, 'Legacy Codex', 'codex', 1, 'system', 10, ?, ?);
`, legacyIDLocalCodex, agenttargetbiz.MustLocalCLILaunchRefJSON("codex"), now, now); err != nil {
t.Fatalf("insert legacy agent target fixture: %v", err)
}
if _, err := store.writeDB.ExecContext(ctx, `
INSERT INTO workspace_agent_sessions (
workspace_id,
agent_session_id,
origin,
agent_target_id,
provider,
created_at_unix_ms,
updated_at_unix_ms
)
VALUES ('ws-legacy-targets', 'session-1', 'runtime', ?, 'codex', ?, ?);
`, legacyIDLocalCodex, now, now); err != nil {
t.Fatalf("insert legacy agent session fixture: %v", err)
}
// Seeding and legacy target ID reconciliation run on every Migrate.
if err := store.Migrate(ctx); err != nil {
t.Fatalf("Migrate() error = %v", err)
}
if _, err := store.GetAgentTarget(ctx, legacyIDLocalCodex); !errors.Is(err, ErrAgentTargetNotFound) {
t.Fatalf("GetAgentTarget(legacy) error = %v, want ErrAgentTargetNotFound", err)
}
if _, err := store.GetAgentTarget(ctx, agenttargetbiz.IDLocalCodex); err != nil {
t.Fatalf("GetAgentTarget(current) error = %v", err)
}
sessions, ok, err := store.ListSessions(ctx, "ws-legacy-targets")
if err != nil {
t.Fatalf("ListSessions() error = %v", err)
}
if !ok || len(sessions) != 1 {
t.Fatalf("ListSessions() ok/len = %v/%d, want true/1", ok, len(sessions))
}
if sessions[0].AgentTargetID != agenttargetbiz.IDLocalCodex {
t.Fatalf("session agent target id = %q, want %s", sessions[0].AgentTargetID, agenttargetbiz.IDLocalCodex)
}
}
func TestSQLiteStorePutAgentTargetRejectsInvalidLaunchRefs(t *testing.T) {
t.Parallel()
for _, tc := range []struct {
name string
provider string
launchRefJSON string
}{
{
name: "unknown type",
provider: "codex",
launchRefJSON: `{"type":"agent_profile","provider":"codex"}`,
},
{
name: "provider mismatch",
provider: "codex",
launchRefJSON: `{"type":"local_cli","provider":"claude-code"}`,
},
{
name: "config blob",
provider: "codex",
launchRefJSON: `{"type":"local_cli","provider":"codex","model":"gpt-5"}`,
},
{
name: "prompt config",
provider: "codex",
launchRefJSON: `{"type":"local_cli","provider":"codex","prompt":"always plan"}`,
},
} {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
store := openTestSQLiteStore(t)
_, err := store.PutAgentTarget(context.Background(), agenttargetbiz.Target{
ID: "custom",
Provider: tc.provider,
LaunchRefJSON: tc.launchRefJSON,
Name: "Custom",
Enabled: true,
Source: agenttargetbiz.SourceUser,
})
if !errors.Is(err, agenttargetbiz.ErrInvalidLaunchRef) {
t.Fatalf("PutAgentTarget() error = %v, want ErrInvalidLaunchRef", err)
}
})
}
}
func TestSQLiteStorePutAgentTargetCanonicalizesLaunchRef(t *testing.T) {
t.Parallel()
store := openTestSQLiteStore(t)
target, err := store.PutAgentTarget(context.Background(), agenttargetbiz.Target{
ID: "custom-codex",
Provider: " codex ",
LaunchRefJSON: `{"provider":"codex","type":"local_cli"}`,
Name: " Custom Codex ",
Enabled: true,
Source: agenttargetbiz.SourceUser,
SortOrder: 30,
})
if err != nil {
t.Fatalf("PutAgentTarget() error = %v", err)
}
if target.LaunchRefJSON != `{"type":"builtin_local","provider":"codex"}` {
t.Fatalf("LaunchRefJSON = %q, want canonical builtin_local codex", target.LaunchRefJSON)
}
if target.Name != "Custom Codex" {
t.Fatalf("Name = %q, want trimmed Custom Codex", target.Name)
}
}