Files
larksuite__cli/tests/cli_e2e/drive/coverage.md
zhoujunteng-max 5b734238d7 feat: report upload file events (#2093)
* feat: report upload file events

* test(drive): skip import workflow without tenant token

* docs: document upload report helpers

* docs: improve function documentation coverage

* docs: complete incremental function documentation

* docs: complete function documentation coverage

* fix: report every upload file event

* refactor: move file event reporting to internal package

* fix: harden upload file event reporting

* fix: omit upload mode from file event reports

* test: fix workbook import dry-run token assertion
2026-08-10 19:12:38 +08:00

29 KiB

Drive CLI E2E Coverage

Metrics

  • Denominator: 46 leaf commands
  • Covered: 26
  • Coverage: 56.5%

Summary

  • TestDrive_FilesCreateFolderWorkflow: proves drive files create_folder in create_folder as bot; helper asserts the returned folder token and registers best-effort cleanup via drive files delete.
  • TestDrive_StatusWorkflow: proves drive +status against a real Drive folder. Seeds the remote side via drive +upload (unchanged.txt, modified.txt, remote-only.txt), seeds local files with the matching/diverging contents, and asserts every output bucket (unchanged, modified, new_local, new_remote) holds exactly the expected rel_path and file_token. Cleans up uploaded files and the parent folder via best-effort cleanup hooks.
  • TestDrive_UploadWorkflow: proves drive +upload against the real backend in both create and overwrite modes. First uploads a fresh file into a temporary Drive folder, then re-uploads new bytes with --file-token against the returned token, asserts the overwrite keeps the token stable, downloads the file with explicit --output to confirm the remote content changed, and downloads again without --output to prove default filename resolution saves the remote name with matching bytes.
  • TestDriveDownloadDryRun_DefaultNamePlansMetadataBeforeDownload / TestDriveDownloadDryRun_ExplicitOutputSkipsMetadata: dry-run coverage for drive +download; asserts omitted --output plans metadata before download for default naming, while explicit --output preserves the direct download-only path.
  • TestDrive_ImportWorkflow: proves drive +import against the real backend. It imports a temporary Markdown file as docx, waits for the async task when needed, verifies the returned document token, and deletes the imported document during cleanup.
  • TestDrive_DuplicateRemoteWorkflow: proves the duplicate-remote workflows against the real backend. One subtest uploads two same-name files into the same Drive folder and asserts drive +status and default drive +pull both fail with a typed validation error for the duplicate rel_path, while drive +pull --on-duplicate-remote=rename succeeds, downloads both files, and writes a hashed renamed sibling locally. The other subtest uploads duplicate remote files, runs drive +push --on-duplicate-remote=newest --if-exists=overwrite --delete-remote --yes, and then re-runs drive +status to prove the mirror converged to a single unchanged dup.txt.
  • TestDrive_ApplyPermissionDryRun / TestDrive_ApplyPermissionDryRunRejectsFullAccess / TestDrive_ApplyPermissionDryRunRejectsUnsafeTargets: dry-run coverage for drive +apply-permission; asserts URL→type inference for docx/sheet/slides, bare-token + explicit --type path, request method/URL/type-query/perm/remark body shape, optional remark omission when unset, and client-side rejection of invalid permissions, unsafe tokens, non-root URL markers, encoded path separators, and conflicting URL/--type inputs. Runs without hitting the live API.
  • TestDriveAddCommentDryRun_File / TestDriveAddCommentDryRun_Base: dry-run coverage for drive +add-comment on supported Drive file and Base targets; pins the metas.batch_query -> files/:token/new_comments file chain, Base file_type=bitable, and Base anchor fields.
  • TestDriveCopyDryRun_DocxURL / TestDriveCopyDryRun_BareTokenBaseAlias / TestDriveCopyDryRun_MySpaceTarget / TestDriveCopyDryRun_WikiURLResolvesResourceThenCopiesToDrive: dry-run coverage for drive +copy; asserts URL parsing to files/:token/copy, request body shape (name/type/folder_token, --extra key=value → extra key/value array), folder-URL target parsing, base→bitable normalization, the --folder-token my_space two-step plan (root_folder/meta -> copy with a placeholder folder_token), the bot-mode post_copy_note auto-grant notice, and the wiki URL plan (wiki get_node -> supported Drive type -> Drive copy). Unit tests pin wiki URL and --token + --type wiki, successful Sheet unwrapping, the full supported resolved-type set, and typed failed_precondition rejection for unsupported Wiki node types. Bot-mode auto-grant of the current CLI user (success, and failure staying non-fatal) is covered by unit tests via the shared permission-grant harness; source-token injection contracts (.., %2e%2e, control characters, dangerous Unicode, traversal via URL path) are pinned by unit tests against validate.ResourceName.
  • TestDrive_CopyWorkflow: proves drive +copy against the real backend. Uploads a source file into a temporary Drive folder, copies it with a new name via bare token + --type file, asserts the copy returns a distinct token with the requested name, downloads the copy, and verifies the content matches the source; a second copy targets --folder-token my_space and asserts the output carries the resolved root token instead of the sentinel. All copies and the folder are removed via best-effort cleanup hooks. The root-folder-meta resolution endpoint (absent from platform metadata) was live-verified for both user and bot identities. Direct Drive URL input and output shape were manually live-probed; wiki document unwrapping is currently covered by mocked unit tests plus dry-run orchestration, not a live fixture. Error codes in the skill reference were also live-probed: nonexistent source token → 1061003, --type mismatch (docx declared as sheet) → 1061003 (not 1061002 — the server looks the token up under the declared type).
  • TestDriveListCommentsDryRun_DocxDefaults / TestDriveListCommentsDryRun_AppsPageURL / TestDriveListCommentsDryRun_WikiToken: dry-run coverage for drive +list-comments; asserts URL parsing to files/:token/comments, apps /page/<token> URL parsing with file_type=apps, default is_solved=false, default omitted is_whole and user_id_type, and Wiki token orchestration (get_node -> comments.list) without live API calls.
  • TestDrive_CommentOpsDryRun: dry-run coverage for drive +batch-query-comments, drive +resolve-comment, drive +restore-comment, drive +add-reply, drive +list-replies, drive +update-reply, drive +delete-reply, and drive +react-reply; asserts URL→type inference (incl. Miaoda apps /page/<token> → file_type=apps and Base /base/ → file_type=bitable), file_type/page_size/need_reaction/need_relation (docx-gated) query wiring, comment_ids / is_solved / reply content.elements[] (text_run) / reaction action+reaction_type+reply_id body shapes, resolved :comment_id/:reply_id path segments, the Wiki get_node -> batch_query / get_node -> replies list / get_node -> v2 reaction orchestration plans, and the batch_query wiki dry-run surfacing need_relation as the <sent only when obj_type is docx> placeholder, without live API calls. All eight verified manually against live documents (list → batch-query → add-reply → list-replies → update-reply → react add/delete → resolve/restore → delete-reply round trip; root-reply update rewriting the comment body, the 1069303 forbidden cross-identity update rejection, the server persisting arbitrary reaction_type strings, and count=0 reaction tombstones were probed live as well).
  • TestDriveAddCommentMarkdownFileWorkflow: opt-in live workflow skeleton for comment write/read, gated by LARK_DRIVE_MD_COMMENT_E2E=1; creates a Markdown file, adds a file comment, lists it back through drive +list-comments, and cleans up.
  • TestDriveCommentOpsWorkflow: opt-in self-contained live workflow for the comment operation shortcuts, gated by LARK_DRIVE_MD_COMMENT_E2E=1; creates a Markdown file + file comment fixture, then +batch-query-comments finds it by ID, +add-reply attaches a reply, +list-replies surfaces it, +update-reply rewrites its content (confirmed by polling +list-replies until the new text lands), +react-reply attaches then removes a THUMBSUP reaction (confirmed by polling +list-replies --need-reaction, judging presence by count>0 because deleted reactions linger as count=0 entries), +resolve-comment marks it solved and +restore-comment reopens it (with polling reads between state flips to absorb rate limiting), +delete-reply --yes removes the created reply, and cleanup deletes the file.
  • TestDrive_SecureLabelDryRun: dry-run coverage for drive +secure-label-list and drive +secure-label-update; asserts label-list query params and update URL→type inference, request method/URL/type query, and label-id body shape. Runs without hitting live APIs because update can trigger document-level security approval flows.
  • TestDriveExportDryRun_FileNameMetadata / TestDriveExportDryRun_WikiURLPlansResolveBeforeExportTask / TestDriveExportDryRun_WikiTokenTypePlansResolveBeforeExportTask / TestDriveExportDryRun_MarkdownFetchAPI / TestDriveExportDryRun_BitableBaseOnlySchema: dry-run coverage for drive +export; asserts export task request shape, Wiki URL and --doc-type wiki token get_node -> export_tasks planning, markdown fetch request shape without docs fetch extra_param, local --file-name / --output-dir metadata, and bitable .base only_schema request body without calling live APIs.
  • TestDriveDeleteDryRunAsyncParams / TestDrive_DeleteAsyncWorkflow: dry-run coverage for drive +delete pins DELETE /drive/v1/files/:file_token params with type plus async=true and the follow-up task_check plan; live workflow creates and deletes a docx, an empty folder, and a non-empty folder, converging every delete outcome to the resource-gone terminal state: async deletes (non-empty task_id) are verified via drive +task_result --scenario task_check, sync deletes (empty task_id) assert deleted=true, and the one verified backend transient (server_error: "drive task failed") passes once the target is confirmed gone (retried up to 3 times otherwise); any other delete failure stays fatal.
  • TestDriveUpdateTitleDryRun_DocxURL / TestDriveUpdateTitleDryRun_BareTokenTypes / TestDriveUpdateTitleDryRun_FileExtensionGuardPlan / TestDriveUpdateTitleDryRun_RejectsRemovedErrorPolicy / TestDriveUpdateTitleDryRun_RejectsExtensionPolicyOnNonFileType / TestDriveUpdateTitleDryRun_WikiURLKeepsNodeToken / TestDriveUpdateTitleDryRun_RejectsEmptyTitle / TestDriveUpdateTitleDryRun_RejectsTypeConflict: dry-run coverage for drive +update-title; asserts URL→type inference into PATCH /drive/v1/files/:file_token with the type query and new_title body, bare-token --type handling for base→bitable and folder, the --new-title alias, the single-request wiki plan that keeps the node token (no get_node unwrap step), the --type file two-step plan (metas.batch_query for the extension guard, then the rename) collapsing to one request under --on-extension-mismatch=allow, rejection of the removed error policy, the Miaoda apps redirect (both a /page/ URL and --type apps fail locally with a hint pointing at the apps domain), the local rejection of the server-refused doc and mindnote types (both --type and URL spellings), and the local rejections for a whitespace-only title, a --type that conflicts with the URL path type, and --on-extension-mismatch paired with a non-file type.
  • TestDrive_UpdateTitleWorkflow: proves drive +update-title against the real backend. Uploads a file into a temporary Drive folder, renames it with an extension-preserving title, reads the title back through drive +inspect, then exercises both extension policies on the same file: default keep (title without extension gets .txt appended, extension_appended/previous_title reported, name verified) and allow (title submitted verbatim, extension dropped on purpose, no previous_title because the guard skips the read). Then renames the containing folder (token stays stable, so the cleanup hook still resolves it) and re-reads that title too. A final negative leg renames the file with --type docx and asserts the endpoint answers 981003 while the name stays untouched. Live-probed manually beforehand as user before the assertions were encoded: type=docx / type=folder / type=file / type=wiki renames, that type=wiki needs the wiki node token (the underlying document token returns 981003), that wiki node and underlying docx titles stay in sync in both directions, that a --type mismatch and an unknown token share code 981003, that a bot without edit permission gets 981004, that an empty new_title is accepted by the server and blanks the title (hence the local --title guard), and that a type=file title without an extension drops the extension server-side (hence the extension guard). Error-scenario guidance was probed the same way rather than assumed: renaming a document the identity cannot edit returns 981004 forbidden for both user and bot (a document-permission failure, not a scope one), a 25-request burst against the endpoint returns 99991400 request trigger frequency limit (classified api/rate_limit, retryable) for the requests over the limit, and the platform's missing-scope shapes were read off a scope the app does not hold: 99991679 for a user token (envelope carries missing_scopes plus an auth login --scope hint) and 99991672 for an app scope that was never applied. Titles are stored verbatim — a new_title of " spaced title " reads back with both pads intact — which is why the CLI trims --title before sending it. doc and mindnote are listed by the platform metadata but refused by the backend: the service log for a real mindnote token records unsupported update file type=mindnote and answers 981002 params error before any token lookup, and probes confirm the type is what fails — a real docx token renames fine under --type docx yet returns 981002 under --type doc or --type mindnote, while unknown tokens under supported types return 981003. Both are therefore refused locally. Miaoda apps were probed the same way: type=apps is rejected by gateway field validation (99992402, the same answer a nonsense type gets) while a supported type with an unknown token answers 981003, which is why the CLI rejects apps inputs and points at the apps domain instead of forwarding them. Rate-limit and scope failures are not asserted in the live workflow — one would need a deliberate burst, the other a second app — so their guidance is unit-tested against the codes instead.
  • TestDrive_PullDryRun / TestDrive_PullDryRunAcceptsDuplicateRemoteStrategies: dry-run coverage for drive +pull; asserts the list-files request shape, Validate-stage safety guards, and acceptance of --on-duplicate-remote=rename|newest|oldest by the real CLI binary.
  • TestDrive_PushDryRun / TestDrive_PushDryRunAcceptsDuplicateRemoteStrategies: dry-run coverage for drive +push; asserts the list-files request shape, Validate-stage safety guards, conditional delete preflight, and acceptance of --on-duplicate-remote=newest|oldest by the real CLI binary.
  • Cleanup note: drive files delete is only exercised in cleanup and is intentionally left uncovered.
  • Blocked area: live export, permission, subscription, reply, and file comment API flows still need deterministic remote fixtures and filesystem setup.
  • Dry-run note: drive_upload_dryrun_test.go::TestDriveUploadDryRun_WikiTarget and TestDriveUploadDryRun_WithFileToken cover the wiki-target and overwrite request shapes for drive +upload; live upload/status/duplicate workflows also use real +upload against the backend.

Command Table

Status Cmd Type Testcase Key parameter shapes Notes / uncovered reason
✓ drive +add-comment shortcut drive_add_comment_dryrun_test.go::TestDriveAddCommentDryRun_File; drive_add_comment_dryrun_test.go::TestDriveAddCommentDryRun_Base --doc file URL vs bare token + --type file; supported-extension metadata gate; placeholder anchor.block_id; Base URL with --block-id <table-id>!<record-id>!<view-id> dry-run coverage in place; opt-in live file workflow exists behind LARK_DRIVE_MD_COMMENT_E2E=1
✓ drive +list-comments shortcut drive_list_comments_dryrun_test.go::TestDriveListCommentsDryRun_DocxDefaults; drive_list_comments_dryrun_test.go::TestDriveListCommentsDryRun_AppsPageURL; drive_list_comments_dryrun_test.go::TestDriveListCommentsDryRun_WikiToken; drive_add_comment_workflow_test.go::TestDriveAddCommentMarkdownFileWorkflow --url; apps /page/<token> URL; --token + --type wiki; --solved-status=false|all; --comment-scope=all|partial; --need-relation; --page-size dry-run locks URL/token parsing, apps file_type=apps, default unresolved filter, omitted all-scope filter, omitted user_id_type, and Wiki unwrap request shape; opt-in live workflow verifies a created file comment can be listed back
✓ drive +batch-query-comments shortcut drive_comment_ops_dryrun_test.go::TestDrive_CommentOpsDryRun; drive_comment_ops_workflow_test.go::TestDriveCommentOpsWorkflow --url docx; base /base/ URL (file_type=bitable); apps /page/<token> URL (file_type=apps); --token + --type wiki; --comment-ids CSV; --need-reaction body flag; --need-relation body flag (docx only, omitted otherwise) dry-run pins request shape and wiki resolve plan; opt-in live workflow covers the full comment-ops round trip; need_relation is metadata-absent but live-verified (returns relation with block position)
✓ drive +resolve-comment shortcut drive_comment_ops_dryrun_test.go::TestDrive_CommentOpsDryRun; drive_comment_ops_workflow_test.go::TestDriveCommentOpsWorkflow --url sheet; --comment-id path segment; fixed is_solved=true body dry-run pins request shape; opt-in live workflow marks the fixture comment solved against the real backend
✓ drive +restore-comment shortcut drive_comment_ops_dryrun_test.go::TestDrive_CommentOpsDryRun; drive_comment_ops_workflow_test.go::TestDriveCommentOpsWorkflow --url docx; --comment-id path segment; fixed is_solved=false body (same patch endpoint as +resolve-comment) dry-run pins request shape; opt-in live workflow reopens the solved fixture comment against the real backend
✓ drive +add-reply shortcut drive_comment_ops_dryrun_test.go::TestDrive_CommentOpsDryRun; drive_comment_ops_workflow_test.go::TestDriveCommentOpsWorkflow --url docx; --comment-id path segment (.../comments/:comment_id/replies); --content simplified elements → content.elements[] text_run dry-run pins reply body mapping; opt-in live workflow attaches and verifies a real reply (body-comment_id create variant does NOT reply — creates a standalone comment)
✓ drive +list-replies shortcut drive_comment_ops_dryrun_test.go::TestDrive_CommentOpsDryRun; drive_comment_ops_workflow_test.go::TestDriveCommentOpsWorkflow --url docx; --token + --type wiki resolve plan; --comment-id path segment (.../comments/:comment_id/replies GET); --page-size/--page-token/--need-reaction query dry-run pins request shape and wiki resolve plan; opt-in live workflow lists the created reply back (the first-page items[0] is the root reply carrying the comment body)
✓ drive +update-reply shortcut drive_comment_ops_dryrun_test.go::TestDrive_CommentOpsDryRun; drive_comment_ops_workflow_test.go::TestDriveCommentOpsWorkflow base /base/ URL (file_type=bitable); --comment-id + --reply-id path segments (PUT); --content simplified elements → content.elements[] text_run dry-run pins request/body shape; opt-in live workflow rewrites the created reply and polls +list-replies until the new text is visible; only the creator identity may update (live-probed 1069303 forbidden)
✓ drive +delete-reply shortcut drive_comment_ops_dryrun_test.go::TestDrive_CommentOpsDryRun; drive_comment_ops_workflow_test.go::TestDriveCommentOpsWorkflow --url docx; --comment-id + --reply-id path segments; --dry-run bypasses the --yes gate dry-run pins request shape; opt-in live workflow deletes the created reply and verifies the count returns to baseline
✓ drive +react-reply shortcut drive_comment_ops_dryrun_test.go::TestDrive_CommentOpsDryRun; drive_comment_ops_workflow_test.go::TestDriveCommentOpsWorkflow --url docx; --token + --type wiki resolve plan; v2 .../comments/reaction POST; --reply-id/--emoji/--action add|delete → body reply_id/reaction_type/action dry-run pins request/body shape and wiki resolve plan; opt-in live workflow adds then removes a reaction, polling +list-replies --need-reaction with count>0 presence checks; local --emoji enum validation guards the unvalidated server field
✓ drive +apply-permission shortcut drive_apply_permission_dryrun_test.go::TestDrive_ApplyPermissionDryRun --token URL vs bare; --type (enum) with URL inference; --perm view|edit; --remark optional dry-run only; no live-apply E2E because a real request pushes a card to the owner
✓ drive +copy shortcut drive_copy_dryrun_test.go::TestDriveCopyDryRun_DocxURL; drive_copy_dryrun_test.go::TestDriveCopyDryRun_BareTokenBaseAlias; drive_copy_dryrun_test.go::TestDriveCopyDryRun_WikiURLResolvesResourceThenCopiesToDrive; drive_copy_workflow_test.go::TestDrive_CopyWorkflow --url doc/wiki URL vs bare --token + --type; --type base alias; --name body; --folder-token URL vs bare vs my_space sentinel; --extra key=value passthrough; wiki URL/token unwrap to any Drive Copy-supported source type dry-run locks request shape, the my_space plan, and wiki get_node -> Drive copy orchestration; unit tests pin supported-type passthrough and unsupported-type rejection; live workflow copies an uploaded file, verifies content via download, and copies into the resolved My Space root; --extra body shape confirmed against the live API (docx copy with target_type=docx)
✓ drive +delete shortcut drive_delete_dryrun_test.go::TestDriveDeleteDryRunAsyncParams + drive_delete_workflow_test.go::TestDrive_DeleteAsyncWorkflow --file-token; --type; fixed query async=true; task_check follow-up dry-run locks async request shape; live workflow covers docx, empty folder, and non-empty folder deletion with async/sync/transient-failure convergence
✓ drive +download shortcut drive_download_dryrun_test.go::TestDriveDownloadDryRun_DefaultNamePlansMetadataBeforeDownload; drive_download_dryrun_test.go::TestDriveDownloadDryRun_ExplicitOutputSkipsMetadata; drive_upload_workflow_test.go::TestDrive_UploadWorkflow omitted --output plans metas.batch_query before file download; explicit --output skips metadata; live workflow downloads an uploaded file both with explicit output and with default remote-name output dry-run plus live fixture coverage
✓ drive +export shortcut drive_export_dryrun_test.go::TestDriveExportDryRun_FileNameMetadata + TestDriveExportDryRun_WikiURLPlansResolveBeforeExportTask + TestDriveExportDryRun_WikiTokenTypePlansResolveBeforeExportTask + TestDriveExportDryRun_MarkdownFetchAPI + TestDriveExportDryRun_BitableBaseOnlySchema --url; --token; --doc-type; --file-extension; --file-name; --output-dir; --only-schema; Wiki URL / --doc-type wiki resolve step; markdown fetch omits docs fetch extra_param dry-run only; no live export workflow yet
✕ drive +export-download shortcut none no export-download workflow yet
✓ drive +import shortcut drive_import_dryrun_test.go::TestDriveImportDryRunFolderTokenWikiProbe + drive_import_workflow_test.go::TestDrive_ImportWorkflow --file; --type docx; upload report request shape; async ticket polling; imported token cleanup dry-run pins the upload/report/import request chain; live workflow imports a real Markdown fixture and deletes the resulting docx
✕ drive +move shortcut none no move workflow yet
✓ drive +pull shortcut drive_pull_dryrun_test.go::TestDrive_PullDryRun + drive_duplicate_sync_workflow_test.go::TestDrive_DuplicateRemoteWorkflow --local-dir; --folder-token; --on-duplicate-remote=rename|newest|oldest; --delete-local --yes guard dry-run locks flag/validate shape; live workflow proves duplicate fail-fast and rename recovery
✓ drive +push shortcut drive_push_dryrun_test.go::TestDrive_PushDryRun + drive_duplicate_sync_workflow_test.go::TestDrive_DuplicateRemoteWorkflow --local-dir; --folder-token; --if-exists; --on-duplicate-remote=newest|oldest; --delete-remote --yes dry-run locks flag/validate shape; live workflow proves overwrite + duplicate cleanup converges status
✓ drive +secure-label-list shortcut drive_secure_label_dryrun_test.go::TestDrive_SecureLabelDryRun --page-size; --page-token; --lang dry-run only; live label availability depends on tenant security-label configuration
✓ drive +secure-label-update shortcut drive_secure_label_dryrun_test.go::TestDrive_SecureLabelDryRun --token URL inference; --type; --label-id body dry-run only; live update can require document-level approval or mutate a fixture document's security level
✓ drive +status shortcut drive_status_workflow_test.go::TestDrive_StatusWorkflow + drive_status_dryrun_test.go::TestDrive_StatusDryRun + drive_duplicate_sync_workflow_test.go::TestDrive_DuplicateRemoteWorkflow --local-dir; --folder-token; bucketed new_local / new_remote / modified / unchanged outputs dry-run pins request shape; live workflows cover both normal hashing buckets and duplicate-remote failure
✓ drive +sync shortcut drive_sync_dryrun_test.go::TestDrive_SyncDryRun + drive_sync_workflow_test.go::TestDrive_SyncWorkflow + drive_sync_workflow_test.go::TestDrive_SyncEmptyDirWorkflow --local-dir; --folder-token; --on-conflict=remote-wins|local-wins|keep-both|ask; --on-duplicate-remote=fail|newest|oldest; --quick dry-run validates request shape, flag acceptance, and path safety guards; live workflow proves new_remote→pull, new_local→push, remote-wins/local-wins/keep-both conflict resolution, empty directory creation, and post-sync convergence
✓ drive +task_result shortcut drive_delete_workflow_test.go::TestDrive_DeleteAsyncWorkflow --scenario task_check; --task-id live delete workflow verifies task polling command can read returned delete tasks
✓ drive +update-title shortcut drive_update_title_dryrun_test.go::TestDriveUpdateTitleDryRun_DocxURL; drive_update_title_dryrun_test.go::TestDriveUpdateTitleDryRun_BareTokenTypes; drive_update_title_dryrun_test.go::TestDriveUpdateTitleDryRun_FileExtensionGuardPlan; drive_update_title_dryrun_test.go::TestDriveUpdateTitleDryRun_RejectsRemovedErrorPolicy; drive_update_title_dryrun_test.go::TestDriveUpdateTitleDryRun_WikiURLKeepsNodeToken; drive_update_title_workflow_test.go::TestDrive_UpdateTitleWorkflow --url vs bare --token + --type; --type base alias → bitable; --type folder / file / wiki; type query param; --title (alias --new-title) → body new_title; --on-extension-mismatch=keep|allow (file only, metas.batch_query pre-read); removed error policy, whitespace-only title, URL/--type conflict and non-file extension policy rejected locally dry-run locks request shape, the wiki single-request plan and the file two-step guard plan; live workflow renames a file and its folder, walks both extension policies, verifies titles via drive +inspect, and pins the 981003 type-mismatch failure
✓ drive +upload shortcut drive_upload_dryrun_test.go::TestDriveUploadDryRun_WikiTarget + drive_upload_dryrun_test.go::TestDriveUploadDryRun_WithFileToken + drive_upload_workflow_test.go::TestDrive_UploadWorkflow + drive_status_workflow_test.go::TestDrive_StatusWorkflow + drive_duplicate_sync_workflow_test.go::TestDrive_DuplicateRemoteWorkflow --wiki-token; --file-token; parent_type=wiki; parent_node; named uploads into Drive folders; in-place overwrite uploads dry-run covers wiki-target and overwrite request shapes; live workflows assert returned file tokens, token-stable overwrite behavior, and that uploaded fixtures are consumable by downstream commands
✕ drive file.comment.replys create api none no reply workflow yet
✕ drive file.comment.replys delete api none no reply workflow yet
✕ drive file.comment.replys list api none no reply workflow yet
✕ drive file.comment.replys update api none no reply workflow yet
✕ drive file.comments create_v2 api none no file comment workflow yet
✕ drive file.comments list api none no file comment workflow yet
✕ drive file.comments patch api none no file comment workflow yet
✕ drive file.statistics get api none no statistics workflow yet
✕ drive file.view_records list api none no view-record workflow yet
✕ drive files copy api none endpoint exercised live through drive +copy (TestDrive_CopyWorkflow); the raw service command itself has no workflow
✓ drive files create_folder api drive_files_workflow_test.go::TestDrive_FilesCreateFolderWorkflow/create_folder as bot name; empty folder_token in --data
✕ drive files list api none no list workflow yet
✕ drive metas batch_query api none no metadata workflow yet
✕ drive permission.members auth api none permission workflows not covered
✕ drive permission.members create api none permission workflows not covered
✕ drive permission.members transfer_owner api none permission workflows not covered
✕ drive user remove_subscription api none subscription workflows not covered
✕ drive user subscription api none subscription workflows not covered
✕ drive user subscription_status api none subscription workflows not covered