Files
tutti/packages/agent/store-sqlite/activity_session_pages_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

216 lines
8.6 KiB
Go

package storesqlite
import (
"context"
"slices"
"strings"
"testing"
)
func TestStoreListSessionsPageOwnsSearchCursorAndIncludedSessionFiltering(t *testing.T) {
t.Parallel()
store := openTestStore(t, testOptions(&staticProjectPaths{}))
ctx := context.Background()
for _, report := range []ActivityStateReport{
sectionBatchActivityReport("ws-session-page", "alpha-new", testTargetIDCodex, "/workspace/scratch", 3_000),
sectionBatchActivityReport("ws-session-page", "alpha-old", testTargetIDCodex, "/workspace/scratch", 2_000),
sectionBatchActivityReport("ws-session-page", "alpha-foreign", testTargetIDCodex, "/workspace/scratch", 4_000),
sectionBatchActivityReport("ws-session-page", "beta", testTargetIDCodex, "/workspace/scratch", 5_000),
} {
if _, err := store.ReportActivityState(ctx, report); err != nil {
t.Fatalf("ReportActivityState(%s) error = %v", report.Session.AgentSessionID, err)
}
}
for sessionID, title := range map[string]string{
"alpha-new": "Alpha build plan",
"alpha-old": "Review alpha build",
"alpha-foreign": "Alpha foreign",
"beta": "Beta build",
} {
if _, ok, err := store.UpdateSessionTitle(ctx, "ws-session-page", sessionID, title); err != nil || !ok {
t.Fatalf("UpdateSessionTitle(%s) ok=%v error=%v", sessionID, ok, err)
}
}
first, ok, err := store.ListSessionsPage(ctx, ListSessionsPageInput{
WorkspaceID: "ws-session-page",
SearchQuery: " alpha build ",
IncludedSessionIDs: []string{"alpha-new", "alpha-old", "beta"},
Limit: 1,
})
if err != nil || !ok {
t.Fatalf("ListSessionsPage(first) ok=%v error=%v", ok, err)
}
if got := sessionIDsFromSessions(first.Sessions); strings.Join(got, ",") != "alpha-new" {
t.Fatalf("first session ids = %#v, want alpha-new", got)
}
if !first.HasMore || first.NextCursor != "3000|alpha-new" {
t.Fatalf("first page = %#v, want stable next cursor", first)
}
second, ok, err := store.ListSessionsPage(ctx, ListSessionsPageInput{
WorkspaceID: "ws-session-page",
SearchQuery: "alpha build",
IncludedSessionIDs: []string{"alpha-new", "alpha-old", "beta"},
CursorSortTimeUnixMS: 3_000,
CursorSessionID: "alpha-new",
Limit: 1,
})
if err != nil || !ok {
t.Fatalf("ListSessionsPage(second) ok=%v error=%v", ok, err)
}
if got := sessionIDsFromSessions(second.Sessions); strings.Join(got, ",") != "alpha-old" {
t.Fatalf("second session ids = %#v, want alpha-old", got)
}
if second.HasMore || second.NextCursor != "" {
t.Fatalf("second page = %#v, want terminal page", second)
}
}
func TestStoreListSessionsPageAppliesTargetVisibilityAndLiteralSearchTokens(t *testing.T) {
t.Parallel()
store := openTestStore(t, testOptions(&staticProjectPaths{}))
ctx := context.Background()
reports := []ActivityStateReport{
sectionBatchActivityReport("ws-session-page-filters", "literal", testTargetIDCodex, "/workspace/scratch", 4_000),
sectionBatchActivityReport("ws-session-page-filters", "wildcard-match", testTargetIDCodex, "/workspace/scratch", 3_000),
sectionBatchActivityReport("ws-session-page-filters", "other-target", testTargetIDClaude, "/workspace/scratch", 2_000),
sectionBatchActivityReport("ws-session-page-filters", "hidden", testTargetIDCodex, "/workspace/scratch", 1_000),
}
reports[3].Session.RuntimeContext = map[string]any{"visible": false}
for _, report := range reports {
if _, err := store.ReportActivityState(ctx, report); err != nil {
t.Fatalf("ReportActivityState(%s) error = %v", report.Session.AgentSessionID, err)
}
}
for sessionID, title := range map[string]string{
"literal": "Literal 100% _ build",
"wildcard-match": "Literal 100X Y build",
"other-target": "Literal 100% _ build",
"hidden": "Literal 100% _ build",
} {
if _, ok, err := store.UpdateSessionTitle(ctx, "ws-session-page-filters", sessionID, title); err != nil || !ok {
t.Fatalf("UpdateSessionTitle(%s) ok=%v error=%v", sessionID, ok, err)
}
}
page, ok, err := store.ListSessionsPage(ctx, ListSessionsPageInput{
WorkspaceID: "ws-session-page-filters",
AgentTargetID: testTargetIDCodex,
SearchQuery: "100% _",
Limit: 10,
})
if err != nil || !ok {
t.Fatalf("ListSessionsPage() ok=%v error=%v", ok, err)
}
if got := sessionIDsFromSessions(page.Sessions); !slices.Equal(got, []string{"literal"}) {
t.Fatalf("session ids = %#v, want only visible exact-target literal match", got)
}
}
func TestStoreSessionPagesUseSessionStartBeforePersistenceTimeWithoutTurns(t *testing.T) {
t.Parallel()
store := openTestStore(t, testOptions(&staticProjectPaths{paths: []string{"/workspace/app"}}))
ctx := context.Background()
reports := []ActivityStateReport{
sectionBatchActivityReport("ws-session-start-order", "started-older", testTargetIDCodex, "/workspace/app", 2_000),
sectionBatchActivityReport("ws-session-start-order", "started-newer", testTargetIDCodex, "/workspace/app", 3_000),
}
reports[0].Turn = nil
reports[0].Session.StartedAtUnixMS = 2_000
reports[0].Session.CreatedAtUnixMS = 5_000
reports[1].Turn = nil
reports[1].Session.StartedAtUnixMS = 3_000
reports[1].Session.CreatedAtUnixMS = 4_000
for _, report := range reports {
if _, err := store.ReportActivityState(ctx, report); err != nil {
t.Fatalf("ReportActivityState(%s) error = %v", report.Session.AgentSessionID, err)
}
}
page, ok, err := store.ListSessionsPage(ctx, ListSessionsPageInput{
WorkspaceID: "ws-session-start-order",
Limit: 10,
})
if err != nil || !ok {
t.Fatalf("ListSessionsPage() ok=%v error=%v", ok, err)
}
if got := sessionIDsFromSessions(page.Sessions); !slices.Equal(got, []string{"started-newer", "started-older"}) {
t.Fatalf("session page ids = %#v, want session start order", got)
}
section, ok, err := store.ListSessionSection(ctx, ListSessionSectionInput{
WorkspaceID: "ws-session-start-order",
SectionKey: RailSectionKeyForProject("/workspace/app"),
Limit: 10,
})
if err != nil || !ok {
t.Fatalf("ListSessionSection() ok=%v error=%v", ok, err)
}
if got := sessionIDsFromSessions(section.Sessions); !slices.Equal(got, []string{"started-newer", "started-older"}) {
t.Fatalf("section page ids = %#v, want session start order", got)
}
}
func TestStoreRailQueriesApplyIncludedSessionIDsBeforePagingAndCounting(t *testing.T) {
t.Parallel()
store := openTestStore(t, testOptions(&staticProjectPaths{paths: []string{"/workspace/app"}}))
ctx := context.Background()
for _, report := range []ActivityStateReport{
sectionBatchActivityReport("ws-included-rail", "owned-new", testTargetIDCodex, "/workspace/app", 3_000),
sectionBatchActivityReport("ws-included-rail", "owned-old", testTargetIDCodex, "/workspace/app", 2_000),
sectionBatchActivityReport("ws-included-rail", "foreign", testTargetIDCodex, "/workspace/app", 4_000),
sectionBatchActivityReport("ws-included-rail", "owned-pinned", testTargetIDCodex, "/workspace/app", 5_000),
} {
if _, err := store.ReportActivityState(ctx, report); err != nil {
t.Fatalf("ReportActivityState(%s) error = %v", report.Session.AgentSessionID, err)
}
}
if _, ok, err := store.UpdateSessionPinned(ctx, "ws-included-rail", "owned-pinned", true); err != nil || !ok {
t.Fatalf("UpdateSessionPinned() ok=%v error=%v", ok, err)
}
included := []string{"owned-new", "owned-old", "owned-pinned"}
projectKey := RailSectionKeyForProject("/workspace/app")
sections, ok, err := store.ListSessionSections(ctx, ListSessionSectionsInput{
WorkspaceID: "ws-included-rail",
SectionKeys: []string{PinnedSessionPageKey, projectKey},
IncludedSessionIDs: included,
LimitPerSection: 1,
})
if err != nil || !ok {
t.Fatalf("ListSessionSections() ok=%v error=%v", ok, err)
}
pages := map[string]SessionSectionPage{}
for _, page := range sections.Sections {
pages[page.SectionKey] = page
}
assertSectionBatchPage(t, pages[PinnedSessionPageKey], []string{"owned-pinned"}, 1, false)
assertSectionBatchPage(t, pages[projectKey], []string{"owned-new"}, 2, true)
candidates, ok, err := store.ListSessionSectionDeletionCandidates(ctx, ListSessionSectionDeletionCandidatesInput{
WorkspaceID: "ws-included-rail",
SectionKey: projectKey,
IncludedSessionIDs: included,
ExcludePinned: true,
})
if err != nil || !ok {
t.Fatalf("ListSessionSectionDeletionCandidates() ok=%v error=%v", ok, err)
}
slices.Sort(candidates.SessionIDs)
if got := strings.Join(candidates.SessionIDs, ","); got != "owned-new,owned-old" {
t.Fatalf("candidate session ids = %q, want owned-new,owned-old", got)
}
}
func sessionIDsFromSessions(sessions []Session) []string {
result := make([]string, 0, len(sessions))
for _, session := range sessions {
result = append(result, session.ID)
}
return result
}