Files
dingtalk-workspace-cli/internal/app/app_tiny_coverage_test.go
玉澜 fe969dad51 refactor(app): unify dynamic server registration and drop dead command surfaces
- Collapse SetDynamicServers/registerDynamicServer/AppendDynamicServer
  into one registration core; the ServerOverride-skip now applies to all
  paths and AppendDynamicServer keeps its cmd-key no-overwrite guard.
- Delete executor.NewWorkflowInvocation (never constructed, no gate
  accepts the kind) and newLegacyHiddenCommands (always returned nil).
- Route the single-profile branch through the runnerResolveProfile seam,
  matching the multi-profile branch.
- Refresh stale discovery-era comments (no wire strings changed).
2026-08-03 23:30:54 +08:00

283 lines
11 KiB
Go

package app
import (
"context"
"errors"
"io"
"io/fs"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"testing"
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/apiclient"
authpkg "github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/auth"
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/pkg/edition"
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/pkg/mcptypes"
"github.com/spf13/cobra"
)
func TestCrossPlatformCoverageAPIAndTimingRemainingCoverage(t *testing.T) {
oldProvider := newAppTokenProvider
oldClientID, oldClientSecret := apiClientID, apiClientSecret
oldMarshal, oldMkdir := timingMarshalIndent, timingMkdirAll
oldWrite, oldRemove, oldRename := timingWriteFile, timingRemove, timingRename
oldRead, oldHome := timingReadFile, timingUserHomeDir
t.Cleanup(func() {
newAppTokenProvider = oldProvider
apiClientID, apiClientSecret = oldClientID, oldClientSecret
timingMarshalIndent, timingMkdirAll = oldMarshal, oldMkdir
timingWriteFile, timingRemove, timingRename = oldWrite, oldRemove, oldRename
timingReadFile, timingUserHomeDir = oldRead, oldHome
authpkg.SetClientID("")
authpkg.SetClientSecret("")
})
fail := errors.New("failure")
apiClientID = func() string { return "" }
apiClientSecret = func() string { return "" }
if _, err := resolveRawAPIToken(context.Background(), ""); err == nil {
t.Fatal("missing raw API credentials succeeded")
}
apiClientID = func() string { return "<placeholder>" }
apiClientSecret = func() string { return "secret" }
if _, err := resolveRawAPIToken(context.Background(), ""); err == nil {
t.Fatal("placeholder raw API credentials succeeded")
}
apiClientID, apiClientSecret = authpkg.ClientID, authpkg.ClientSecret
authpkg.SetClientID("app-key")
authpkg.SetClientSecret("app-secret")
for _, tc := range []struct {
getter fakeAppTokenGetter
want string
}{
{getter: fakeAppTokenGetter{err: fail}, want: "failure"},
{getter: fakeAppTokenGetter{token: " "}, want: "为空"},
{getter: fakeAppTokenGetter{token: " token "}},
} {
newAppTokenProvider = func(string, string, string) appTokenGetter { return tc.getter }
got, err := resolveRawAPIToken(context.Background(), "")
if tc.want != "" && (err == nil || !containsText(err.Error(), tc.want)) {
t.Fatalf("raw token error = %v, want %q", err, tc.want)
}
if tc.want == "" && (err != nil || got != "token") {
t.Fatalf("raw token = %q, %v", got, err)
}
}
server := httptest.NewServer(http.HandlerFunc(func(http.ResponseWriter, *http.Request) {}))
endpoint := server.URL
server.Close()
apiclient.AllowedHosts["127.0.0.1"] = true
t.Cleanup(func() { delete(apiclient.AllowedHosts, "127.0.0.1") })
cmd := &cobra.Command{Use: "api"}
cmd.SetContext(context.Background())
cmd.SetOut(io.Discard)
cmd.SetErr(io.Discard)
if err := runAPI(cmd, []string{"GET", "/path"}, &GlobalFlags{Token: "token", Timeout: 1}, &apiFlags{baseURL: endpoint}); err == nil {
t.Fatal("closed raw API endpoint succeeded")
}
collector := NewTimingCollector()
collector.Print(io.Discard)
t.Setenv(PerfReportEnv, t.TempDir()+"/report.json")
timingMarshalIndent = func(any, string, string) ([]byte, error) { return nil, fail }
collector.WriteReportIfEnabled("v", "cmd")
timingMarshalIndent = oldMarshal
timingUserHomeDir = func() (string, error) { return "", fail }
t.Setenv(PerfReportEnv, "auto")
collector.WriteReportIfEnabled("v", "cmd")
if defaultPerfReportPath() != "" {
t.Fatal("home-dir failure produced a report path")
}
t.Setenv(PerfReportEnv, t.TempDir()+"/report.json")
timingMkdirAll = func(string, os.FileMode) error { return fail }
collector.WriteReportIfEnabled("v", "cmd")
timingMkdirAll = oldMkdir
timingWriteFile = func(string, []byte, os.FileMode) error { return fail }
removed := false
timingRemove = func(string) error { removed = true; return nil }
collector.WriteReportIfEnabled("v", "cmd")
if !removed {
t.Fatal("failed temporary report was not removed")
}
timingWriteFile = oldWrite
timingRemove = oldRemove
renamed := false
timingRename = func(string, string) error { renamed = true; return fail }
collector.WriteReportIfEnabled("v", "cmd")
if !renamed {
t.Fatal("report rename was not attempted")
}
timingReadFile = func(string) ([]byte, error) { return []byte("{"), nil }
if _, err := LoadLatestReport(); err == nil {
t.Fatal("malformed performance report succeeded")
}
}
func TestCrossPlatformCoverageDirectRuntimeRemainingCoverage(t *testing.T) {
oldEdition := edition.Get()
t.Cleanup(func() {
edition.Override(oldEdition)
SetDynamicServers(nil)
})
configDir := t.TempDir()
t.Setenv("DWS_CONFIG_DIR", configDir)
for _, raw := range []string{
"not a url",
"https://mcp.dingtalk.com/path?q=1#fragment",
"https://pre-mcp.example.test:8443/path/",
"https://mcp.example.test/path/",
} {
if err := os.WriteFile(filepath.Join(configDir, "mcp_url"), []byte(raw), 0o600); err != nil {
t.Fatal(err)
}
if got := defaultPATGatewayBaseURL(); got == "" {
t.Fatalf("gateway for %q is blank", raw)
}
}
endpoints := map[string]string{}
products := map[string]bool{}
aliases := map[string]string{}
tools := map[string]string{}
registerDynamicServer(mcptypes.ServerDescriptor{CLI: mcptypes.CLIOverlay{Skip: true}}, endpoints, products, aliases, tools, false)
registerDynamicServer(mcptypes.ServerDescriptor{
Endpoint: "https://server.test",
CLI: mcptypes.CLIOverlay{
ID: "id", Command: "command", Aliases: []string{"alias", " "},
Tools: []mcptypes.CLITool{{Name: "tool"}, {Name: " "}},
ToolOverrides: map[string]mcptypes.CLIToolOverride{"override": {}, " ": {}},
},
}, endpoints, products, aliases, tools, false)
if endpoints["command"] == "" || aliases["alias"] != "id" || tools["override"] == "" {
t.Fatalf("registered dynamic server = %#v %#v %#v", endpoints, aliases, tools)
}
SetDynamicServers(nil)
dynamicMu.Lock()
dynamicEndpoints = map[string]string{}
dynamicProducts = map[string]bool{}
dynamicAliases = map[string]string{}
dynamicToolEndpoints = map[string]string{}
dynamicMu.Unlock()
if got, ok := directRuntimeEndpoint(defaultPATProductID, ""); !ok || got == "" {
t.Fatal("cold-start PAT fallback did not resolve")
}
SetDynamicServers(nil)
if _, ok := directRuntimeEndpoint(" ", " "); ok {
t.Fatal("blank runtime endpoint resolved")
}
t.Setenv("DINGTALK_CUSTOM_MCP_URL", "https://override.test")
if got, ok := directRuntimeEndpoint("custom", ""); !ok || got != "https://override.test" {
t.Fatalf("environment runtime endpoint = %q, %v", got, ok)
}
if got, ok := directRuntimeEndpoint(devappProductID, ""); !ok || got == "" {
t.Fatal("devapp fallback did not resolve")
}
if got, ok := directRuntimeEndpoint(defaultPATProductID, ""); !ok || got == "" {
t.Fatal("PAT fallback did not resolve")
}
edition.Override(&edition.Hooks{
StaticServers: func() []edition.ServerInfo { return []edition.ServerInfo{{ID: "other", Endpoint: ""}} },
SupplementServers: func() []edition.ServerInfo {
return []edition.ServerInfo{{ID: "other", Endpoint: "https://other.test", Prefixes: []string{" ", "wanted"}}}
},
})
if got, ok := directRuntimeEndpoint("wanted", ""); !ok || got != "https://other.test" {
t.Fatalf("edition runtime endpoint = %q, %v", got, ok)
}
dynamicMu.Lock()
dynamicEndpoints, dynamicProducts, dynamicAliases, dynamicToolEndpoints = nil, nil, nil, nil
dynamicMu.Unlock()
AppendDynamicServer(mcptypes.ServerDescriptor{
Endpoint: "https://append.test",
CLI: mcptypes.CLIOverlay{
ID: "append", Command: "append-command", Aliases: []string{"append-alias"},
Tools: []mcptypes.CLITool{{Name: "append-tool"}},
ToolOverrides: map[string]mcptypes.CLIToolOverride{
"append-override": {}, "skip": {ServerOverride: "other"}, " ": {},
},
},
})
if got, ok := directRuntimeEndpoint("", "append-override"); !ok || got != "https://append.test" {
t.Fatalf("append override endpoint = %q, %v", got, ok)
}
}
func containsText(value, substring string) bool {
for i := 0; i+len(substring) <= len(value); i++ {
if value[i:i+len(substring)] == substring {
return true
}
}
return false
}
func TestCrossPlatformCoverageEmbeddedSkillAndTinyCommandsRemainingCoverage(t *testing.T) {
oldStat, oldTemp, oldRemove := embeddedSkillStat, embeddedSkillMkdirTemp, embeddedSkillRemoveAll
oldWalk, oldRead := embeddedSkillWalkDir, embeddedSkillReadFile
oldMkdir, oldWrite := embeddedSkillMkdirAll, embeddedSkillWriteFile
t.Cleanup(func() {
embeddedSkillStat, embeddedSkillMkdirTemp, embeddedSkillRemoveAll = oldStat, oldTemp, oldRemove
embeddedSkillWalkDir, embeddedSkillReadFile = oldWalk, oldRead
embeddedSkillMkdirAll, embeddedSkillWriteFile = oldMkdir, oldWrite
})
fail := errors.New("failure")
embeddedSkillStat = func(string) (os.FileInfo, error) { return nil, nil }
embeddedSkillMkdirTemp = func(string, string) (string, error) { return "", fail }
if _, _, err := materializeEmbeddedSkillSource("codex"); !errors.Is(err, fail) {
t.Fatalf("embedded mkdir error = %v", err)
}
embeddedSkillMkdirTemp = func(string, string) (string, error) { return t.TempDir(), nil }
removed := false
embeddedSkillRemoveAll = func(string) error { removed = true; return nil }
embeddedSkillWalkDir = func(_ string, fn fs.WalkDirFunc) error {
return fn("entry", nil, fail)
}
if _, _, err := materializeEmbeddedSkillSource("codex"); !errors.Is(err, fail) || !removed {
t.Fatalf("embedded walk error = %v, removed=%v", err, removed)
}
embeddedSkillWalkDir = func(_ string, fn fs.WalkDirFunc) error {
return fn("skills/codex/file", fakeSkillDirEntry{}, nil)
}
embeddedSkillReadFile = func(string) ([]byte, error) { return nil, fail }
if _, _, err := materializeEmbeddedSkillSource("codex"); !errors.Is(err, fail) {
t.Fatalf("embedded read error = %v", err)
}
embeddedSkillReadFile = func(string) ([]byte, error) { return []byte("skill"), nil }
embeddedSkillMkdirAll = func(string, os.FileMode) error { return fail }
if _, _, err := materializeEmbeddedSkillSource("codex"); !errors.Is(err, fail) {
t.Fatalf("embedded nested mkdir error = %v", err)
}
embeddedSkillWalkDir = func(_ string, fn fs.WalkDirFunc) error {
return fn("skills/codex/dir", fakeSkillDirEntry{dir: true}, nil)
}
if _, _, err := materializeEmbeddedSkillSource("codex"); !errors.Is(err, fail) {
t.Fatalf("embedded directory mkdir error = %v", err)
}
embeddedSkillWalkDir = func(_ string, fn fs.WalkDirFunc) error {
return fn("skills/codex/file", fakeSkillDirEntry{}, nil)
}
embeddedSkillMkdirAll = func(string, os.FileMode) error { return nil }
embeddedSkillWriteFile = func(string, []byte, os.FileMode) error { return fail }
if _, _, err := materializeEmbeddedSkillSource("codex"); !errors.Is(err, fail) {
t.Fatalf("embedded write error = %v", err)
}
merged := mergeTopLevelCommands([]*cobra.Command{nil, {}})
if len(merged) != 0 {
t.Fatalf("empty legacy commands = %#v", merged)
}
root := &cobra.Command{Use: "root"}
completion := newCompletionCommand(root)
if err := completion.RunE(completion, []string{"other"}); err != nil {
t.Fatal(err)
}
catalog := newCatalogCommand()
catalog.SetOut(io.Discard)
if err := catalog.RunE(catalog, nil); err != nil {
t.Fatal(err)
}
}