fix(doc): verify recovered import placement

This commit is contained in:
dxb committed 2026-08-26 09:53:11 +08:00
1 parent 81b4e3e81b
commit 5677dec657
8 files changed
+280 -34

No files matched your search

@@ -402,7 +402,9 @@ var reviewedSchemaParameterMappingExclusions = map[string]string{
"doc.get_document_content --start-block-id": "Runtime extension sends startBlockId for scoped JSONML reads, which is absent from the immutable pinned get_document_content metadata at its declared source revision.",
"doc.get_document_content --tags": "Runtime extension sends tags for scoped JSONML reads, which is absent from the immutable pinned get_document_content metadata at its declared source revision.",
"doc.get_document_style --node": "Reviewed unpinned adapter: doc.get_document_style has no singular pinned interface_ref; --node is a CLI wrapper input and does not publish a direct interface property.",
"doc.import_get --folder": "Composite recovery verification input; it is used only by the get_document_info readback after query_import_task completes.",
"doc.import_get --task-id": "Reviewed unpinned adapter: doc.import_get has no singular pinned interface_ref; --task-id is a CLI wrapper input and does not publish a direct interface property.",
"doc.import_get --workspace": "Composite recovery verification input; it is used only by the get_document_info readback after query_import_task completes.",
"doc.insert_document_block --fix-jsonml": "local JSONML normalization control",
"doc.insert_document_block --heading": "aggregate convenience input used to build element",
"doc.insert_document_block --level": "aggregate convenience input used to build element",
+9 -4
View File
@@ -4316,13 +4316,15 @@ CLI 内部自动完成全部流程:
Short: "查询导入任务结果(手动兜底)",
Long: `根据 taskId 查询文档导入任务的执行结果。
通常不需要手动调用,dws doc import 会自动完成轮询。
仅在导入命令超时或中断后,用于手动查询任务状态。
仅在导入命令超时或中断后,用于手动查询任务状态。必须同时提供原导入
目标(--folder 或 --workspace),以便 completed 后回读验证真实落点;优先
直接复制超时结果中的完整 next_command。
任务状态:
processing 转换中
completed 导入成功,返回 documentUrl
failed 导入失败`,
Example: ` dws doc import get --task-id <TASK_ID>`,
Example: ` dws doc import get --task-id <TASK_ID> --workspace <WORKSPACE_ID>`,
RunE: func(cmd *cobra.Command, _ []string) error {
return runImportGetCommand(cmd, docImportFlowConfig())
},
@@ -4349,13 +4351,16 @@ CLI 内部自动完成全部流程:
},
Selection: contract.SelectionSpec{
AgentSummary: "根据 taskId 查询文档导入任务的执行结果",
UseWhen: []string{"查询文档导入任务结果(已有 taskId,导入超时/中断后兜底)时"},
UseWhen: []string{"已有 doc import 超时结果及其完整 next_command,需要续查同一 taskId 并验证原 folder/workspace 落点时"},
AvoidWhen: []string{"发起导入用 doc import(若入口可用);不要用本命令代替导入"},
Examples: []string{"dws doc import get --task-id <TASK_ID> --format json"},
Examples: []string{"dws doc import get --task-id <TASK_ID> --workspace <WORKSPACE_ID> --format json"},
},
},
})
importGetCmd.Flags().String("task-id", "", "导入任务 ID (必填)")
importGetCmd.Flags().String("folder", "", "原导入目标文件夹 ID 或 URL(与 --workspace 至少提供一个,用于落点验证)")
importGetCmd.Flags().String("workspace", "", "原导入目标知识库 ID 或 URL(与 --folder 至少提供一个,用于落点验证)")
importGetCmd.MarkFlagsOneRequired("folder", "workspace")
importCmd.AddCommand(importGetCmd)
newHybridGroupCommand(importCmd)
+1 -1
View File
@@ -683,7 +683,7 @@ func TestCrossPlatformCoverageDocExportImportCommandEdges(t *testing.T) {
{"failed empty", []scriptedToolStep{{text: `{"status":"failed"}`}}, false},
} {
t.Run("import get "+tc.name, func(t *testing.T) {
_ = run(t, tc.steps, tc.dry, "import", "get", "--task-id=task")
_ = run(t, tc.steps, tc.dry, "import", "get", "--task-id=task", "--workspace=workspace")
})
}
}
+106
View File
@@ -19,6 +19,7 @@ import (
"encoding/json"
"errors"
"os"
"strings"
"testing"
"time"
@@ -252,3 +253,108 @@ func TestCrossPlatformCoverageDocImportTargetDefensiveBranches(t *testing.T) {
verifyFailure(t, preparedImportFile{}, `{"nodeId":"other"}`, "https://alidocs.dingtalk.com/i/nodes/node-1")
verifyFailure(t, preparedImportFile{workspace: "space-1"}, `{"nodeId":"node-1","workspaceId":"wrong"}`, "https://alidocs.dingtalk.com/i/nodes/node-1")
}
func TestCrossPlatformCoverageDocImportGetVerifiesOriginalTarget(t *testing.T) {
previousDeps := deps
previousArgs := os.Args
t.Cleanup(func() {
deps = previousDeps
os.Args = previousArgs
})
os.Args = []string{"dws", "doc"}
caller := &sheetImportCaller{responses: map[string][]string{
"query_import_task": {`{"status":"completed","documentUrl":"https://alidocs.dingtalk.com/i/nodes/node-2"}`},
"get_document_info": {`{"result":{"nodeId":"node-2","workspaceId":"space-2","name":"report"}}`},
}}
InitDeps(caller)
var output bytes.Buffer
deps.Out.w = &output
deps.Out.errW = &output
cmd := &cobra.Command{Use: "get"}
cmd.Flags().String("task-id", "task-2", "")
cmd.Flags().String("folder", "", "")
cmd.Flags().String("workspace", "space-2", "")
if err := runImportGetCommand(cmd, docImportFlowConfig()); err != nil {
t.Fatalf("doc import get: %v", err)
}
if len(caller.calls) != 2 || caller.calls[0].tool != "query_import_task" || caller.calls[1].tool != "get_document_info" {
t.Fatalf("calls = %#v", caller.calls)
}
var result map[string]any
if err := json.Unmarshal(output.Bytes(), &result); err != nil {
t.Fatalf("decode output: %v\n%s", err, output.String())
}
if result["nodeId"] != "node-2" || result["verified"] != true {
t.Fatalf("result = %#v", result)
}
target, _ := result["target"].(map[string]any)
if target["source"] != "workspace_flag" || target["workspaceId"] != "space-2" {
t.Fatalf("target = %#v", target)
}
}
func TestCrossPlatformCoverageDocImportGetRequiresOriginalTarget(t *testing.T) {
previousDeps := deps
t.Cleanup(func() { deps = previousDeps })
caller := &sheetImportCaller{responses: map[string][]string{}}
InitDeps(caller)
cmd := &cobra.Command{Use: "get"}
cmd.Flags().String("task-id", "task-2", "")
cmd.Flags().String("folder", "", "")
cmd.Flags().String("workspace", "", "")
if err := runImportGetCommand(cmd, docImportFlowConfig()); err == nil || !strings.Contains(err.Error(), "完整 next_command") {
t.Fatalf("missing target error = %v", err)
}
if len(caller.calls) != 0 {
t.Fatalf("missing target reached MCP: %#v", caller.calls)
}
}
func TestCrossPlatformCoverageDocImportGetDryRunIncludesTarget(t *testing.T) {
previousDeps := deps
t.Cleanup(func() { deps = previousDeps })
caller := &sheetImportCaller{dryRun: true}
InitDeps(caller)
var output bytes.Buffer
deps.Out.w = &output
cmd := &cobra.Command{Use: "get"}
cmd.Flags().String("task-id", "task-2", "")
cmd.Flags().String("folder", "", "")
cmd.Flags().String("workspace", "space-2", "")
if err := runImportGetCommand(cmd, docImportFlowConfig()); err != nil {
t.Fatalf("doc import get dry-run: %v", err)
}
if len(caller.calls) != 0 {
t.Fatalf("dry-run reached MCP: %#v", caller.calls)
}
var result map[string]any
if err := json.Unmarshal(output.Bytes(), &result); err != nil {
t.Fatalf("decode output: %v\n%s", err, output.String())
}
if result["dry_run"] != true || result["executed"] != false {
t.Fatalf("result = %#v", result)
}
target, _ := result["target"].(map[string]any)
if target["source"] != "workspace_flag" || target["workspaceId"] != "space-2" {
t.Fatalf("target = %#v", target)
}
}
func TestCrossPlatformCoverageDocImportRecoveryCommandCarriesEveryTarget(t *testing.T) {
got := importRecoveryCommand(docImportFlowConfig(), "task-1", preparedImportFile{
folder: "folder;unsafe", workspace: "https://alidocs.test/space?id=1&kind=doc",
})
for _, want := range []string{
"dws doc import get --task-id task-1",
"--folder 'folder;unsafe'",
"--workspace 'https://alidocs.test/space?id=1&kind=doc'",
} {
if !strings.Contains(got, want) {
t.Fatalf("recovery command = %q, want %q", got, want)
}
}
}
+82 -17
View File
@@ -328,7 +328,7 @@ func findImportedDocumentInfo(value any) (map[string]any, bool) {
if !ok {
return nil, false
}
if importString(object, "nodeId", "folderId", "workspaceId") != "" {
if importString(object, "nodeId", "fileId", "dentryUuid", "folderId", "workspaceId") != "" {
return object, true
}
for _, key := range []string{"result", "data", "documentInfo", "document", "doc", "file"} {
@@ -372,6 +372,10 @@ func verifyImportedDocumentPlacement(ctx context.Context, file preparedImportFil
if nodeID == "" {
return "", nil, docImportPlacementError(file, taskID, "", nil, fmt.Errorf("导入结果缺少可解析的 documentUrl"))
}
return verifyImportedNodePlacement(ctx, file, taskID, nodeID)
}
func verifyImportedNodePlacement(ctx context.Context, file preparedImportFile, taskID, nodeID string) (string, map[string]any, error) {
text, err := callMCPToolReturnTextOnServer(ctx, "doc", "get_document_info", map[string]any{"nodeId": nodeID})
if err != nil {
return nodeID, nil, docImportPlacementError(file, taskID, nodeID, nil, err)
@@ -381,7 +385,7 @@ func verifyImportedDocumentPlacement(ctx context.Context, file preparedImportFil
return nodeID, nil, docImportPlacementError(file, taskID, nodeID, nil, err)
}
observedNodeID := importString(info, "nodeId")
observedNodeID := importString(info, "nodeId", "fileId", "dentryUuid", "id")
if observedNodeID != "" && observedNodeID != nodeID {
return nodeID, info, docImportPlacementError(file, taskID, nodeID, info,
fmt.Errorf("回读 nodeId=%s,与导入结果 nodeId=%s 不一致", observedNodeID, nodeID))
@@ -429,16 +433,18 @@ func importTargetSummary(file preparedImportFile) map[string]any {
func docImportPlacementError(file preparedImportFile, taskID, nodeID string, observed map[string]any, cause error) error {
details := map[string]any{
"status": "partial_success",
"taskId": taskID,
"nodeId": nodeID,
"target": importTargetSummary(file),
"verified": false,
}
if taskID != "" {
details["taskId"] = taskID
}
if observed != nil {
details["observed"] = compactImportedDocumentInfo(observed, nodeID)
}
return apperrors.NewAPI(
"导入任务已经完成,但目标落点回读验证失败;为避免重复创建,请先按 nodeId 检查文档",
"导入或上传已经完成,但目标落点回读验证失败;为避免重复创建,请先按 nodeId 检查文档",
apperrors.WithOperation("doc.import"),
apperrors.WithReason("doc_import_placement_unverified"),
apperrors.WithFailureStage("verify_placement"),
@@ -469,7 +475,7 @@ func runImportUploadFallback(cmd *cobra.Command, cfg importFlowConfig, file prep
label = "无扩展名"
}
deps.Out.PrintWarning(fmt.Sprintf(
"%s 文件不支持转换为在线文档(支持: %s),已自动改走文件上传链路,以原文件形式存入 --folder/--workspace 指定的目标位置;如需在线文档,请先将内容转换为 md 后重新执行 doc import;上传到钉盘请用 dws drive upload",
"%s 文件不支持转换为在线文档(支持: %s),已自动改走文件上传链路,以原文件形式存入解析出的文档目标位置;如需在线文档,请先将内容转换为 md 后重新执行 doc import;上传到钉盘请用 dws drive upload",
label, cfg.supportedFormatsText))
// prepareImportFile 的 name 去掉了扩展名;上传保留原始文件名形态
@@ -523,7 +529,14 @@ func runImportUploadFallback(cmd *cobra.Command, cfg importFlowConfig, file prep
if err != nil {
return err
}
return deps.Out.PrintJSON(map[string]any{
var verification map[string]any
if cfg.verifyPlacement {
_, verification, err = verifyImportedNodePlacement(ctx, file, "", dentryID)
if err != nil {
return err
}
}
result := map[string]any{
"success": true,
"operation": "上传文件到钉钉文档",
"requested_operation": cfg.operation,
@@ -533,7 +546,13 @@ func runImportUploadFallback(cmd *cobra.Command, cfg importFlowConfig, file prep
"format": file.extension,
"dentry_id": dentryID,
"result": commit,
})
}
if cfg.verifyPlacement {
result["verified"] = true
result["target"] = importTargetSummary(file)
result["verification"] = verification
}
return deps.Out.PrintJSON(result)
}
// uploadCommitIDKeys 是 commit_uploaded_file 响应中可作为文件标识的字段,
@@ -569,13 +588,13 @@ func runImportCommand(cmd *cobra.Command, args []string, cfg importFlowConfig) e
if err != nil {
return err
}
// 非回退配置的白名单外文件已在 prepareImportFile 中按基线顺序拒绝
if cfg.uploadFallback && !cfg.supportedFormats[file.extension] {
return runImportUploadFallback(cmd, cfg, file)
}
uploadFallback := cfg.uploadFallback && !cfg.supportedFormats[file.extension]
jsonMode := deps.Caller.Format() == "json"
if deps.Caller.DryRun() {
if uploadFallback {
return runImportUploadFallback(cmd, cfg, file)
}
if jsonMode {
return deps.Out.PrintJSON(map[string]any{
"dry_run": true,
@@ -605,6 +624,11 @@ func runImportCommand(cmd *cobra.Command, args []string, cfg importFlowConfig) e
return err
}
}
// 实际执行时,白名单外格式也必须先完成与在线转换路径相同的目标解析,
// 再进入上传回退;这样无显式目标时仍落到“我的文档”,且可执行同一套回读验证。
if uploadFallback {
return runImportUploadFallback(cmd, cfg, file)
}
if !jsonMode {
deps.Out.PrintInfo("[1/4] 创建导入会话...")
@@ -691,10 +715,10 @@ func runImportCommand(cmd *cobra.Command, args []string, cfg importFlowConfig) e
"timed_out": true,
"taskId": taskID,
"status": "processing",
"next_command": fmt.Sprintf(cfg.nextCommand, taskID),
"next_command": importRecoveryCommand(cfg, taskID, file),
})
}
return fmt.Errorf("%s,请稍后使用 %s 手动查询", timeoutErr.Error(), fmt.Sprintf(cfg.nextCommand, taskID))
return fmt.Errorf("%s,请稍后使用 %s 手动查询", timeoutErr.Error(), importRecoveryCommand(cfg, taskID, file))
}
documentURL, _ := result["documentUrl"].(string)
@@ -730,20 +754,50 @@ func runImportCommand(cmd *cobra.Command, args []string, cfg importFlowConfig) e
return deps.Out.PrintJSON(finalResult)
}
func importRecoveryCommand(cfg importFlowConfig, taskID string, file preparedImportFile) string {
command := fmt.Sprintf(cfg.nextCommand, ShellQuoteArg(taskID))
if !cfg.verifyPlacement {
return command
}
if file.folder != "" {
command += " --folder " + ShellQuoteArg(file.folder)
}
if file.workspace != "" {
command += " --workspace " + ShellQuoteArg(file.workspace)
}
return command
}
func runImportGetCommand(cmd *cobra.Command, cfg importFlowConfig) error {
taskID := mustGetFlag(cmd, "task-id")
if taskID == "" {
return fmt.Errorf("flag --task-id is required")
}
target := preparedImportFile{
folder: importFlagValue(cmd, cfg.folderFlags...),
workspace: importFlagValue(cmd, cfg.workspaceFlags...),
}
if target.folder != "" {
target.target = "folder_flag"
} else if target.workspace != "" {
target.target = "workspace_flag"
}
if cfg.verifyPlacement && target.folder == "" && target.workspace == "" {
return fmt.Errorf("doc import get 需要通过 --folder 或 --workspace 提供原导入目标;请直接使用 doc import 超时结果中的完整 next_command")
}
if deps.Caller.DryRun() {
if deps.Caller.Format() == "json" {
return deps.Out.PrintJSON(map[string]any{
preview := map[string]any{
"dry_run": true,
"executed": false,
"preview_kind": "plan",
"operation": cfg.queryOperation,
"taskId": taskID,
})
}
if cfg.verifyPlacement {
preview["target"] = importTargetSummary(target)
}
return deps.Out.PrintJSON(preview)
}
deps.Out.PrintKeyValue("操作", cfg.queryOperation)
deps.Out.PrintKeyValue("任务ID", taskID)
@@ -767,9 +821,20 @@ func runImportGetCommand(cmd *cobra.Command, cfg importFlowConfig) error {
status, _ := result["status"].(string)
message, _ := result["message"].(string)
if strings.EqualFold(status, "completed") {
documentURL, _ := result["documentUrl"].(string)
nodeID := extractNodeIDFromDocURL(documentURL)
if cfg.verifyPlacement {
var verification map[string]any
nodeID, verification, err = verifyImportedDocumentPlacement(ctx, target, taskID, documentURL)
if err != nil {
return err
}
result["verified"] = true
result["target"] = importTargetSummary(target)
result["verification"] = verification
}
if cfg.includeNodeID {
documentURL, _ := result["documentUrl"].(string)
result["nodeId"] = extractNodeIDFromDocURL(documentURL)
result["nodeId"] = nodeID
}
return deps.Out.PrintJSON(result)
}
@@ -77,7 +77,7 @@ func TestCrossPlatformCoverageImportFlowRemainingBranches(t *testing.T) {
cfg.poll.interval = func(int) time.Duration { return 0 }
cfg.poll.wait = func(context.Context, time.Duration) error { return nil }
err := runImportCommand(importCoverageCommand(t, writeImportFixture(t, "md")), nil, cfg)
if err == nil || !strings.Contains(err.Error(), "手动查询") {
if err == nil || !strings.Contains(err.Error(), "手动查询") || !strings.Contains(err.Error(), "--workspace my-space") {
t.Fatalf("runImportCommand() error = %v, want manual-query timeout", err)
}
})
@@ -90,6 +90,8 @@ func TestCrossPlatformCoverageImportFlowRemainingBranches(t *testing.T) {
installScriptedCaller(t, &scriptedToolCaller{steps: []scriptedToolStep{{text: `{"status":"processing"}`}}})
cmd := &cobra.Command{Use: "get"}
cmd.Flags().String("task-id", "task-1", "")
cmd.Flags().String("folder", "", "")
cmd.Flags().String("workspace", "workspace-1", "")
if err := runImportGetCommand(cmd, docImportFlowConfig()); err != nil {
t.Fatalf("runImportGetCommand() error = %v", err)
}
+76 -10
View File
@@ -23,6 +23,7 @@ import (
"strings"
"testing"
apperrors "github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/errors"
"github.com/spf13/cobra"
)
@@ -56,6 +57,7 @@ func TestCrossPlatformCoverageDocImportHTMLUploadRedirect(t *testing.T) {
uploadSteps := []scriptedToolStep{
{text: `{"resourceUrl":"https://upload.example.test/object","uploadKey":"key-1"}`},
{text: `{"dentryUuid":"node-1","name":"sales.html"}`},
{text: `{"nodeId":"node-1","workspaceId":"ws-1","folderId":"folder-abc","name":"sales.html"}`},
}
t.Run("html upload fallback emits marked json without legacy warnings", func(t *testing.T) {
@@ -74,20 +76,20 @@ func TestCrossPlatformCoverageDocImportHTMLUploadRedirect(t *testing.T) {
if err := runImportCommand(cmd, nil, docImportFlowConfig()); err != nil {
t.Fatalf("runImportCommand() error = %v, want upload fallback success", err)
}
if caller.calls != 2 || caller.tool != "commit_uploaded_file" {
t.Fatalf("fallback calls = %d last tool = %q, want 2 calls ending in commit_uploaded_file", caller.calls, caller.tool)
if caller.calls != 3 || caller.tool != "get_document_info" {
t.Fatalf("fallback calls = %d last tool = %q, want readback after commit", caller.calls, caller.tool)
}
if got := caller.args["workspaceId"]; got != "ws-1" {
if got := caller.argsLog[1]["workspaceId"]; got != "ws-1" {
t.Fatalf("commit workspaceId = %v, want ws-1", got)
}
if got := caller.args["name"]; got != "sales.html" {
if got := caller.argsLog[1]["name"]; got != "sales.html" {
t.Fatalf("commit name = %v, want original file name with extension", got)
}
var payload map[string]any
if err := json.Unmarshal(stdout.Bytes(), &payload); err != nil {
t.Fatalf("fallback result must be one JSON document: %v\n%s", err, stdout.String())
}
if payload["success"] != true || payload["fallback"] != "upload" || payload["converted"] != false {
if payload["success"] != true || payload["fallback"] != "upload" || payload["converted"] != false || payload["verified"] != true {
t.Fatalf("fallback markers missing: %#v", payload)
}
if payload["dentry_id"] != "node-1" {
@@ -104,6 +106,63 @@ func TestCrossPlatformCoverageDocImportHTMLUploadRedirect(t *testing.T) {
}
})
t.Run("fallback resolves and verifies the default personal workspace", func(t *testing.T) {
caller := &scriptedToolCaller{format: "json", steps: []scriptedToolStep{
{text: `{"wikiSpaces":[{"workspaceId":"my-space"}]}`},
{text: `{"resourceUrl":"https://upload.example.test/object","uploadKey":"key-1"}`},
{text: `{"dentryUuid":"node-default","name":"sales.pdf"}`},
{text: `{"nodeId":"node-default","workspaceId":"my-space","name":"sales.pdf"}`},
}}
installScriptedCaller(t, caller)
var stdout bytes.Buffer
deps.Out.w = &stdout
SetHTTPPutFile(func(context.Context, string, map[string]string, string, int64) error { return nil })
t.Cleanup(func() { SetHTTPPutFile(nil) })
cmd := htmlFallbackCommand(t, writeImportFixture(t, "pdf"))
if err := runImportCommand(cmd, nil, docImportFlowConfig()); err != nil {
t.Fatalf("runImportCommand() error = %v", err)
}
if strings.Join(caller.toolLog, ",") != "list_wikiSpaces,get_file_upload_info,commit_uploaded_file,get_document_info" {
t.Fatalf("fallback calls = %#v", caller.toolLog)
}
if got := caller.argsLog[2]["workspaceId"]; got != "my-space" {
t.Fatalf("default commit workspaceId = %#v", got)
}
var payload map[string]any
if err := json.Unmarshal(stdout.Bytes(), &payload); err != nil {
t.Fatal(err)
}
target, _ := payload["target"].(map[string]any)
if payload["verified"] != true || target["source"] != "default_personal_workspace" || target["workspaceId"] != "my-space" {
t.Fatalf("fallback result = %#v", payload)
}
})
t.Run("fallback does not report success when placement readback mismatches", func(t *testing.T) {
caller := &scriptedToolCaller{format: "json", steps: []scriptedToolStep{
{text: `{"resourceUrl":"https://upload.example.test/object","uploadKey":"key-1"}`},
{text: `{"dentryUuid":"node-mismatch"}`},
{text: `{"nodeId":"node-mismatch","workspaceId":"wrong-space"}`},
}}
installScriptedCaller(t, caller)
var stdout bytes.Buffer
deps.Out.w = &stdout
SetHTTPPutFile(func(context.Context, string, map[string]string, string, int64) error { return nil })
t.Cleanup(func() { SetHTTPPutFile(nil) })
cmd := htmlFallbackCommand(t, writeImportFixture(t, "pdf"))
_ = cmd.Flags().Set("workspace", "expected-space")
err := runImportCommand(cmd, nil, docImportFlowConfig())
var structured *apperrors.Error
if !errors.As(err, &structured) || structured.Reason != "doc_import_placement_unverified" {
t.Fatalf("placement mismatch error = %#v", err)
}
if stdout.Len() != 0 {
t.Fatalf("placement mismatch emitted success output: %s", stdout.String())
}
})
t.Run("json dry run stays a single json document", func(t *testing.T) {
caller := &scriptedToolCaller{format: "json", dry: true}
installScriptedCaller(t, caller)
@@ -134,11 +193,12 @@ func TestCrossPlatformCoverageDocImportHTMLUploadRedirect(t *testing.T) {
t.Cleanup(func() { SetHTTPPutFile(nil) })
cmd := htmlFallbackCommand(t, writeImportFixture(t, ext))
_ = cmd.Flags().Set("workspace", "ws-1")
if err := runImportCommand(cmd, nil, docImportFlowConfig()); err != nil {
t.Fatalf("runImportCommand(%s) error = %v, want upload fallback success", ext, err)
}
if caller.tool != "commit_uploaded_file" {
t.Fatalf("%s last tool = %q, want commit_uploaded_file", ext, caller.tool)
if caller.tool != "get_document_info" {
t.Fatalf("%s last tool = %q, want get_document_info", ext, caller.tool)
}
}
})
@@ -151,11 +211,12 @@ func TestCrossPlatformCoverageDocImportHTMLUploadRedirect(t *testing.T) {
path := writeImportFixture(t, "HTM")
cmd := htmlFallbackCommand(t, "")
_ = cmd.Flags().Set("workspace", "ws-1")
if err := runImportCommand(cmd, []string{path}, docImportFlowConfig()); err != nil {
t.Fatalf("runImportCommand() error = %v, want upload fallback success", err)
}
if caller.tool != "commit_uploaded_file" {
t.Fatalf("last tool = %q, want commit_uploaded_file", caller.tool)
if caller.tool != "get_document_info" {
t.Fatalf("last tool = %q, want get_document_info", caller.tool)
}
})
@@ -172,7 +233,7 @@ func TestCrossPlatformCoverageDocImportHTMLUploadRedirect(t *testing.T) {
if err := runImportCommand(cmd, nil, docImportFlowConfig()); err != nil {
t.Fatalf("runImportCommand() error = %v, want upload fallback success", err)
}
if got := caller.args["folderId"]; got != "folder-abc" {
if got := caller.argsLog[1]["folderId"]; got != "folder-abc" {
t.Fatalf("commit folderId = %v, want folder-abc from --folder-id alias", got)
}
})
@@ -190,6 +251,7 @@ func TestCrossPlatformCoverageDocImportHTMLUploadRedirect(t *testing.T) {
t.Fatal(err)
}
cmd := htmlFallbackCommand(t, noExt)
_ = cmd.Flags().Set("workspace", "ws-1")
if err := runImportCommand(cmd, nil, docImportFlowConfig()); err != nil {
t.Fatalf("runImportCommand() error = %v, want upload fallback success", err)
}
@@ -298,6 +360,7 @@ func TestCrossPlatformCoverageDocImportHTMLUploadRedirect(t *testing.T) {
t.Cleanup(func() { SetHTTPPutFile(nil) })
cmd := htmlFallbackCommand(t, writeImportFixture(t, "html"))
_ = cmd.Flags().Set("workspace", "ws-1")
err := runImportCommand(cmd, nil, docImportFlowConfig())
if err == nil || !strings.Contains(err.Error(), tc.wantErr) {
t.Fatalf("runImportCommand() error = %v, want %q", err, tc.wantErr)
@@ -326,6 +389,7 @@ func TestCrossPlatformCoverageDocImportHTMLUploadRedirect(t *testing.T) {
t.Cleanup(func() { SetHTTPPutFile(nil) })
cmd := htmlFallbackCommand(t, writeImportFixture(t, "html"))
_ = cmd.Flags().Set("workspace", "ws-1")
err := runImportCommand(cmd, nil, docImportFlowConfig())
if err == nil || !strings.Contains(err.Error(), tc.wantErr) {
t.Fatalf("runImportCommand() error = %v, want %q", err, tc.wantErr)
@@ -338,6 +402,7 @@ func TestCrossPlatformCoverageDocImportHTMLUploadRedirect(t *testing.T) {
caller := &scriptedToolCaller{format: "json", steps: []scriptedToolStep{
{text: `{"resourceUrl":"https://upload.example.test/object","uploadKey":"key-1"}`},
{text: `{"result":{"dentryUuid":"nested-node-9"}}`},
{text: `{"fileId":"nested-node-9","workspaceId":"ws-1"}`},
}}
installScriptedCaller(t, caller)
var stdout bytes.Buffer
@@ -346,6 +411,7 @@ func TestCrossPlatformCoverageDocImportHTMLUploadRedirect(t *testing.T) {
t.Cleanup(func() { SetHTTPPutFile(nil) })
cmd := htmlFallbackCommand(t, writeImportFixture(t, "html"))
_ = cmd.Flags().Set("workspace", "ws-1")
if err := runImportCommand(cmd, nil, docImportFlowConfig()); err != nil {
t.Fatalf("runImportCommand() error = %v", err)
}
@@ -93,7 +93,7 @@ func TestWukongSyncDocCommands(t *testing.T) {
requireWukongSyncFlags(t, importCmd, "file", "folder", "workspace", "name", "folder-id", "workspace-id")
importGetCmd := requireWukongSyncCommand(t, root, "import", "get")
requireWukongSyncFlags(t, importGetCmd, "task-id")
requireWukongSyncFlags(t, importGetCmd, "task-id", "folder", "workspace")
}
func TestWukongSyncSheetCommands(t *testing.T) {