test(core): restore 9 unit tests removed by PR #603 (S1011 coverage)

PR #603 (S1011 fix for #600) removed 9 unit tests targeting
SwitchToAgentSession, recordPastAgentSessionID, and KnownAgentSessionIDs —
production functions that the PR kept. The production code never lost
those behaviors, but the test coverage dropped by 9. QA review
(msg-20260607-4iaibz/2ocb88) flagged this as a P1 blocker on the merge.

Restore the 9 tests verbatim from commit 4e61c8f5 (which sat on the
pre-rebase base of #603) so the merge of #603 into main does not lose
the regression coverage for the legacy-session-preservation invariant
that #603 was built on top of.

- TestSwitchToAgentSession_PreservesOldSession
- TestSwitchToAgentSession_ReusesExisting
- TestPastAgentSessionIDs_ClearPreservesHistory
- TestPastAgentSessionIDs_ReplacePreservesHistory
- TestPastAgentSessionIDs_NoDuplicates
- TestPastAgentSessionIDs_ContinueSentinelNotRecorded
- TestKnownAgentSessionIDs_IncludesPast
- TestKnownAgentSessionIDs_ReproducesNewCommandBug
- TestKnownAgentSessionIDs_ResetAllSessionsBug

Co-existence verified: the 9 new tests live alongside the existing
TestPruneDuplicateSessions_* tests in core/session_test.go and exercise
the same package-level helpers (NewSessionManager, Session,
SetAgentSessionID, SwitchToAgentSession, KnownAgentSessionIDs,
filterOwnedSessions, AgentSessionInfo).

No production code touched. No changes to the S1011 fix at
core/session.go:878, sort.SliceStable at :879, /prune subcommand,
PruneDuplicateSessions, --empty/--merge flags, or
TestPruneDuplicateSessions_NoMergeKeepsBothWithHistory.

go test -count=1 -tags no_web ./core/  →  ok  (39 existing + 9 restored = 48 tests)
go vet -tags no_web ./core/...        →  clean

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Claude
2026-06-09 08:07:58 +00:00
parent a298743a46
commit 3392323b3b

View File

@@ -897,3 +897,187 @@ func TestPruneDuplicateSessions_Persistence(t *testing.T) {
t.Errorf("merged history after reload = %d, want 2", len(history))
}
}
// TestSwitchToAgentSession_PreservesOldSession locks down that switching the
// active session to a different agent_session_id keeps the previous ID in
// KnownAgentSessionIDs so it stays visible to /list, /switch, and
// filterOwnedSessions. Regression test for #603 / issue #600.
func TestSwitchToAgentSession_PreservesOldSession(t *testing.T) {
dir := t.TempDir()
sm := NewSessionManager(dir + "/sessions.json")
userKey := "user:alice"
s1 := sm.GetOrCreateActive(userKey)
s1.SetAgentInfo("agent-A", "claude", "session A")
known := sm.KnownAgentSessionIDs()
if _, ok := known["agent-A"]; !ok {
t.Fatal("agent-A should be in KnownAgentSessionIDs before switch")
}
s2 := sm.SwitchToAgentSession(userKey, "agent-B", "claude", "session B")
if s2.GetAgentSessionID() != "agent-B" {
t.Fatalf("switched session AgentSessionID = %q, want agent-B", s2.GetAgentSessionID())
}
known = sm.KnownAgentSessionIDs()
if _, ok := known["agent-A"]; !ok {
t.Fatal("agent-A should still be in KnownAgentSessionIDs after switch")
}
if _, ok := known["agent-B"]; !ok {
t.Fatal("agent-B should be in KnownAgentSessionIDs after switch")
}
}
func TestSwitchToAgentSession_ReusesExisting(t *testing.T) {
dir := t.TempDir()
sm := NewSessionManager(dir + "/sessions.json")
userKey := "user:bob"
s1 := sm.GetOrCreateActive(userKey)
s1.SetAgentInfo("agent-A", "claude", "session A")
sm.SwitchToAgentSession(userKey, "agent-B", "claude", "session B")
s3 := sm.SwitchToAgentSession(userKey, "agent-A", "claude", "session A")
if s3.ID != s1.ID {
t.Fatalf("switching back to agent-A should reuse session %s, got %s", s1.ID, s3.ID)
}
}
func TestPastAgentSessionIDs_ClearPreservesHistory(t *testing.T) {
s := &Session{}
s.SetAgentSessionID("thread-1", "codex")
s.SetAgentSessionID("", "")
if len(s.PastAgentSessionIDs) != 1 || s.PastAgentSessionIDs[0] != "thread-1" {
t.Fatalf("PastAgentSessionIDs = %v, want [thread-1]", s.PastAgentSessionIDs)
}
}
func TestPastAgentSessionIDs_ReplacePreservesHistory(t *testing.T) {
s := &Session{}
s.SetAgentSessionID("thread-1", "codex")
s.SetAgentSessionID("thread-2", "codex")
if len(s.PastAgentSessionIDs) != 1 || s.PastAgentSessionIDs[0] != "thread-1" {
t.Fatalf("PastAgentSessionIDs = %v, want [thread-1]", s.PastAgentSessionIDs)
}
if s.AgentSessionID != "thread-2" {
t.Fatalf("AgentSessionID = %q, want thread-2", s.AgentSessionID)
}
}
func TestPastAgentSessionIDs_NoDuplicates(t *testing.T) {
s := &Session{}
s.SetAgentSessionID("thread-1", "codex")
s.SetAgentSessionID("", "")
s.SetAgentSessionID("thread-1", "codex")
s.SetAgentSessionID("", "")
if len(s.PastAgentSessionIDs) != 1 {
t.Fatalf("PastAgentSessionIDs has duplicates: %v", s.PastAgentSessionIDs)
}
}
func TestPastAgentSessionIDs_ContinueSentinelNotRecorded(t *testing.T) {
s := &Session{}
s.SetAgentSessionID(ContinueSession, "codex")
s.SetAgentSessionID("real-id", "codex")
s.SetAgentSessionID("", "")
for _, past := range s.PastAgentSessionIDs {
if past == ContinueSession {
t.Fatal("ContinueSession sentinel should not be in PastAgentSessionIDs")
}
}
if len(s.PastAgentSessionIDs) != 1 || s.PastAgentSessionIDs[0] != "real-id" {
t.Fatalf("PastAgentSessionIDs = %v, want [real-id]", s.PastAgentSessionIDs)
}
}
func TestKnownAgentSessionIDs_IncludesPast(t *testing.T) {
sm := NewSessionManager("")
s1 := sm.NewSession("user1", "a")
s1.SetAgentSessionID("thread-aaa", "codex")
s1.SetAgentSessionID("", "")
s2 := sm.NewSession("user1", "b")
s2.SetAgentSessionID("thread-bbb", "codex")
known := sm.KnownAgentSessionIDs()
if _, ok := known["thread-aaa"]; !ok {
t.Fatal("expected thread-aaa (past ID) in known set")
}
if _, ok := known["thread-bbb"]; !ok {
t.Fatal("expected thread-bbb (current ID) in known set")
}
}
// TestKnownAgentSessionIDs_ReproducesNewCommandBug simulates the exact user
// reproduction steps: repeated /new commands progressively clear AgentSessionIDs.
// Before the PastAgentSessionIDs fix, only the latest session would remain visible.
func TestKnownAgentSessionIDs_ReproducesNewCommandBug(t *testing.T) {
sm := NewSessionManager("")
userKey := "user:test"
agentSessions := []AgentSessionInfo{
{ID: "codex-thread-1"},
{ID: "codex-thread-2"},
{ID: "codex-thread-3"},
}
s1 := sm.GetOrCreateActive(userKey)
s1.SetAgentSessionID("codex-thread-1", "codex")
s1.SetAgentSessionID("", "")
s2 := sm.NewSession(userKey, "session 2")
s2.SetAgentSessionID("codex-thread-2", "codex")
s2.SetAgentSessionID("", "")
s3 := sm.NewSession(userKey, "session 3")
s3.SetAgentSessionID("codex-thread-3", "codex")
known := sm.KnownAgentSessionIDs()
filtered := filterOwnedSessions(agentSessions, known)
if len(filtered) != 3 {
t.Fatalf("filterOwnedSessions returned %d sessions, want 3 (all should be visible)\nknown IDs: %v",
len(filtered), known)
}
}
// TestKnownAgentSessionIDs_ResetAllSessionsBug simulates resetAllSessions
// clearing all IDs (management API provider switch). Past IDs should keep
// all sessions visible.
func TestKnownAgentSessionIDs_ResetAllSessionsBug(t *testing.T) {
sm := NewSessionManager("")
userKey := "user:test"
s1 := sm.NewSession(userKey, "a")
s1.SetAgentSessionID("thread-1", "codex")
s2 := sm.NewSession(userKey, "b")
s2.SetAgentSessionID("thread-2", "codex")
s3 := sm.NewSession(userKey, "c")
s3.SetAgentSessionID("thread-3", "codex")
for _, s := range sm.AllSessions() {
s.SetAgentSessionID("", "")
}
known := sm.KnownAgentSessionIDs()
for _, id := range []string{"thread-1", "thread-2", "thread-3"} {
if _, ok := known[id]; !ok {
t.Fatalf("expected %s in known set after resetAllSessions, known = %v", id, known)
}
}
agentSessions := []AgentSessionInfo{
{ID: "thread-1"}, {ID: "thread-2"}, {ID: "thread-3"},
}
filtered := filterOwnedSessions(agentSessions, known)
if len(filtered) != 3 {
t.Fatalf("filterOwnedSessions returned %d, want 3", len(filtered))
}
}