- Add testseam.Protect for save-and-restore seams with no up-front stub value (e.g. os.Args mutated by the code under test). - Migrate all 35 remaining manual prev/assign/t.Cleanup-restore trios to testseam.Swap/Protect across app, auth, cli, event, helpers, output, pipeline, and shortcut tests; restores can no longer be forgotten. - check-schema-catalog.sh: fail closed when a manual seam restore reappears in any *_test.go (internal/testseam exempt). Seam injection is now a mechanism, not a convention.
604 lines
23 KiB
Go
604 lines
23 KiB
Go
// Copyright 2026 Alibaba Group
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
package helpers
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/testseam"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
type markdownCIFailingReader struct{}
|
|
|
|
func (markdownCIFailingReader) Read([]byte) (int, error) {
|
|
return 0, errors.New("forced read failure")
|
|
}
|
|
|
|
func installMarkdownCITempFileDisappearance(t *testing.T) {
|
|
t.Helper()
|
|
original := markdownUploadStat
|
|
markdownUploadStat = func(path string) (os.FileInfo, error) {
|
|
if err := os.Remove(path); err != nil {
|
|
return nil, err
|
|
}
|
|
return os.Stat(path)
|
|
}
|
|
t.Cleanup(func() { markdownUploadStat = original })
|
|
}
|
|
|
|
func TestCrossPlatformCoverageMarkdownUploadStatFailures(t *testing.T) {
|
|
t.Run("create", func(t *testing.T) {
|
|
installMarkdownDriveDeps(t, &markdownDriveCaller{format: "json"})
|
|
installMarkdownCITempFileDisappearance(t)
|
|
err := executeMarkdownDriveCommand(t, newMarkdownCommand(), nil,
|
|
"markdown", "create", "--name", "a.md", "--content", "body")
|
|
if err == nil || !strings.Contains(err.Error(), "读取上传文件失败") {
|
|
t.Fatalf("error = %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("overwrite", func(t *testing.T) {
|
|
installMarkdownDriveDeps(t, &markdownDriveCaller{format: "json"})
|
|
installMarkdownCITempFileDisappearance(t)
|
|
err := executeMarkdownDriveCommand(t, newMarkdownCommand(), nil,
|
|
"markdown", "overwrite", "--node", "node-1", "--space-id", "space-1",
|
|
"--name", "a.md", "--content", "body", "--yes")
|
|
if err == nil || !strings.Contains(err.Error(), "读取上传文件失败") {
|
|
t.Fatalf("error = %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("patch", func(t *testing.T) {
|
|
caller := &markdownDriveCaller{
|
|
format: "json",
|
|
steps: []markdownDriveStep{
|
|
{text: `{"downloadUrl":"https://download.test/current.md","fileName":"current.md"}`},
|
|
{text: `{"fileName":"current.md"}`},
|
|
},
|
|
}
|
|
installMarkdownDriveDeps(t, caller)
|
|
installMarkdownHTTPGet(t, "old")
|
|
installMarkdownCITempFileDisappearance(t)
|
|
err := executeMarkdownDriveCommand(t, newMarkdownCommand(), nil,
|
|
"markdown", "patch", "--node", "node-1", "--space-id", "space-1",
|
|
"--pattern", "old", "--content", "new", "--yes")
|
|
if err == nil || !strings.Contains(err.Error(), "读取临时文件失败") {
|
|
t.Fatalf("error = %v", err)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestMarkdownCICoverageFetchAndOutputPaths(t *testing.T) {
|
|
t.Run("missing node reaches runtime validation", func(t *testing.T) {
|
|
installMarkdownDriveDeps(t, &markdownDriveCaller{format: "json"})
|
|
if err := runMarkdownFetch(newMarkdownFetchCmd(), nil); err == nil || !strings.Contains(err.Error(), "--node") {
|
|
t.Fatalf("error = %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("output resolution failure propagates", func(t *testing.T) {
|
|
caller := &markdownDriveCaller{
|
|
format: "json",
|
|
steps: []markdownDriveStep{{text: `{"downloadUrl":"https://download.test/current.md","fileName":"current.md"}`}},
|
|
}
|
|
installMarkdownDriveDeps(t, caller)
|
|
installMarkdownHTTPGet(t, "body")
|
|
parentFile := writeMarkdownDriveFixture(t, "parent", "not a directory")
|
|
err := executeMarkdownDriveCommand(t, newMarkdownCommand(), nil,
|
|
"markdown", "fetch", "--node", "node-1", "--space-id", "space-1",
|
|
"--output", filepath.Join(parentFile, "child.md"))
|
|
if err == nil || !strings.Contains(err.Error(), "检查输出路径") {
|
|
t.Fatalf("error = %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("write failure propagates", func(t *testing.T) {
|
|
caller := &markdownDriveCaller{
|
|
format: "json",
|
|
steps: []markdownDriveStep{{text: `{"downloadUrl":"https://download.test/current.md","fileName":"current.md"}`}},
|
|
}
|
|
installMarkdownDriveDeps(t, caller)
|
|
installMarkdownHTTPGet(t, "body")
|
|
output := filepath.Join(t.TempDir(), "missing", "child.md")
|
|
err := executeMarkdownDriveCommand(t, newMarkdownCommand(), nil,
|
|
"markdown", "fetch", "--node", "node-1", "--space-id", "space-1", "--output", output)
|
|
if err == nil || !strings.Contains(err.Error(), "保存到") {
|
|
t.Fatalf("error = %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("raw saved output reports destination", func(t *testing.T) {
|
|
caller := &markdownDriveCaller{
|
|
format: "raw",
|
|
steps: []markdownDriveStep{{text: `{"downloadUrl":"https://download.test/current.md","fileName":"current.md"}`}},
|
|
}
|
|
_, stderr := installMarkdownDriveDeps(t, caller)
|
|
installMarkdownHTTPGet(t, "body")
|
|
output := filepath.Join(t.TempDir(), "saved.md")
|
|
if err := executeMarkdownDriveCommand(t, newMarkdownCommand(), nil,
|
|
"markdown", "fetch", "--node", "node-1", "--space-id", "space-1", "--output", output); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !strings.Contains(stderr.String(), "已保存到 "+output) {
|
|
t.Fatalf("stderr = %q", stderr.String())
|
|
}
|
|
})
|
|
|
|
t.Run("safe path fallbacks and lstat failure", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
got, err := resolveMarkdownOutputPath(dir, ".")
|
|
if err != nil || got != filepath.Join(dir, "download.md") {
|
|
t.Fatalf("path = %q, error = %v", got, err)
|
|
}
|
|
tooLong := strings.Repeat("x", 300) + ".md"
|
|
if _, err := resolveMarkdownOutputPath(dir, tooLong); err == nil || !strings.Contains(err.Error(), "检查输出文件") {
|
|
t.Fatalf("error = %v", err)
|
|
}
|
|
if got := resolveDownloadFilename(`{`, "https://download.test/fallback.md?token=redacted"); got != "fallback.md" {
|
|
t.Fatalf("fallback name = %q", got)
|
|
}
|
|
})
|
|
|
|
t.Run("directory traversal defense rejects unsanitized names", func(t *testing.T) {
|
|
if _, err := resolveMarkdownDirectoryOutputPath(t.TempDir(), "../escape.md"); err == nil ||
|
|
!strings.Contains(err.Error(), "越过输出目录") {
|
|
t.Fatalf("error = %v", err)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestMarkdownCICoverageCreateEdges(t *testing.T) {
|
|
t.Run("directory source", func(t *testing.T) {
|
|
installMarkdownDriveDeps(t, &markdownDriveCaller{format: "json"})
|
|
err := executeMarkdownDriveCommand(t, newMarkdownCommand(), nil,
|
|
"markdown", "create", "--file", t.TempDir())
|
|
if err == nil || !strings.Contains(err.Error(), "是目录而非文件") {
|
|
t.Fatalf("error = %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("content source failure", func(t *testing.T) {
|
|
installMarkdownDriveDeps(t, &markdownDriveCaller{format: "json"})
|
|
err := executeMarkdownDriveCommand(t, newMarkdownCommand(), nil,
|
|
"markdown", "create", "--name", "a.md", "--content", "@"+filepath.Join(t.TempDir(), "missing"))
|
|
if err == nil || !strings.Contains(err.Error(), "从文件") {
|
|
t.Fatalf("error = %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("temporary directory failure", func(t *testing.T) {
|
|
installMarkdownDriveDeps(t, &markdownDriveCaller{format: "json"})
|
|
t.Setenv("TMPDIR", filepath.Join(t.TempDir(), "missing"))
|
|
err := executeMarkdownDriveCommand(t, newMarkdownCommand(), nil,
|
|
"markdown", "create", "--name", "a.md", "--content", "body")
|
|
if err == nil || !strings.Contains(err.Error(), "创建临时目录失败") {
|
|
t.Fatalf("error = %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("temporary file write failure", func(t *testing.T) {
|
|
installMarkdownDriveDeps(t, &markdownDriveCaller{format: "json"})
|
|
name := strings.Repeat("x", 300) + ".md"
|
|
err := executeMarkdownDriveCommand(t, newMarkdownCommand(), nil,
|
|
"markdown", "create", "--name", name, "--content", "body")
|
|
if err == nil || !strings.Contains(err.Error(), "写入临时文件失败") {
|
|
t.Fatalf("error = %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("temporary file disappears before stat", func(t *testing.T) {
|
|
installMarkdownDriveDeps(t, &markdownDriveCaller{format: "json"})
|
|
installMarkdownCITempFileDisappearance(t)
|
|
err := executeMarkdownDriveCommand(t, newMarkdownCommand(), nil,
|
|
"markdown", "create", "--name", "a.md", "--content", "body")
|
|
if err == nil || !strings.Contains(err.Error(), "读取上传文件失败") {
|
|
t.Fatalf("error = %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("caller dry run after stat", func(t *testing.T) {
|
|
caller := &markdownDriveCaller{format: "json", dryRun: true}
|
|
stdout, _ := installMarkdownDriveDeps(t, caller)
|
|
path := writeMarkdownDriveFixture(t, "a.md", "body")
|
|
if err := executeMarkdownDriveCommand(t, newMarkdownCommand(), nil,
|
|
"markdown", "create", "--file", path, "--space-id", "space-1"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var payload map[string]any
|
|
if err := json.Unmarshal(stdout.Bytes(), &payload); err != nil || payload["operation"] != "create" {
|
|
t.Fatalf("payload = %#v, error = %v, output = %q", payload, err, stdout.String())
|
|
}
|
|
})
|
|
|
|
t.Run("stdin read failure", func(t *testing.T) {
|
|
cmd := &cobra.Command{Use: "source"}
|
|
cmd.SetIn(markdownCIFailingReader{})
|
|
if _, err := resolveMarkdownContentSource(cmd, "-"); err == nil || !strings.Contains(err.Error(), "stdin") {
|
|
t.Fatalf("error = %v", err)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestMarkdownCICoverageOverwriteEdges(t *testing.T) {
|
|
t.Run("content source failure", func(t *testing.T) {
|
|
installMarkdownDriveDeps(t, &markdownDriveCaller{format: "json"})
|
|
err := executeMarkdownDriveCommand(t, newMarkdownCommand(), nil,
|
|
"markdown", "overwrite", "--node", "node-1", "--space-id", "space-1",
|
|
"--name", "a.md", "--content", "@"+filepath.Join(t.TempDir(), "missing"), "--yes")
|
|
if err == nil || !strings.Contains(err.Error(), "从文件") {
|
|
t.Fatalf("error = %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("content mode remote name failure", func(t *testing.T) {
|
|
boom := errors.New("metadata failed")
|
|
caller := &markdownDriveCaller{format: "json", steps: []markdownDriveStep{{err: boom}}}
|
|
installMarkdownDriveDeps(t, caller)
|
|
err := executeMarkdownDriveCommand(t, newMarkdownCommand(), nil,
|
|
"markdown", "overwrite", "--node", "node-1", "--space-id", "space-1", "--content", "body", "--yes")
|
|
if err == nil || !strings.Contains(err.Error(), "自动获取文件名失败") {
|
|
t.Fatalf("error = %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("temporary directory failure", func(t *testing.T) {
|
|
installMarkdownDriveDeps(t, &markdownDriveCaller{format: "json"})
|
|
t.Setenv("TMPDIR", filepath.Join(t.TempDir(), "missing"))
|
|
err := executeMarkdownDriveCommand(t, newMarkdownCommand(), nil,
|
|
"markdown", "overwrite", "--node", "node-1", "--space-id", "space-1",
|
|
"--name", "a.md", "--content", "body", "--yes")
|
|
if err == nil || !strings.Contains(err.Error(), "创建临时目录失败") {
|
|
t.Fatalf("error = %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("temporary file write failure", func(t *testing.T) {
|
|
installMarkdownDriveDeps(t, &markdownDriveCaller{format: "json"})
|
|
name := strings.Repeat("x", 300) + ".md"
|
|
err := executeMarkdownDriveCommand(t, newMarkdownCommand(), nil,
|
|
"markdown", "overwrite", "--node", "node-1", "--space-id", "space-1",
|
|
"--name", name, "--content", "body", "--yes")
|
|
if err == nil || !strings.Contains(err.Error(), "写入临时文件失败") {
|
|
t.Fatalf("error = %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("temporary file disappears before stat", func(t *testing.T) {
|
|
installMarkdownDriveDeps(t, &markdownDriveCaller{format: "json"})
|
|
installMarkdownCITempFileDisappearance(t)
|
|
err := executeMarkdownDriveCommand(t, newMarkdownCommand(), nil,
|
|
"markdown", "overwrite", "--node", "node-1", "--space-id", "space-1",
|
|
"--name", "a.md", "--content", "body", "--yes")
|
|
if err == nil || !strings.Contains(err.Error(), "读取上传文件失败") {
|
|
t.Fatalf("error = %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("file mode remote name failure", func(t *testing.T) {
|
|
boom := errors.New("metadata failed")
|
|
caller := &markdownDriveCaller{format: "json", steps: []markdownDriveStep{{err: boom}}}
|
|
installMarkdownDriveDeps(t, caller)
|
|
path := writeMarkdownDriveFixture(t, "source.md", "body")
|
|
err := executeMarkdownDriveCommand(t, newMarkdownCommand(), nil,
|
|
"markdown", "overwrite", "--node", "node-1", "--space-id", "space-1", "--file", path, "--yes")
|
|
if err == nil || !strings.Contains(err.Error(), "自动获取文件名失败") {
|
|
t.Fatalf("error = %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("local preview read failure", func(t *testing.T) {
|
|
installMarkdownDriveDeps(t, &markdownDriveCaller{format: "json"})
|
|
path := writeMarkdownDriveFixture(t, "source.md", "body")
|
|
if err := os.Chmod(path, 0); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Cleanup(func() { _ = os.Chmod(path, 0o600) })
|
|
err := executeMarkdownDriveCommand(t, newMarkdownCommand(), nil,
|
|
"markdown", "overwrite", "--node", "node-1", "--space-id", "space-1",
|
|
"--name", "source.md", "--file", path, "--dry-run")
|
|
if err == nil || !strings.Contains(err.Error(), "读取新内容失败") {
|
|
t.Fatalf("error = %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("confirmation cancellation", func(t *testing.T) {
|
|
installMarkdownDriveDeps(t, &markdownDriveCaller{format: "raw"})
|
|
path := writeMarkdownDriveFixture(t, "source.md", "body")
|
|
err := executeMarkdownDriveCommand(t, newMarkdownCommand(), strings.NewReader("no\n"),
|
|
"markdown", "overwrite", "--node", "node-1", "--space-id", "space-1",
|
|
"--name", "source.md", "--file", path)
|
|
if err == nil || !strings.Contains(err.Error(), "用户取消了操作") {
|
|
t.Fatalf("error = %v, want 用户取消了操作", err)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestMarkdownCICoveragePatchEdges(t *testing.T) {
|
|
t.Run("global caller dry run", func(t *testing.T) {
|
|
caller := &markdownDriveCaller{format: "json", dryRun: true}
|
|
stdout, _ := installMarkdownDriveDeps(t, caller)
|
|
if err := executeMarkdownDriveCommand(t, newMarkdownCommand(), nil,
|
|
"markdown", "patch", "--node", "node-1", "--pattern", "old", "--content", "new"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var payload map[string]any
|
|
if err := json.Unmarshal(stdout.Bytes(), &payload); err != nil || payload["operation"] != "patch" {
|
|
t.Fatalf("payload = %#v, error = %v", payload, err)
|
|
}
|
|
})
|
|
|
|
t.Run("raw zero match", func(t *testing.T) {
|
|
caller := &markdownDriveCaller{
|
|
format: "raw",
|
|
steps: []markdownDriveStep{{text: `{"downloadUrl":"https://download.test/current.md","fileName":"current.md"}`}},
|
|
}
|
|
stdout, _ := installMarkdownDriveDeps(t, caller)
|
|
installMarkdownHTTPGet(t, "alpha beta")
|
|
if err := executeMarkdownDriveCommand(t, newMarkdownCommand(), nil,
|
|
"markdown", "patch", "--node", "node-1", "--space-id", "space-1",
|
|
"--pattern", "missing", "--content", "new", "--yes"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !strings.Contains(stdout.String(), "未找到匹配内容") || !strings.Contains(stdout.String(), "匹配数") {
|
|
t.Fatalf("stdout = %q", stdout.String())
|
|
}
|
|
})
|
|
|
|
t.Run("empty replacement cannot clear the whole file", func(t *testing.T) {
|
|
caller := &markdownDriveCaller{
|
|
format: "json",
|
|
steps: []markdownDriveStep{{text: `{"downloadUrl":"https://download.test/current.md","fileName":"current.md"}`}},
|
|
}
|
|
installMarkdownDriveDeps(t, caller)
|
|
installMarkdownHTTPGet(t, "entire file")
|
|
err := executeMarkdownDriveCommand(t, newMarkdownCommand(), nil,
|
|
"markdown", "patch", "--node", "node-1", "--space-id", "space-1",
|
|
"--pattern", "entire file", "--content", "", "--yes")
|
|
if err == nil || !strings.Contains(err.Error(), "替换后内容为空") {
|
|
t.Fatalf("error = %v", err)
|
|
}
|
|
if len(caller.calls) != 1 {
|
|
t.Fatalf("empty-result guard made write calls: %#v", caller.calls)
|
|
}
|
|
})
|
|
|
|
t.Run("remote name failure", func(t *testing.T) {
|
|
boom := errors.New("metadata failed")
|
|
caller := &markdownDriveCaller{
|
|
format: "json",
|
|
steps: []markdownDriveStep{
|
|
{text: `{"downloadUrl":"https://download.test/current.md","fileName":"current.md"}`},
|
|
{err: boom},
|
|
},
|
|
}
|
|
installMarkdownDriveDeps(t, caller)
|
|
installMarkdownHTTPGet(t, "old value")
|
|
err := executeMarkdownDriveCommand(t, newMarkdownCommand(), nil,
|
|
"markdown", "patch", "--node", "node-1", "--space-id", "space-1",
|
|
"--pattern", "old", "--content", "new", "--yes")
|
|
if err == nil || !strings.Contains(err.Error(), "自动获取文件名失败") {
|
|
t.Fatalf("error = %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("temporary directory failure", func(t *testing.T) {
|
|
caller := &markdownDriveCaller{
|
|
format: "json",
|
|
steps: []markdownDriveStep{
|
|
{text: `{"downloadUrl":"https://download.test/current.md","fileName":"current.md"}`},
|
|
{text: `{"fileName":"current.md"}`},
|
|
},
|
|
}
|
|
installMarkdownDriveDeps(t, caller)
|
|
missingTemp := filepath.Join(t.TempDir(), "missing")
|
|
previousTemp, hadPreviousTemp := os.LookupEnv("TMPDIR")
|
|
t.Cleanup(func() {
|
|
if hadPreviousTemp {
|
|
_ = os.Setenv("TMPDIR", previousTemp)
|
|
} else {
|
|
_ = os.Unsetenv("TMPDIR")
|
|
}
|
|
})
|
|
httpGetFile = func(_ context.Context, _ string, _ map[string]string, destPath string) error {
|
|
if err := os.WriteFile(destPath, []byte("old value"), 0o600); err != nil {
|
|
return err
|
|
}
|
|
return os.Setenv("TMPDIR", missingTemp)
|
|
}
|
|
err := executeMarkdownDriveCommand(t, newMarkdownCommand(), nil,
|
|
"markdown", "patch", "--node", "node-1", "--space-id", "space-1",
|
|
"--pattern", "old", "--content", "new", "--yes")
|
|
if err == nil || !strings.Contains(err.Error(), "创建临时目录失败") {
|
|
t.Fatalf("error = %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("temporary file write failure", func(t *testing.T) {
|
|
longName := strings.Repeat("x", 300) + ".md"
|
|
caller := &markdownDriveCaller{
|
|
format: "json",
|
|
steps: []markdownDriveStep{
|
|
{text: `{"downloadUrl":"https://download.test/current.md","fileName":"current.md"}`},
|
|
{text: fmt.Sprintf(`{"fileName":%q}`, longName)},
|
|
},
|
|
}
|
|
installMarkdownDriveDeps(t, caller)
|
|
installMarkdownHTTPGet(t, "old value")
|
|
err := executeMarkdownDriveCommand(t, newMarkdownCommand(), nil,
|
|
"markdown", "patch", "--node", "node-1", "--space-id", "space-1",
|
|
"--pattern", "old", "--content", "new", "--yes")
|
|
if err == nil || !strings.Contains(err.Error(), "写入临时文件失败") {
|
|
t.Fatalf("error = %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("temporary file disappears before stat", func(t *testing.T) {
|
|
caller := &markdownDriveCaller{
|
|
format: "json",
|
|
steps: []markdownDriveStep{
|
|
{text: `{"downloadUrl":"https://download.test/current.md","fileName":"current.md"}`},
|
|
{text: `{"fileName":"current.md"}`},
|
|
},
|
|
}
|
|
installMarkdownDriveDeps(t, caller)
|
|
installMarkdownHTTPGet(t, "old")
|
|
installMarkdownCITempFileDisappearance(t)
|
|
err := executeMarkdownDriveCommand(t, newMarkdownCommand(), nil,
|
|
"markdown", "patch", "--node", "node-1", "--space-id", "space-1",
|
|
"--pattern", "old", "--content", "new", "--yes")
|
|
if err == nil || !strings.Contains(err.Error(), "读取临时文件失败") {
|
|
t.Fatalf("error = %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("drive upload error propagates", func(t *testing.T) {
|
|
boom := errors.New("upload info failed")
|
|
caller := &markdownDriveCaller{
|
|
format: "json",
|
|
steps: []markdownDriveStep{
|
|
{text: `{"downloadUrl":"https://download.test/current.md","fileName":"current.md"}`},
|
|
{text: `{"fileName":"current.md"}`},
|
|
{err: boom},
|
|
},
|
|
}
|
|
installMarkdownDriveDeps(t, caller)
|
|
installMarkdownHTTPGet(t, "old value")
|
|
err := executeMarkdownDriveCommand(t, newMarkdownCommand(), nil,
|
|
"markdown", "patch", "--node", "node-1", "--space-id", "space-1",
|
|
"--pattern", "old", "--content", "new", "--yes")
|
|
if !errors.Is(err, boom) {
|
|
t.Fatalf("error = %v, want %v", err, boom)
|
|
}
|
|
})
|
|
|
|
t.Run("raw drive success reports result", func(t *testing.T) {
|
|
caller := &markdownDriveCaller{
|
|
format: "raw",
|
|
steps: []markdownDriveStep{
|
|
{text: `{"downloadUrl":"https://download.test/current.md","fileName":"current.md"}`},
|
|
{text: `{"fileName":"current.md"}`},
|
|
{text: `{"uploadId":"upload-1","resourceUrls":[{"url":"https://upload.test/drive"}]}`},
|
|
{text: `{"updated":true}`},
|
|
},
|
|
}
|
|
stdout, _ := installMarkdownDriveDeps(t, caller)
|
|
installMarkdownHTTPGet(t, "old value")
|
|
httpPutFile = func(context.Context, string, map[string]string, string, int64) error { return nil }
|
|
if err := executeMarkdownDriveCommand(t, newMarkdownCommand(), nil,
|
|
"markdown", "patch", "--node", "node-1", "--space-id", "space-1",
|
|
"--pattern", "old", "--content", "new", "--yes"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !strings.Contains(stdout.String(), "内容已更新") {
|
|
t.Fatalf("stdout = %q", stdout.String())
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestMarkdownCICoverageGlobalDryRunAndNames(t *testing.T) {
|
|
t.Run("caller enables helper dry run", func(t *testing.T) {
|
|
installMarkdownDriveDeps(t, &markdownDriveCaller{dryRun: true})
|
|
if !markdownGlobalDryRun(&cobra.Command{Use: "standalone"}) {
|
|
t.Fatal("caller dry run was not observed")
|
|
}
|
|
})
|
|
|
|
t.Run("nil command", func(t *testing.T) {
|
|
testseam.Swap(t, &deps, nil)
|
|
if markdownGlobalDryRun(nil) {
|
|
t.Fatal("nil command unexpectedly enabled dry run")
|
|
}
|
|
})
|
|
|
|
t.Run("root without flag", func(t *testing.T) {
|
|
installMarkdownDriveDeps(t, &markdownDriveCaller{})
|
|
if markdownGlobalDryRun(&cobra.Command{Use: "standalone"}) {
|
|
t.Fatal("standalone command unexpectedly enabled dry run")
|
|
}
|
|
})
|
|
|
|
t.Run("short command path", func(t *testing.T) {
|
|
installMarkdownDriveDeps(t, &markdownDriveCaller{})
|
|
root := &cobra.Command{Use: "dws"}
|
|
root.PersistentFlags().Bool("dry-run", false, "")
|
|
if markdownGlobalDryRun(root) {
|
|
t.Fatal("root command unexpectedly enabled dry run")
|
|
}
|
|
})
|
|
|
|
t.Run("subcommand without preceding global flag", func(t *testing.T) {
|
|
installMarkdownDriveDeps(t, &markdownDriveCaller{})
|
|
previousArgs := os.Args
|
|
os.Args = []string{"dws", "markdown", "patch"}
|
|
t.Cleanup(func() { os.Args = previousArgs })
|
|
root := &cobra.Command{Use: "dws"}
|
|
root.PersistentFlags().Bool("dry-run", false, "")
|
|
markdown := &cobra.Command{Use: "markdown"}
|
|
patch := &cobra.Command{Use: "patch"}
|
|
root.AddCommand(markdown)
|
|
markdown.AddCommand(patch)
|
|
if markdownGlobalDryRun(patch) {
|
|
t.Fatal("local command unexpectedly enabled global dry run")
|
|
}
|
|
})
|
|
|
|
for _, test := range []struct {
|
|
name string
|
|
step markdownDriveStep
|
|
want string
|
|
}{
|
|
{name: "metadata error", step: markdownDriveStep{err: errors.New("boom")}, want: "自动获取文件名失败"},
|
|
{name: "empty name", step: markdownDriveStep{text: `{}`}, want: "无法自动获取原文件名"},
|
|
{name: "wrong extension", step: markdownDriveStep{text: `{"fileName":"notes.txt"}`}, want: "不是 .md 文件"},
|
|
} {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
installMarkdownDriveDeps(t, &markdownDriveCaller{steps: []markdownDriveStep{test.step}})
|
|
if _, err := markdownRemoteNameWithContext(context.Background(), "node-1", false); err == nil || !strings.Contains(err.Error(), test.want) {
|
|
t.Fatalf("error = %v", err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMarkdownCICoverageDiffOutputModes(t *testing.T) {
|
|
t.Run("raw overwrite preview", func(t *testing.T) {
|
|
caller := &markdownDriveCaller{
|
|
format: "raw",
|
|
steps: []markdownDriveStep{{text: `{"downloadUrl":"https://download.test/current.md","fileName":"current.md"}`}},
|
|
}
|
|
stdout, _ := installMarkdownDriveDeps(t, caller)
|
|
installMarkdownHTTPGet(t, "before")
|
|
if err := previewMarkdownOverwriteDiff(context.Background(), "node-1", "space-1", false, "after"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !strings.Contains(stdout.String(), "markdown overwrite") {
|
|
t.Fatalf("stdout = %q", stdout.String())
|
|
}
|
|
})
|
|
|
|
t.Run("JSON patch preview", func(t *testing.T) {
|
|
caller := &markdownDriveCaller{format: "json"}
|
|
stdout, _ := installMarkdownDriveDeps(t, caller)
|
|
if err := printMarkdownPatchDiff("node-1", "before", "after", 1); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var payload map[string]any
|
|
if err := json.Unmarshal(stdout.Bytes(), &payload); err != nil || payload["operation"] != "patch" {
|
|
t.Fatalf("payload = %#v, error = %v", payload, err)
|
|
}
|
|
})
|
|
}
|
|
|
|
var _ io.Reader = markdownCIFailingReader{}
|