package app import ( "sync" "testing" ) func resetMcpCache() { mcpMu.Lock() defer mcpMu.Unlock() if mcpManager != nil { mcpManager.Close() } mcpKey, mcpManager = "", nil } func TestMcpManagerForCacheAndRebuild(t *testing.T) { resetMcpCache() defer resetMcpCache() cfgA := `[{"name":"a","command":"/bin/true"}]` cfgB := `[{"name":"b","command":"/bin/true"}]` m1 := mcpManagerFor(cfgA, "") if m1 == nil { t.Fatal("valid config must build a manager") } if m2 := mcpManagerFor(cfgA, ""); m2 != m1 { t.Fatal("same config must reuse the cached manager") } m3 := mcpManagerFor(cfgB, "") if m3 == nil || m3 == m1 { t.Fatal("changed config must rebuild a fresh manager") } if mcpManagerFor("", "") != nil { t.Fatal("empty config disables MCP and clears the cache") } if mcpManagerFor(`{bad json`, "") != nil { t.Fatal("invalid JSON must disable MCP (nil), not panic") } if mcpManagerFor(`[{"name":"bad name","command":"x"}]`, "") != nil { t.Fatal("invalid server config must disable MCP (nil)") } // 并发调用不死锁、返回同一实例或各自重建(缓存一致性由锁保证)。 var wg sync.WaitGroup for i := 0; i < 8; i++ { wg.Add(1) go func() { defer wg.Done() _ = mcpManagerFor(cfgB, "") }() } wg.Wait() } func TestMcpCacheConcurrencyWithSettingsResolution(t *testing.T) { resetMcpCache() defer resetMcpCache() var wg sync.WaitGroup cfgs := []string{ `[{"name":"a","command":"/bin/true"}]`, `[{"name":"b","command":"/bin/true"}]`, "", } for i := 0; i < 12; i++ { wg.Add(1) go func(i int) { defer wg.Done() _ = mcpManagerFor(cfgs[i%len(cfgs)], "") }(i) } wg.Wait() }