fix: stabilize direct runtime endpoint tests

This commit is contained in:
InternZzp
2026-06-10 21:07:03 +08:00
parent 2c1be7a8fb
commit 532fcb4874
2 changed files with 27 additions and 35 deletions
+21 -28
View File
@@ -223,12 +223,9 @@ func directRuntimeToolEndpoint(toolName string) (string, bool) {
return "", false return "", false
} }
dynamicMu.RLock() dynamicMu.RLock()
te := dynamicToolEndpoints defer dynamicMu.RUnlock()
dynamicMu.RUnlock()
if te == nil { endpoint, ok := dynamicToolEndpoints[toolName]
return "", false
}
endpoint, ok := te[toolName]
return endpoint, ok && strings.TrimSpace(endpoint) != "" return endpoint, ok && strings.TrimSpace(endpoint) != ""
} }
@@ -252,24 +249,19 @@ func directRuntimeEndpoint(productID, toolName string) (string, bool) {
} }
} }
dynamicMu.RLock()
de := dynamicEndpoints
te := dynamicToolEndpoints
dynamicMu.RUnlock()
// Priority 1: product-level endpoint. // Priority 1: product-level endpoint.
// When the caller already knows the productID (e.g. "drive"), the product // When the caller already knows the productID (e.g. "drive"), the product
// endpoint is authoritative. This prevents cross-product tool name // endpoint is authoritative. This prevents cross-product tool name
// collisions (e.g. both "drive" and "doc" register "create_folder") from // collisions (e.g. both "drive" and "doc" register "create_folder") from
// routing the request to the wrong MCP server. See issue #219. // routing the request to the wrong MCP server. See issue #219.
dynamicMu.RLock()
for _, candidate := range []string{strings.TrimSpace(productID), normalized} { for _, candidate := range []string{strings.TrimSpace(productID), normalized} {
if candidate == "" { if candidate == "" {
continue continue
} }
if de != nil { if endpoint, ok := dynamicEndpoints[candidate]; ok {
if endpoint, ok := de[candidate]; ok { dynamicMu.RUnlock()
return endpoint, true return endpoint, true
}
} }
} }
@@ -277,11 +269,13 @@ func directRuntimeEndpoint(productID, toolName string) (string, bool) {
// This path is used when the caller does not know the productID but has a // This path is used when the caller does not know the productID but has a
// tool name, e.g. in helper invocations or plugin routes where only the // tool name, e.g. in helper invocations or plugin routes where only the
// tool name is available. // tool name is available.
if tool := strings.TrimSpace(toolName); tool != "" && te != nil { if tool := strings.TrimSpace(toolName); tool != "" {
if endpoint, ok := te[tool]; ok { if endpoint, ok := dynamicToolEndpoints[tool]; ok {
dynamicMu.RUnlock()
return endpoint, true return endpoint, true
} }
} }
dynamicMu.RUnlock()
// Priority 3: built-in PAT fallback for cold-start paths that run before // Priority 3: built-in PAT fallback for cold-start paths that run before
// discovery/plugin registration has populated the dynamic registry. // discovery/plugin registration has populated the dynamic registry.
@@ -347,12 +341,12 @@ func endpointFromEditionServers(productID string, fn func() []edition.ServerInfo
// through DINGTALK_<PRODUCT>_MCP_URL instead of requiring discovery. // through DINGTALK_<PRODUCT>_MCP_URL instead of requiring discovery.
func DirectRuntimeProductIDs() map[string]bool { func DirectRuntimeProductIDs() map[string]bool {
dynamicMu.RLock() dynamicMu.RLock()
dp := dynamicProducts defer dynamicMu.RUnlock()
dynamicMu.RUnlock()
ids := make(map[string]bool, len(dp)+2) ids := make(map[string]bool, len(dynamicProducts)+2)
ids[defaultPATProductID] = true ids[defaultPATProductID] = true
ids[devappProductID] = true ids[devappProductID] = true
for key := range dp { for key := range dynamicProducts {
ids[key] = true ids[key] = true
} }
return ids return ids
@@ -427,15 +421,14 @@ func AppendDynamicServer(server market.ServerDescriptor) {
} }
func normalizeDirectRuntimeProductID(productID string) string { func normalizeDirectRuntimeProductID(productID string) string {
dynamicMu.RLock()
da := dynamicAliases
dynamicMu.RUnlock()
trimmed := strings.TrimSpace(productID) trimmed := strings.TrimSpace(productID)
if da != nil { dynamicMu.RLock()
if normalizedID, ok := da[trimmed]; ok && normalizedID != "" { if normalizedID, ok := dynamicAliases[trimmed]; ok && normalizedID != "" {
return normalizedID dynamicMu.RUnlock()
} return normalizedID
} }
dynamicMu.RUnlock()
if normalizedID, ok := legacyDirectRuntimeAliases[trimmed]; ok { if normalizedID, ok := legacyDirectRuntimeAliases[trimmed]; ok {
return normalizedID return normalizedID
} }
+6 -7
View File
@@ -62,7 +62,7 @@ func TestDirectRuntimeEndpoint_DevappEnvOverridePreservesQuery(t *testing.T) {
assertEndpoint(t, "devapp", "list_open_dev_apps_by_condition", "https://example.test/server/devapp?key=secret") assertEndpoint(t, "devapp", "list_open_dev_apps_by_condition", "https://example.test/server/devapp?key=secret")
} }
func TestDirectRuntimeEndpoint_DevappDynamicServerWithoutRegistry(t *testing.T) { func TestDirectRuntimeEndpoint_DevappDynamicServerDoesNotOverrideHardcoded(t *testing.T) {
withCleanDynamicRegistry(t) withCleanDynamicRegistry(t)
SetDynamicServers([]market.ServerDescriptor{ SetDynamicServers([]market.ServerDescriptor{
{ {
@@ -74,10 +74,10 @@ func TestDirectRuntimeEndpoint_DevappDynamicServerWithoutRegistry(t *testing.T)
}, },
}) })
assertEndpoint(t, "devapp", "list_open_dev_apps_by_condition", "https://example.test/server/devapp-supplement") assertEndpoint(t, "devapp", "list_open_dev_apps_by_condition", devappEndpoint)
} }
func TestDirectRuntimeEndpoint_DevappEditionSupplementWithoutRegistry(t *testing.T) { func TestDirectRuntimeEndpoint_DevappEditionSupplementDoesNotOverrideHardcoded(t *testing.T) {
withCleanDynamicRegistry(t) withCleanDynamicRegistry(t)
prev := edition.Get() prev := edition.Get()
edition.Override(&edition.Hooks{ edition.Override(&edition.Hooks{
@@ -95,11 +95,10 @@ func TestDirectRuntimeEndpoint_DevappEditionSupplementWithoutRegistry(t *testing
}) })
t.Cleanup(func() { edition.Override(prev) }) t.Cleanup(func() { edition.Override(prev) })
assertEndpoint(t, "devapp", "list_open_dev_apps_by_condition", "https://example.test/server/devapp-edition-supplement?key=secret") assertEndpoint(t, "devapp", "list_open_dev_apps_by_condition", devappEndpoint)
assertEndpoint(t, "app", "list_open_dev_apps_by_condition", "https://example.test/server/devapp-edition-supplement?key=secret")
} }
func TestDirectRuntimeEndpoint_DevappEditionStaticWithoutRegistry(t *testing.T) { func TestDirectRuntimeEndpoint_DevappEditionStaticDoesNotOverrideHardcoded(t *testing.T) {
withCleanDynamicRegistry(t) withCleanDynamicRegistry(t)
prev := edition.Get() prev := edition.Get()
edition.Override(&edition.Hooks{ edition.Override(&edition.Hooks{
@@ -117,7 +116,7 @@ func TestDirectRuntimeEndpoint_DevappEditionStaticWithoutRegistry(t *testing.T)
}) })
t.Cleanup(func() { edition.Override(prev) }) t.Cleanup(func() { edition.Override(prev) })
assertEndpoint(t, "devapp", "list_open_dev_apps_by_condition", "https://example.test/server/devapp-edition-static") assertEndpoint(t, "devapp", "list_open_dev_apps_by_condition", devappEndpoint)
} }
func TestDirectRuntimeEndpoint_DevappEnvOverrideWinsOverEditionSupplement(t *testing.T) { func TestDirectRuntimeEndpoint_DevappEnvOverrideWinsOverEditionSupplement(t *testing.T) {