The devapp endpoint was hardcoded to the pre gateway, so robot create/list hit the pre environment for everyone. Derive it from the configured MCP gateway base URL instead: production by default, pre when ~/.dws/mcp_url points at the pre gateway. Also bump quickstart doc to v1.0.51-dws-devapp and add a FAQ entry for the production-side developer-identity check.
199 lines
5.8 KiB
Go
199 lines
5.8 KiB
Go
package app
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/market"
|
|
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/pkg/edition"
|
|
)
|
|
|
|
func TestDefaultPATServerDescriptorUsesBehaviorAuthorizationName(t *testing.T) {
|
|
server := defaultPATServerDescriptor()
|
|
if server.CLI.ID != "pat" {
|
|
t.Fatalf("default PAT server id = %q, want pat", server.CLI.ID)
|
|
}
|
|
if server.DisplayName != "行为授权" {
|
|
t.Fatalf("default PAT server display name = %q, want 行为授权", server.DisplayName)
|
|
}
|
|
if server.Endpoint != defaultPATMCPEndpoint() {
|
|
t.Fatalf("default PAT server endpoint = %q, want %q", server.Endpoint, defaultPATMCPEndpoint())
|
|
}
|
|
}
|
|
|
|
func TestDirectRuntimeProductIDsIncludesDefaultPAT(t *testing.T) {
|
|
dynamicMu.Lock()
|
|
previousProducts := dynamicProducts
|
|
dynamicProducts = nil
|
|
dynamicMu.Unlock()
|
|
t.Cleanup(func() {
|
|
dynamicMu.Lock()
|
|
dynamicProducts = previousProducts
|
|
dynamicMu.Unlock()
|
|
})
|
|
|
|
ids := DirectRuntimeProductIDs()
|
|
if !ids["pat"] {
|
|
t.Fatalf("DirectRuntimeProductIDs() missing default pat product: %#v", ids)
|
|
}
|
|
}
|
|
|
|
func TestDirectRuntimeProductIDsIncludesDevappHelper(t *testing.T) {
|
|
withCleanDynamicRegistry(t)
|
|
|
|
ids := DirectRuntimeProductIDs()
|
|
if !ids["devapp"] {
|
|
t.Fatalf("DirectRuntimeProductIDs() missing devapp helper product: %#v", ids)
|
|
}
|
|
}
|
|
|
|
func TestDirectRuntimeEndpoint_DevappEnvOverrideWithoutRegistry(t *testing.T) {
|
|
withCleanDynamicRegistry(t)
|
|
t.Setenv("DINGTALK_DEVAPP_MCP_URL", "https://example.test/server/devapp")
|
|
|
|
assertEndpoint(t, "devapp", "list_open_dev_apps_by_condition", "https://example.test/server/devapp")
|
|
}
|
|
|
|
func TestDirectRuntimeEndpoint_DevappEnvOverridePreservesQuery(t *testing.T) {
|
|
withCleanDynamicRegistry(t)
|
|
t.Setenv("DINGTALK_DEVAPP_MCP_URL", "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_DevappDynamicServerDoesNotOverrideHardcoded(t *testing.T) {
|
|
withCleanDynamicRegistry(t)
|
|
SetDynamicServers([]market.ServerDescriptor{
|
|
{
|
|
Endpoint: "https://example.test/server/devapp-supplement",
|
|
CLI: market.CLIOverlay{
|
|
ID: "devapp",
|
|
Command: "devapp",
|
|
},
|
|
},
|
|
})
|
|
|
|
assertEndpoint(t, "devapp", "list_open_dev_apps_by_condition", devappMCPEndpoint())
|
|
}
|
|
|
|
func TestDirectRuntimeEndpoint_DevappEditionSupplementDoesNotOverrideHardcoded(t *testing.T) {
|
|
withCleanDynamicRegistry(t)
|
|
prev := edition.Get()
|
|
edition.Override(&edition.Hooks{
|
|
Name: "wukong",
|
|
SupplementServers: func() []edition.ServerInfo {
|
|
return []edition.ServerInfo{
|
|
{
|
|
ID: "devapp",
|
|
Name: "开放平台应用管理",
|
|
Endpoint: "https://example.test/server/devapp-edition-supplement?key=secret",
|
|
Prefixes: []string{"devapp", "app"},
|
|
},
|
|
}
|
|
},
|
|
})
|
|
t.Cleanup(func() { edition.Override(prev) })
|
|
|
|
assertEndpoint(t, "devapp", "list_open_dev_apps_by_condition", devappMCPEndpoint())
|
|
}
|
|
|
|
func TestDirectRuntimeEndpoint_DevappEditionStaticDoesNotOverrideHardcoded(t *testing.T) {
|
|
withCleanDynamicRegistry(t)
|
|
prev := edition.Get()
|
|
edition.Override(&edition.Hooks{
|
|
Name: "wukong",
|
|
StaticServers: func() []edition.ServerInfo {
|
|
return []edition.ServerInfo{
|
|
{
|
|
ID: "devapp",
|
|
Name: "开放平台应用管理",
|
|
Endpoint: "https://example.test/server/devapp-edition-static",
|
|
Prefixes: []string{"devapp", "app"},
|
|
},
|
|
}
|
|
},
|
|
})
|
|
t.Cleanup(func() { edition.Override(prev) })
|
|
|
|
assertEndpoint(t, "devapp", "list_open_dev_apps_by_condition", devappMCPEndpoint())
|
|
}
|
|
|
|
func TestDirectRuntimeEndpoint_DevappEnvOverrideWinsOverEditionSupplement(t *testing.T) {
|
|
withCleanDynamicRegistry(t)
|
|
t.Setenv("DINGTALK_DEVAPP_MCP_URL", "https://example.test/server/devapp-env")
|
|
prev := edition.Get()
|
|
edition.Override(&edition.Hooks{
|
|
Name: "wukong",
|
|
SupplementServers: func() []edition.ServerInfo {
|
|
return []edition.ServerInfo{
|
|
{
|
|
ID: "devapp",
|
|
Name: "开放平台应用管理",
|
|
Endpoint: "https://example.test/server/devapp-edition-supplement",
|
|
},
|
|
}
|
|
},
|
|
})
|
|
t.Cleanup(func() { edition.Override(prev) })
|
|
|
|
assertEndpoint(t, "devapp", "list_open_dev_apps_by_condition", "https://example.test/server/devapp-env")
|
|
}
|
|
|
|
func TestDirectRuntimeEndpoint_DefaultPATFallbackWhenRegistryMissing(t *testing.T) {
|
|
withCleanDynamicRegistry(t)
|
|
assertEndpoint(t, "pat", "", defaultPATMCPEndpoint())
|
|
}
|
|
|
|
func TestDirectRuntimeEndpoint_DefaultPATFallbackUsesConfiguredMCPBaseURL(t *testing.T) {
|
|
withCleanDynamicRegistry(t)
|
|
|
|
tmpDir := t.TempDir()
|
|
if err := os.WriteFile(filepath.Join(tmpDir, "mcp_url"), []byte("http://127.0.0.1:54321/base"), 0o600); err != nil {
|
|
t.Fatalf("WriteFile(mcp_url) error = %v", err)
|
|
}
|
|
t.Setenv("DWS_CONFIG_DIR", tmpDir)
|
|
|
|
assertEndpoint(t, "pat", "", "http://127.0.0.1:54321/base/server/"+defaultPATServerID)
|
|
}
|
|
|
|
func TestDirectRuntimeEndpoint_PATDiscoveryOverrideWinsOverBuiltInFallback(t *testing.T) {
|
|
withCleanDynamicRegistry(t)
|
|
customEndpoint := "https://example.com/server/custom-pat"
|
|
SetDynamicServers([]market.ServerDescriptor{
|
|
{
|
|
Endpoint: customEndpoint,
|
|
CLI: market.CLIOverlay{
|
|
ID: "pat",
|
|
Command: "pat",
|
|
},
|
|
},
|
|
})
|
|
assertEndpoint(t, "pat", "", customEndpoint)
|
|
}
|
|
|
|
func TestNormalizeDirectRuntimeProductIDPreservesLegacyHiddenVendorRouting(t *testing.T) {
|
|
dynamicMu.Lock()
|
|
previousAliases := dynamicAliases
|
|
dynamicAliases = nil
|
|
dynamicMu.Unlock()
|
|
t.Cleanup(func() {
|
|
dynamicMu.Lock()
|
|
dynamicAliases = previousAliases
|
|
dynamicMu.Unlock()
|
|
})
|
|
|
|
cases := map[string]string{
|
|
"tb": "teambition",
|
|
"dingtalk-discovery": "discovery",
|
|
"dingtalk-oa-plus": "oa",
|
|
"dingtalk-ai-sincere-hire": "ai-sincere-hire",
|
|
}
|
|
|
|
for input, want := range cases {
|
|
if got := normalizeDirectRuntimeProductID(input); got != want {
|
|
t.Fatalf("normalizeDirectRuntimeProductID(%q) = %q, want %q", input, got, want)
|
|
}
|
|
}
|
|
}
|