mirror of
https://github.com/larksuite/cli.git
synced 2026-07-09 18:34:03 +08:00
test: cover in-memory Content upload paths for clipboard feature
Adds unit tests for the new Content io.Reader branches introduced by the clipboard feature: - UploadDriveMediaAll with in-memory Content (drive_media_upload.go 87.5%) - UploadDriveMediaMultipart with in-memory Content (84.6%) - uploadDocMediaFile single-part and multipart with clipboard bytes (doc_media_upload.go 0% -> 88.9%) Adds TestNewRuntimeContextForAPI helper that wires Factory, context, and bot identity so package tests can invoke DoAPI without mounting the full cobra command tree.
This commit is contained in:
@@ -106,6 +106,98 @@ func TestUploadDriveMediaAllBuildsMultipartBody(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestUploadDriveMediaAllWithInMemoryContent(t *testing.T) {
|
||||
// When Content is provided, FilePath is ignored — the in-memory reader
|
||||
// is streamed directly into the multipart form. Used by the clipboard
|
||||
// upload path.
|
||||
runtime, reg := newDriveMediaUploadTestRuntime(t)
|
||||
withDriveMediaUploadWorkingDir(t, t.TempDir())
|
||||
|
||||
uploadStub := &httpmock.Stub{
|
||||
Method: "POST",
|
||||
URL: "/open-apis/drive/v1/medias/upload_all",
|
||||
Body: map[string]interface{}{
|
||||
"code": 0,
|
||||
"data": map[string]interface{}{"file_token": "file_mem_123"},
|
||||
},
|
||||
}
|
||||
reg.Register(uploadStub)
|
||||
|
||||
payload := []byte{0x89, 0x50, 0x4e, 0x47, 0xde, 0xad}
|
||||
fileToken, err := UploadDriveMediaAll(runtime, DriveMediaUploadAllConfig{
|
||||
Content: bytes.NewReader(payload),
|
||||
FileName: "clipboard.png",
|
||||
FileSize: int64(len(payload)),
|
||||
ParentType: "docx_image",
|
||||
ParentNode: strPtr("blk_parent"),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("UploadDriveMediaAll() error: %v", err)
|
||||
}
|
||||
if fileToken != "file_mem_123" {
|
||||
t.Fatalf("fileToken = %q, want %q", fileToken, "file_mem_123")
|
||||
}
|
||||
|
||||
body := decodeCapturedDriveMediaMultipartBody(t, uploadStub)
|
||||
if got := body.Fields["file_name"]; got != "clipboard.png" {
|
||||
t.Fatalf("file_name = %q, want %q", got, "clipboard.png")
|
||||
}
|
||||
if got := body.Files["file"]; !bytes.Equal(got, payload) {
|
||||
t.Fatalf("uploaded file bytes mismatch; got %v, want %v", got, payload)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUploadDriveMediaMultipartWithInMemoryContent(t *testing.T) {
|
||||
// Clipboard multipart upload: Content reader replaces FilePath, and the
|
||||
// server-declared block plan is honored exactly.
|
||||
runtime, reg := newDriveMediaUploadTestRuntime(t)
|
||||
withDriveMediaUploadWorkingDir(t, t.TempDir())
|
||||
|
||||
size := MaxDriveMediaUploadSinglePartSize + 1
|
||||
reg.Register(&httpmock.Stub{
|
||||
Method: "POST",
|
||||
URL: "/open-apis/drive/v1/medias/upload_prepare",
|
||||
Body: map[string]interface{}{
|
||||
"code": 0,
|
||||
"data": map[string]interface{}{
|
||||
"upload_id": "upload_mem_1",
|
||||
"block_size": float64(4 * 1024 * 1024),
|
||||
"block_num": float64(6),
|
||||
},
|
||||
},
|
||||
})
|
||||
for i := 0; i < 6; i++ {
|
||||
reg.Register(&httpmock.Stub{
|
||||
Method: "POST",
|
||||
URL: "/open-apis/drive/v1/medias/upload_part",
|
||||
Body: map[string]interface{}{"code": 0, "msg": "ok"},
|
||||
})
|
||||
}
|
||||
reg.Register(&httpmock.Stub{
|
||||
Method: "POST",
|
||||
URL: "/open-apis/drive/v1/medias/upload_finish",
|
||||
Body: map[string]interface{}{
|
||||
"code": 0,
|
||||
"data": map[string]interface{}{"file_token": "file_mem_multi"},
|
||||
},
|
||||
})
|
||||
|
||||
payload := bytes.Repeat([]byte{0xAB}, int(size))
|
||||
fileToken, err := UploadDriveMediaMultipart(runtime, DriveMediaMultipartUploadConfig{
|
||||
Content: bytes.NewReader(payload),
|
||||
FileName: "clipboard.png",
|
||||
FileSize: size,
|
||||
ParentType: "docx_image",
|
||||
ParentNode: "",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("UploadDriveMediaMultipart() error: %v", err)
|
||||
}
|
||||
if fileToken != "file_mem_multi" {
|
||||
t.Fatalf("fileToken = %q, want %q", fileToken, "file_mem_multi")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUploadDriveMediaMultipartBuildsPreparePartsAndFinish(t *testing.T) {
|
||||
runtime, reg := newDriveMediaUploadTestRuntime(t)
|
||||
withDriveMediaUploadWorkingDir(t, t.TempDir())
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/larksuite/cli/internal/cmdutil"
|
||||
"github.com/larksuite/cli/internal/core"
|
||||
)
|
||||
|
||||
@@ -37,3 +38,16 @@ func TestNewRuntimeContextWithBotInfo(cmd *cobra.Command, cfg *core.CliConfig, i
|
||||
})
|
||||
return rctx
|
||||
}
|
||||
|
||||
// TestNewRuntimeContextForAPI creates a RuntimeContext ready for HTTP tests:
|
||||
// sets Cmd, Config, Factory, context, and bot identity so callers can invoke
|
||||
// DoAPI / CallAPI directly without wiring through a cobra parent command.
|
||||
func TestNewRuntimeContextForAPI(ctx context.Context, cmd *cobra.Command, cfg *core.CliConfig, f *cmdutil.Factory) *RuntimeContext {
|
||||
return &RuntimeContext{
|
||||
ctx: ctx,
|
||||
Cmd: cmd,
|
||||
Config: cfg,
|
||||
Factory: f,
|
||||
resolvedAs: core.AsBot,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,6 +190,110 @@ func TestDocMediaInsertDryRunUsesMultipartForLargeFile(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestUploadDocMediaFileWithContentUsesSinglePartUpload(t *testing.T) {
|
||||
// Clipboard path: in-memory bytes (no FilePath) route through
|
||||
// UploadDriveMediaAll when small enough. This also exercises the
|
||||
// drive_route_token extra built from docID.
|
||||
f, _, _, reg := cmdutil.TestFactory(t, docsTestConfigWithAppID("docs-upload-content-app"))
|
||||
uploadStub := &httpmock.Stub{
|
||||
Method: "POST",
|
||||
URL: "/open-apis/drive/v1/medias/upload_all",
|
||||
Body: map[string]interface{}{
|
||||
"code": 0,
|
||||
"data": map[string]interface{}{"file_token": "file_content_123"},
|
||||
},
|
||||
}
|
||||
reg.Register(uploadStub)
|
||||
|
||||
runtime := common.TestNewRuntimeContextForAPI(
|
||||
context.Background(),
|
||||
&cobra.Command{Use: "docs +media-upload"},
|
||||
docsTestConfigWithAppID("docs-upload-content-app"),
|
||||
f,
|
||||
)
|
||||
|
||||
payload := []byte{0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a} // PNG magic bytes
|
||||
fileToken, err := uploadDocMediaFile(
|
||||
runtime,
|
||||
"", // no FilePath
|
||||
bytes.NewReader(payload),
|
||||
"clipboard.png",
|
||||
int64(len(payload)),
|
||||
"docx_image",
|
||||
"blk_parent",
|
||||
"doxcnDocID123",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("uploadDocMediaFile() error: %v", err)
|
||||
}
|
||||
if fileToken != "file_content_123" {
|
||||
t.Fatalf("fileToken = %q, want %q", fileToken, "file_content_123")
|
||||
}
|
||||
|
||||
if !strings.Contains(string(uploadStub.CapturedBody), `drive_route_token`) {
|
||||
t.Fatalf("expected drive_route_token in extra, captured body did not include it")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUploadDocMediaFileWithContentUsesMultipart(t *testing.T) {
|
||||
// Clipboard path: in-memory bytes route through UploadDriveMediaMultipart
|
||||
// when size exceeds the single-part threshold.
|
||||
f, _, _, reg := cmdutil.TestFactory(t, docsTestConfigWithAppID("docs-upload-content-multi"))
|
||||
reg.Register(&httpmock.Stub{
|
||||
Method: "POST",
|
||||
URL: "/open-apis/drive/v1/medias/upload_prepare",
|
||||
Body: map[string]interface{}{
|
||||
"code": 0,
|
||||
"data": map[string]interface{}{
|
||||
"upload_id": "upload_content_multi",
|
||||
"block_size": float64(4 * 1024 * 1024),
|
||||
"block_num": float64(6),
|
||||
},
|
||||
},
|
||||
})
|
||||
for i := 0; i < 6; i++ {
|
||||
reg.Register(&httpmock.Stub{
|
||||
Method: "POST",
|
||||
URL: "/open-apis/drive/v1/medias/upload_part",
|
||||
Body: map[string]interface{}{"code": 0, "msg": "ok"},
|
||||
})
|
||||
}
|
||||
reg.Register(&httpmock.Stub{
|
||||
Method: "POST",
|
||||
URL: "/open-apis/drive/v1/medias/upload_finish",
|
||||
Body: map[string]interface{}{
|
||||
"code": 0,
|
||||
"data": map[string]interface{}{"file_token": "file_content_multi_done"},
|
||||
},
|
||||
})
|
||||
|
||||
runtime := common.TestNewRuntimeContextForAPI(
|
||||
context.Background(),
|
||||
&cobra.Command{Use: "docs +media-upload"},
|
||||
docsTestConfigWithAppID("docs-upload-content-multi"),
|
||||
f,
|
||||
)
|
||||
|
||||
size := common.MaxDriveMediaUploadSinglePartSize + 1
|
||||
payload := bytes.Repeat([]byte{0xAB}, int(size))
|
||||
fileToken, err := uploadDocMediaFile(
|
||||
runtime,
|
||||
"",
|
||||
bytes.NewReader(payload),
|
||||
"clipboard.png",
|
||||
size,
|
||||
"docx_image",
|
||||
"blk_parent",
|
||||
"", // no docID → no extra
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("uploadDocMediaFile() error: %v", err)
|
||||
}
|
||||
if fileToken != "file_content_multi_done" {
|
||||
t.Fatalf("fileToken = %q, want %q", fileToken, "file_content_multi_done")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDocMediaInsertExecuteResolvesWikiBeforeFileCheck(t *testing.T) {
|
||||
f, _, stderr, reg := cmdutil.TestFactory(t, docsTestConfigWithAppID("docs-insert-exec-app"))
|
||||
reg.Register(&httpmock.Stub{
|
||||
|
||||
Reference in New Issue
Block a user