package mcp import ( "context" "testing" "github.com/stretchr/testify/assert" ) func TestWithSessionID_RoundTrip(t *testing.T) { ctx := WithSessionID(context.Background(), "sess_abc") assert.Equal(t, "sess_abc", SessionIDFromContext(ctx)) } func TestWithSessionID_EmptyIsNoOp(t *testing.T) { // Empty session IDs shouldn't pollute the ctx tree with a useless // key — callers rely on SessionIDFromContext == "" as the signal // "no session, use default." base := context.Background() withEmpty := WithSessionID(base, "") assert.Equal(t, base, withEmpty, "empty session ID must return ctx unchanged") assert.Equal(t, "", SessionIDFromContext(withEmpty)) } func TestSessionIDFromContext_BareContext(t *testing.T) { // A context with no session value attached should return "" rather // than panic — callers rely on "" as the "no session, use default" // signal, and the helper must be safe to call from any callsite. assert.Equal(t, "", SessionIDFromContext(context.TODO())) } func TestSessionMap_GetCreatesLazily(t *testing.T) { m := newSessionMap() s1 := m.get("a") s2 := m.get("a") assert.Same(t, s1, s2, "repeated get(same id) must return the same entry") s3 := m.get("b") assert.NotSame(t, s1, s3, "different ids must yield distinct entries") } func TestSessionMap_Release(t *testing.T) { m := newSessionMap() original := m.get("a") m.release("a") reborn := m.get("a") assert.NotSame(t, original, reborn, "release() must drop the entry so a subsequent get() yields a fresh one") } // TestServer_SessionFor_IsolatedState proves that two different session // IDs get independent per-client activity state — the core guarantee // that makes the daemon's shared *mcp.Server safe for concurrent // proxies. func TestServer_SessionFor_IsolatedState(t *testing.T) { srv, _ := setupTestServer(t) ctxA := WithSessionID(context.Background(), "session_A") ctxB := WithSessionID(context.Background(), "session_B") srv.sessionFor(ctxA).recordSymbol("main.go::Foo") srv.sessionFor(ctxB).recordSymbol("main.go::Bar") snapA := srv.sessionFor(ctxA).snapshot() snapB := srv.sessionFor(ctxB).snapshot() symsA, _ := snapA["viewed_symbols"].([]string) symsB, _ := snapB["viewed_symbols"].([]string) assert.Contains(t, symsA, "main.go::Foo", "session A must see its own symbol") assert.NotContains(t, symsA, "main.go::Bar", "session A must NOT see session B's symbol") assert.Contains(t, symsB, "main.go::Bar", "session B must see its own symbol") assert.NotContains(t, symsB, "main.go::Foo", "session B must NOT see session A's symbol") } // TestServer_SessionFor_NoIDFallsBackToShared confirms that embedded // mode (no session ID in ctx) still hits the shared default state, so // existing single-client behavior is preserved byte-for-byte. func TestServer_SessionFor_NoIDFallsBackToShared(t *testing.T) { srv, _ := setupTestServer(t) // No WithSessionID → fallback to shared default. sess := srv.sessionFor(context.Background()) assert.Same(t, srv.session, sess, "ctx without session ID must route to the shared default") } // TestServer_TokenStatsFor_IsolatedCounters proves per-session token // savings stay separate. Client A's record() calls must not show up in // client B's session-level snapshot — the token_savings field in // graph_stats would otherwise merge them and mislead each client about // its own efficiency. func TestServer_TokenStatsFor_IsolatedCounters(t *testing.T) { srv, _ := setupTestServer(t) ctxA := WithSessionID(context.Background(), "session_A") ctxB := WithSessionID(context.Background(), "session_B") // A records 1000 saved / 500 returned; B records 300/100. srv.tokenStatsFor(ctxA).record(nil, "test", 500, 1500) // returned=500, fullFile=1500 → saved=1000 srv.tokenStatsFor(ctxB).record(nil, "test", 100, 400) // returned=100, fullFile=400 → saved=300 snapA := srv.tokenStatsFor(ctxA).snapshot() snapB := srv.tokenStatsFor(ctxB).snapshot() assert.EqualValues(t, 1000, snapA["tokens_saved"], "session A isolated counter") assert.EqualValues(t, 300, snapB["tokens_saved"], "session B isolated counter") assert.EqualValues(t, 1, snapA["calls_counted"]) assert.EqualValues(t, 1, snapB["calls_counted"]) }