361 lines
15 KiB
Go
361 lines
15 KiB
Go
package helpers
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"errors"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
func executeDriveEdge(t *testing.T, caller *scriptedToolCaller, args ...string) error {
|
|
t.Helper()
|
|
oldDeps := deps
|
|
oldArgs := os.Args
|
|
InitDeps(caller)
|
|
deps.Out.w = io.Discard
|
|
deps.Out.errW = io.Discard
|
|
t.Cleanup(func() {
|
|
deps = oldDeps
|
|
os.Args = oldArgs
|
|
})
|
|
root := newDriveCommand()
|
|
installExampleGlobalFlags(root)
|
|
root.SilenceErrors = true
|
|
root.SilenceUsage = true
|
|
root.SetOut(io.Discard)
|
|
root.SetErr(io.Discard)
|
|
root.SetArgs(args)
|
|
os.Args = append([]string{"dws", "drive"}, args...)
|
|
return root.Execute()
|
|
}
|
|
|
|
func TestCrossPlatformCoverageParseDriveUploadInfoRemainingCoverage(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
json string
|
|
err bool
|
|
}{
|
|
{"resource array", `{"result":{"uploadId":"u","resourceUrls":[{"url":"https://upload.invalid","headers":{"X-Test":"yes","skip":1}}]}}`, false},
|
|
{"flat resource and headers", `{"uploadId":"u","resourceUrl":"https://upload.invalid","headers":{"X-Test":"yes","skip":1}}`, false},
|
|
{"upload URL fallback", `{"uploadId":"u","uploadUrl":"https://upload.invalid"}`, false},
|
|
{"non-map first URL", `{"uploadId":"u","resourceUrls":[1]}`, true},
|
|
{"missing upload id", `{"resourceUrl":"https://upload.invalid"}`, true},
|
|
}
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
url, id, headers, err := parseDriveUploadInfo(tc.json)
|
|
if (err != nil) != tc.err {
|
|
t.Fatalf("parse error=%v, wantErr=%v", err, tc.err)
|
|
}
|
|
if !tc.err && (url == "" || id == "" || headers == nil) {
|
|
t.Fatalf("parse result url=%q id=%q headers=%v", url, id, headers)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCrossPlatformCoverageDriveUploadValidationAndDryRunCoverage(t *testing.T) {
|
|
file := filepath.Join(t.TempDir(), "fixture.txt")
|
|
if err := os.WriteFile(file, []byte("fixture"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
cases := []struct {
|
|
name string
|
|
args []string
|
|
err bool
|
|
}{
|
|
{"missing file", []string{"upload"}, true},
|
|
{"unreadable file", []string{"upload", "--file", file + ".missing"}, true},
|
|
{"directory", []string{"upload", "--file", t.TempDir()}, true},
|
|
{"numeric drive folder", []string{"upload", "--file", file, "--folder", "123"}, true},
|
|
{"drive dry run", []string{"upload", "--file", file, "--file-name", "named.txt", "--dry-run"}, false},
|
|
{"numeric doc folder", []string{"upload", "--file", file, "--workspace", "space", "--folder", "123"}, true},
|
|
{"doc dry run extension", []string{"upload", "--file", file, "--file-name", "named", "--workspace", "space", "--dry-run"}, false},
|
|
}
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
err := executeDriveEdge(t, &scriptedToolCaller{dry: strings.Contains(strings.Join(tc.args, " "), "--dry-run")}, tc.args...)
|
|
if (err != nil) != tc.err {
|
|
t.Fatalf("Execute(%v) error=%v, wantErr=%v", tc.args, err, tc.err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCrossPlatformCoverageDriveUploadTransportCoverage(t *testing.T) {
|
|
file := filepath.Join(t.TempDir(), "fixture.txt")
|
|
if err := os.WriteFile(file, []byte("fixture"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
boom := errors.New("boom")
|
|
t.Run("drive credentials error", func(t *testing.T) {
|
|
if err := executeDriveEdge(t, &scriptedToolCaller{steps: []scriptedToolStep{{err: boom}}}, "upload", "--file", file); !errors.Is(err, boom) {
|
|
t.Fatalf("error=%v", err)
|
|
}
|
|
})
|
|
t.Run("drive credentials parse error", func(t *testing.T) {
|
|
if err := executeDriveEdge(t, &scriptedToolCaller{steps: []scriptedToolStep{{text: `{}`}}}, "upload", "--file", file); err == nil {
|
|
t.Fatal("parse error returned nil")
|
|
}
|
|
})
|
|
t.Run("drive put error", func(t *testing.T) {
|
|
old := httpPutFile
|
|
httpPutFile = func(context.Context, string, map[string]string, string, int64) error { return boom }
|
|
t.Cleanup(func() { httpPutFile = old })
|
|
payload := `{"uploadId":"u","resourceUrl":"https://upload.invalid"}`
|
|
if err := executeDriveEdge(t, &scriptedToolCaller{steps: []scriptedToolStep{{text: payload}}}, "upload", "--file", file); !errors.Is(err, boom) {
|
|
t.Fatalf("error=%v", err)
|
|
}
|
|
})
|
|
t.Run("drive commit", func(t *testing.T) {
|
|
old := httpPutFile
|
|
httpPutFile = func(context.Context, string, map[string]string, string, int64) error { return nil }
|
|
t.Cleanup(func() { httpPutFile = old })
|
|
payload := `{"uploadId":"u","resourceUrl":"https://upload.invalid"}`
|
|
if err := executeDriveEdge(t, &scriptedToolCaller{steps: []scriptedToolStep{{text: payload}, {text: `{}`}}}, "upload", "--file", file, "--space-id", "space", "--folder", "uuid"); err != nil {
|
|
t.Fatalf("error=%v", err)
|
|
}
|
|
})
|
|
|
|
docArgs := []string{"upload", "--file", file, "--workspace", "space", "--folder", "uuid", "--convert"}
|
|
t.Run("doc credentials error", func(t *testing.T) {
|
|
if err := executeDriveEdge(t, &scriptedToolCaller{steps: []scriptedToolStep{{err: boom}}}, docArgs...); !errors.Is(err, boom) {
|
|
t.Fatalf("error=%v", err)
|
|
}
|
|
})
|
|
t.Run("doc credentials parse error", func(t *testing.T) {
|
|
if err := executeDriveEdge(t, &scriptedToolCaller{steps: []scriptedToolStep{{text: `{}`}}}, docArgs...); err == nil {
|
|
t.Fatal("parse error returned nil")
|
|
}
|
|
})
|
|
t.Run("doc put error", func(t *testing.T) {
|
|
old := httpPutFile
|
|
httpPutFile = func(context.Context, string, map[string]string, string, int64) error { return boom }
|
|
t.Cleanup(func() { httpPutFile = old })
|
|
payload := `{"resourceUrl":"https://upload.invalid","uploadKey":"key"}`
|
|
if err := executeDriveEdge(t, &scriptedToolCaller{steps: []scriptedToolStep{{text: payload}}}, docArgs...); !errors.Is(err, boom) {
|
|
t.Fatalf("error=%v", err)
|
|
}
|
|
})
|
|
t.Run("doc commit", func(t *testing.T) {
|
|
old := httpPutFile
|
|
httpPutFile = func(context.Context, string, map[string]string, string, int64) error { return nil }
|
|
t.Cleanup(func() { httpPutFile = old })
|
|
payload := `{"resourceUrl":"https://upload.invalid","uploadKey":"key"}`
|
|
if err := executeDriveEdge(t, &scriptedToolCaller{steps: []scriptedToolStep{{text: payload}, {text: `{}`}}}, docArgs...); err != nil {
|
|
t.Fatalf("error=%v", err)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestCrossPlatformCoverageUploadDriveFileDataStrictTransaction(t *testing.T) {
|
|
credential := `{"result":{"uploadType":"httpToCenterWithToken","resourceUrl":"https://c.example.com/u?upload_key=u1","uploadId":"u1","headers":{"dentry-token":"token"}}}`
|
|
request := DriveUploadRequest{FilePath: "fixture.bin", FileName: "fixture.bin", FileSize: 7, SpaceID: "space", ParentID: "folder", MIMEType: "application/octet-stream"}
|
|
|
|
t.Run("success with parent", func(t *testing.T) {
|
|
caller := &scriptedToolCaller{steps: []scriptedToolStep{{text: credential}, {text: `{"success":true,"result":{"fileId":"n1"}}`}}}
|
|
installScriptedCaller(t, caller)
|
|
SetHTTPPutFile(func(context.Context, string, map[string]string, string, int64) error { return nil })
|
|
t.Cleanup(func() { SetHTTPPutFile(nil) })
|
|
result, err := UploadDriveFileData(context.Background(), request)
|
|
if err != nil || result["success"] != true || caller.calls != 2 {
|
|
t.Fatalf("result=%v calls=%d error=%v", result, caller.calls, err)
|
|
}
|
|
if caller.args["spaceId"] != "space" || caller.args["parentId"] != "folder" {
|
|
t.Fatalf("commit args=%v", caller.args)
|
|
}
|
|
})
|
|
|
|
t.Run("success with overwrite", func(t *testing.T) {
|
|
caller := &scriptedToolCaller{steps: []scriptedToolStep{{text: credential}, {text: `{"success":true}`}}}
|
|
installScriptedCaller(t, caller)
|
|
SetHTTPPutFile(func(context.Context, string, map[string]string, string, int64) error { return nil })
|
|
t.Cleanup(func() { SetHTTPPutFile(nil) })
|
|
overwrite := request
|
|
overwrite.ParentID = "ignored"
|
|
overwrite.OverwriteFile = "existing"
|
|
if _, err := UploadDriveFileData(context.Background(), overwrite); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if caller.args["overwriteFileId"] != "existing" {
|
|
t.Fatalf("commit args=%v", caller.args)
|
|
}
|
|
})
|
|
|
|
t.Run("credential refresh callback", func(t *testing.T) {
|
|
caller := &scriptedToolCaller{steps: []scriptedToolStep{{text: credential}, {text: credential}, {text: `{"success":true}`}}}
|
|
installScriptedCaller(t, caller)
|
|
putCalls := 0
|
|
SetHTTPPutFile(func(context.Context, string, map[string]string, string, int64) error {
|
|
putCalls++
|
|
if putCalls == 1 {
|
|
return &httpStatusError{StatusCode: 401, Body: "expired"}
|
|
}
|
|
return nil
|
|
})
|
|
t.Cleanup(func() { SetHTTPPutFile(nil) })
|
|
if _, err := UploadDriveFileData(context.Background(), request); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if caller.calls != 3 || putCalls != 2 {
|
|
t.Fatalf("caller calls=%d put calls=%d", caller.calls, putCalls)
|
|
}
|
|
})
|
|
|
|
for _, tc := range []struct {
|
|
name string
|
|
request DriveUploadRequest
|
|
steps []scriptedToolStep
|
|
putErr error
|
|
want string
|
|
}{
|
|
{name: "invalid request", request: DriveUploadRequest{}, want: "invalid drive upload request"},
|
|
{name: "credential failure", request: request, steps: []scriptedToolStep{{err: errors.New("credentials")}}, want: "credentials"},
|
|
{name: "put failure", request: request, steps: []scriptedToolStep{{text: credential}}, putErr: errors.New("put failed"), want: "put failed"},
|
|
{name: "commit failure", request: request, steps: []scriptedToolStep{{text: credential}, {err: errors.New("commit failed")}}, want: "commit failed"},
|
|
{name: "empty commit", request: request, steps: []scriptedToolStep{{text: credential}, {text: " "}}, want: "no business result"},
|
|
{name: "malformed commit", request: request, steps: []scriptedToolStep{{text: credential}, {text: "{"}}, want: "parse commit_upload response"},
|
|
{name: "empty object commit", request: request, steps: []scriptedToolStep{{text: credential}, {text: `{}`}}, want: "empty JSON object"},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
caller := &scriptedToolCaller{steps: tc.steps}
|
|
installScriptedCaller(t, caller)
|
|
SetHTTPPutFile(func(context.Context, string, map[string]string, string, int64) error { return tc.putErr })
|
|
t.Cleanup(func() { SetHTTPPutFile(nil) })
|
|
_, err := UploadDriveFileData(context.Background(), tc.request)
|
|
if err == nil || !strings.Contains(err.Error(), tc.want) {
|
|
t.Fatalf("error=%v, want %q", err, tc.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCrossPlatformCoverageDriveCommandRemainingEdges(t *testing.T) {
|
|
file := filepath.Join(t.TempDir(), "fixture.txt")
|
|
_ = os.WriteFile(file, []byte("fixture"), 0o600)
|
|
cases := [][]string{
|
|
{"list", "--workspace", "space", "--folder", "123"},
|
|
{"mkdir", "--name", "folder", "--folder", "123"},
|
|
{"upload-info", "--file-name", "x", "--file-size", "1", "--folder", "123"},
|
|
{"commit", "--file-name", "x", "--file-size", "1", "--upload-id", "u", "--folder", "123"},
|
|
{"copy", "--node", "node", "--folder", "123"},
|
|
{"move", "--node", "node", "--folder", "123"},
|
|
}
|
|
for _, args := range cases {
|
|
if err := executeDriveEdge(t, &scriptedToolCaller{}, args...); err == nil {
|
|
t.Fatalf("Execute(%v) returned nil", args)
|
|
}
|
|
}
|
|
if err := executeDriveEdge(t, &scriptedToolCaller{dry: true}, "download", "--node", "node", "--output", file, "--dry-run"); err != nil {
|
|
t.Fatalf("dry download: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestCrossPlatformCoverageDriveDownloadDirectoryCoverage(t *testing.T) {
|
|
oldGet := httpGetFile
|
|
httpGetFile = func(context.Context, string, map[string]string, string) error { return nil }
|
|
t.Cleanup(func() { httpGetFile = oldGet })
|
|
dir := t.TempDir()
|
|
for _, payload := range []string{
|
|
`{"resourceUrl":"https://download.invalid/path/from-url.txt","fileName":""}`,
|
|
`{"resourceUrl":"https://download.invalid/path/from-url.txt","fileName":"folder/name.txt"}`,
|
|
} {
|
|
if err := executeDriveEdge(t, &scriptedToolCaller{steps: []scriptedToolStep{{text: payload}}}, "download", "--node", "node", "--output", dir); err != nil {
|
|
t.Fatalf("download: %v", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestCrossPlatformCoverageDriveConfirmationCancellationCoverage(t *testing.T) {
|
|
oldStdin := os.Stdin
|
|
t.Cleanup(func() { os.Stdin = oldStdin })
|
|
for _, test := range []struct {
|
|
args []string
|
|
wantObservableCancel bool
|
|
}{
|
|
{args: []string{"delete", "--node", "node"}, wantObservableCancel: true},
|
|
{args: []string{"publish", "set", "--node", "node"}},
|
|
{args: []string{"publish", "unset", "--node", "node"}},
|
|
} {
|
|
file, err := os.CreateTemp(t.TempDir(), "stdin")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := file.WriteString("no\n"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
_, _ = file.Seek(0, 0)
|
|
os.Stdin = file
|
|
err = executeDriveEdge(t, &scriptedToolCaller{}, test.args...)
|
|
if err == nil || !strings.Contains(err.Error(), "用户取消了操作") {
|
|
t.Fatalf("cancel %v = %v, want 用户取消了操作", test.args, err)
|
|
}
|
|
_ = file.Close()
|
|
}
|
|
}
|
|
|
|
func TestCrossPlatformCoverageDriveInfoDocFallbackCoverage(t *testing.T) {
|
|
oldArgs := os.Args
|
|
os.Args = []string{"dws", "drive", "info"}
|
|
t.Cleanup(func() { os.Args = oldArgs })
|
|
boom := errors.New("boom")
|
|
cases := []struct {
|
|
name string
|
|
steps []scriptedToolStep
|
|
err bool
|
|
}{
|
|
{"drive error", []scriptedToolStep{{err: boom}}, true},
|
|
{"invalid drive JSON", []scriptedToolStep{{text: `{`}}, false},
|
|
{"no result", []scriptedToolStep{{text: `{}`}}, false},
|
|
{"ordinary file", []scriptedToolStep{{text: `{"result":{"extension":"pdf"}}`}}, false},
|
|
{"doc lookup error", []scriptedToolStep{{text: `{"result":{"message":"钉钉文档","fileId":""}}`}, {err: boom}}, false},
|
|
{"invalid doc JSON", []scriptedToolStep{{text: `{"result":{"extension":"adoc","fileId":"node"}}`}, {text: `{`}}, false},
|
|
{"empty flat doc", []scriptedToolStep{{text: `{"result":{"extension":"axls","fileId":"node"}}`}, {text: `{}`}}, false},
|
|
{"flat doc merge", []scriptedToolStep{{text: `{"result":{"extension":"amind","fileId":"node","path":"/drive","fileSize":3,"type":"doc"}}`}, {text: `{"title":"Doc","path":"existing"}`}}, false},
|
|
{"wrapped doc", []scriptedToolStep{{text: `{"result":{"extension":"adraw","fileId":"node","dentryId":"d"}}`}, {text: `{"result":{"title":"Doc"}}`}}, false},
|
|
}
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
caller := &scriptedToolCaller{steps: tc.steps}
|
|
old := deps
|
|
InitDeps(caller)
|
|
deps.Out.w = &bytes.Buffer{}
|
|
deps.Out.errW = io.Discard
|
|
t.Cleanup(func() { deps = old })
|
|
err := driveInfoWithDocFallback("fallback-node", map[string]any{"fileId": "fallback-node"})
|
|
if (err != nil) != tc.err {
|
|
t.Fatalf("error=%v, wantErr=%v", err, tc.err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCrossPlatformCoverageDriveSmallHelperEdges(t *testing.T) {
|
|
for _, ext := range []string{"adoc", "AXLS", "amind", "adraw", "pdf"} {
|
|
_ = isDingTalkDocExtension(ext)
|
|
}
|
|
cmd := &cobra.Command{Use: "upload"}
|
|
cmd.Flags().String("file", "", "")
|
|
cmd.Flags().String("file-name", "", "")
|
|
cmd.Flags().String("name", "", "")
|
|
cmd.Flags().String("workspace", "", "")
|
|
cmd.Flags().String("workspace-id", "", "")
|
|
cmd.Flags().String("folder", "", "")
|
|
cmd.Flags().String("parent-id", "", "")
|
|
cmd.Flags().String("space-id", "", "")
|
|
cmd.Flags().String("mime-type", "", "")
|
|
cmd.Flags().Bool("convert", false, "")
|
|
if err := cmd.Flags().Set("file", t.TempDir()); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := runDriveUpload(cmd, nil); err == nil {
|
|
t.Fatal("directory upload returned nil")
|
|
}
|
|
}
|