Files
dingtalk-workspace-cli/internal/helpers/drive_depth_test.go

814 lines
28 KiB
Go

package helpers
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"os"
"strings"
"testing"
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/pkg/edition"
"github.com/spf13/cobra"
)
func driveDepthTestCmd() *cobra.Command {
cmd := &cobra.Command{Use: "list"}
cmd.Flags().String("cursor", "", "")
cmd.Flags().String("next-token", "", "")
cmd.Flags().Int("limit", 0, "")
cmd.Flags().Int("max", 0, "")
return cmd
}
func TestCrossPlatformCoverageDriveDepthCancelledError(t *testing.T) {
err := &driveDepthCancelledError{}
if err.Error() != driveDepthCancelledMsg || err.RawStderr() != driveDepthCancelledMsg {
t.Fatalf("messages = %q/%q", err.Error(), err.RawStderr())
}
if err.ExitCode() != 130 {
t.Fatalf("ExitCode = %d, want 130", err.ExitCode())
}
}
func TestCrossPlatformCoverageValidateDriveListDepth(t *testing.T) {
newCmd := func() *cobra.Command { return driveDepthTestCmd() }
if err := validateDriveListDepth(newCmd(), 0); err == nil {
t.Fatal("depth 0 returned nil")
}
if err := validateDriveListDepth(newCmd(), driveDepthMax+1); err == nil {
t.Fatal("depth above max returned nil")
}
shallow := newCmd()
_ = shallow.Flags().Set("cursor", "c1")
_ = shallow.Flags().Set("limit", "5")
if err := validateDriveListDepth(shallow, 1); err != nil {
t.Fatalf("depth 1 with cursor/limit returned %v", err)
}
withCursor := newCmd()
_ = withCursor.Flags().Set("cursor", "c1")
if err := validateDriveListDepth(withCursor, 2); err == nil {
t.Fatal("depth 2 with cursor returned nil")
}
withNextToken := newCmd()
_ = withNextToken.Flags().Set("next-token", "t1")
if err := validateDriveListDepth(withNextToken, 2); err == nil {
t.Fatal("depth 2 with next-token returned nil")
}
withLimit := newCmd()
_ = withLimit.Flags().Set("limit", "5")
if err := validateDriveListDepth(withLimit, 2); err == nil {
t.Fatal("depth 2 with limit returned nil")
}
withMax := newCmd()
_ = withMax.Flags().Set("max", "5")
if err := validateDriveListDepth(withMax, 2); err == nil {
t.Fatal("depth 2 with max returned nil")
}
if err := validateDriveListDepth(newCmd(), 2); err != nil {
t.Fatalf("depth 2 clean returned %v", err)
}
if err := validateDriveListDepth(newCmd(), driveDepthMax); err != nil {
t.Fatalf("depth max clean returned %v", err)
}
}
func TestCrossPlatformCoverageDriveDepthRoutesBuildArgs(t *testing.T) {
pan := newDrivePanDepthRoute()
args := pan.buildArgs(map[string]any{"spaceId": "s1"}, "folder1", "tok")
if args["maxResults"] != float64(driveDepthPageSize) || args["spaceId"] != "s1" ||
args["parentId"] != "folder1" || args["nextToken"] != "tok" {
t.Fatalf("pan args = %#v", args)
}
empty := pan.buildArgs(nil, "", "")
if _, ok := empty["parentId"]; ok {
t.Fatalf("pan empty folder args = %#v", empty)
}
if _, ok := empty["nextToken"]; ok {
t.Fatalf("pan empty token args = %#v", empty)
}
if id := pan.itemID(map[string]any{"fileId": "f1"}); id != "f1" {
t.Fatalf("pan itemID = %q", id)
}
if id := pan.itemID(map[string]any{}); id != "" {
t.Fatalf("pan missing itemID = %q", id)
}
doc := newDocDepthRoute()
dargs := doc.buildArgs(map[string]any{"workspaceId": "w1"}, "node1", "pt")
if dargs["pageSize"] != float64(docDepthPageSize) || dargs["workspaceId"] != "w1" ||
dargs["folderId"] != "node1" || dargs["pageToken"] != "pt" {
t.Fatalf("doc args = %#v", dargs)
}
dempty := doc.buildArgs(nil, "", "")
if _, ok := dempty["folderId"]; ok {
t.Fatalf("doc empty folder args = %#v", dempty)
}
if id := doc.itemID(map[string]any{"nodeId": "n1"}); id != "n1" {
t.Fatalf("doc itemID = %q", id)
}
if id := doc.itemID(map[string]any{}); id != "" {
t.Fatalf("doc missing itemID = %q", id)
}
}
func TestCrossPlatformCoverageParseDriveDepthPage(t *testing.T) {
if items, next, hasMore := parseDriveDepthPage(`{invalid`); items != nil || next != "" || hasMore {
t.Fatalf("invalid JSON = %#v %q %v", items, next, hasMore)
}
if items, _, _ := parseDriveDepthPage(`{"foo":1}`); items != nil {
t.Fatalf("missing items key = %#v", items)
}
items, next, hasMore := parseDriveDepthPage(`{"items":[{"name":"a"},42],"nextToken":"t","hasMore":true}`)
if len(items) != 1 || items[0]["name"] != "a" || next != "t" || !hasMore {
t.Fatalf("top-level items = %#v %q %v", items, next, hasMore)
}
items, next, _ = parseDriveDepthPage(`{"result":{"dentryList":[{"name":"b"}],"nextToken":"t2"}}`)
if len(items) != 1 || items[0]["name"] != "b" || next != "t2" {
t.Fatalf("result dentryList = %#v %q", items, next)
}
if items, _, _ := parseDriveDepthPage(`{"result":{"other":1}}`); items != nil {
t.Fatalf("result without items = %#v", items)
}
}
func TestCrossPlatformCoverageDriveDepthListItemsKey(t *testing.T) {
if k := driveDepthListItemsKey(map[string]any{"items": []any{}}); k != "items" {
t.Fatalf("items key = %q", k)
}
if k := driveDepthListItemsKey(map[string]any{"dentryList": []any{1}}); k != "dentryList" {
t.Fatalf("dentryList key = %q", k)
}
if k := driveDepthListItemsKey(map[string]any{"items": nil}); k != "" {
t.Fatalf("nil items key = %q", k)
}
if k := driveDepthListItemsKey(map[string]any{}); k != "" {
t.Fatalf("missing key = %q", k)
}
}
func TestCrossPlatformCoverageParseDocDepthPage(t *testing.T) {
if items, next, hasMore := parseDocDepthPage(`{bad`); items != nil || next != "" || hasMore {
t.Fatalf("invalid JSON = %#v %q %v", items, next, hasMore)
}
items, next, hasMore := parseDocDepthPage(`{"nodes":[{"name":"a"},"x"],"nextPageToken":"nt","hasMore":true}`)
if len(items) != 1 || next != "nt" || !hasMore {
t.Fatalf("nodes = %#v %q %v", items, next, hasMore)
}
}
func TestCrossPlatformCoverageMatchDriveNamePattern(t *testing.T) {
if !matchDriveNamePattern("anything", "") {
t.Fatal("empty pattern should match")
}
if !matchDriveNamePattern("report.xlsx", "*.xlsx") || matchDriveNamePattern("report.csv", "*.xlsx") {
t.Fatal("glob match failed")
}
if !matchDriveNamePattern("weekly-report.xlsx", "report") || matchDriveNamePattern("a.txt", "report") {
t.Fatal("substring wrap failed")
}
if !matchDriveNamePattern("a[b", "[") {
t.Fatal("invalid pattern should fall back to substring")
}
}
func TestCrossPlatformCoverageDriveDepthItemClassifiers(t *testing.T) {
if !isDriveDepthFolder(map[string]any{"type": "FOLDER"}) {
t.Fatal("type FOLDER not detected")
}
if !isDriveDepthFolder(map[string]any{"dentryType": "folder"}) {
t.Fatal("dentryType folder not detected")
}
if isDriveDepthFolder(map[string]any{"type": "FILE"}) || isDriveDepthFolder(map[string]any{}) {
t.Fatal("non-folder detected as folder")
}
if !isDocDepthFolder(map[string]any{"nodeType": "Folder"}) {
t.Fatal("doc folder not detected")
}
if isDocDepthFolder(map[string]any{"nodeType": "doc"}) {
t.Fatal("doc detected as folder")
}
if id := driveDepthItemID(map[string]any{"fileId": "f"}); id != "f" {
t.Fatalf("fileId = %q", id)
}
if id := driveDepthItemID(map[string]any{"nodeId": "n"}); id != "n" {
t.Fatalf("nodeId = %q", id)
}
if id := driveDepthItemID(map[string]any{"fileId": ""}); id != "" {
t.Fatalf("empty = %q", id)
}
}
func TestCrossPlatformCoverageDriveDepthUnrecoverable(t *testing.T) {
for _, code := range []string{CodeAuthTokenExpired, CodeAuthNotConfigured, CodeNetworkTimeout, CodeNetworkUnreachable} {
if !driveDepthUnrecoverable(&CLIError{Code: code}) {
t.Fatalf("%s not unrecoverable", code)
}
}
if driveDepthUnrecoverable(&CLIError{Code: CodeMCPToolError}) {
t.Fatal("tool error marked unrecoverable")
}
if driveDepthUnrecoverable(errors.New("plain")) {
t.Fatal("plain error marked unrecoverable")
}
}
func TestCrossPlatformCoverageDriveDepthErrorCode(t *testing.T) {
if c := driveDepthErrorCode(errors.New("plain")); c != "" {
t.Fatalf("plain = %q", c)
}
if c := driveDepthErrorCode(&CLIError{Message: "not json"}); c != "" {
t.Fatalf("non-JSON = %q", c)
}
for _, tc := range []struct{ body, want string }{
{`{"errorCode":"a.b"}`, "a.b"},
{`{"error_code":"c.d"}`, "c.d"},
{`{"code":"e.f"}`, "e.f"},
{`{"errorCode":""}`, ""},
} {
if c := driveDepthErrorCode(&CLIError{Message: tc.body}); c != tc.want {
t.Fatalf("%s = %q, want %q", tc.body, c, tc.want)
}
}
}
func TestCrossPlatformCoverageClassifyDriveDepthReason(t *testing.T) {
if r := classifyDriveDepthReason(driveDepthRateLimitedCode); r != "rate_limited" {
t.Fatalf("rate limit = %q", r)
}
if r := classifyDriveDepthReason("forbidden.noPermission"); r != "permission_denied" {
t.Fatalf("forbidden = %q", r)
}
if r := classifyDriveDepthReason("other.x"); r != "api_error" {
t.Fatalf("other = %q", r)
}
}
func TestCrossPlatformCoverageDriveDepthErrorMessage(t *testing.T) {
if m := driveDepthErrorMessage(&CLIError{Message: `{"errorMsg":"boom"}`}); m != "boom" {
t.Fatalf("errorMsg = %q", m)
}
if m := driveDepthErrorMessage(&CLIError{Message: `{"message":"m2"}`}); m != "m2" {
t.Fatalf("message = %q", m)
}
if m := driveDepthErrorMessage(&CLIError{Message: "raw text"}); m != "raw text" {
t.Fatalf("raw = %q", m)
}
if m := driveDepthErrorMessage(errors.New("plain boom")); m != "plain boom" {
t.Fatalf("plain = %q", m)
}
}
func TestCrossPlatformCoverageNewDriveDepthError(t *testing.T) {
folder := driveDepthFolder{id: "f1", name: "folder one", depth: 2}
derr := newDriveDepthError(folder, &CLIError{Code: CodeMCPToolError, Message: `{"errorCode":"forbidden.x","errorMsg":"denied"}`})
if derr.Depth != 2 || derr.FolderID != "f1" || derr.FolderName != "folder one" ||
derr.Reason != "permission_denied" || derr.Message != "denied" {
t.Fatalf("driveDepthError = %#v", derr)
}
}
type failingWriter struct{}
func (failingWriter) Write([]byte) (int, error) { return 0, errors.New("write failed") }
func installDepthCaller(t *testing.T, caller *scriptedToolCaller) *bytes.Buffer {
t.Helper()
installScriptedCaller(t, caller)
buf := &bytes.Buffer{}
deps.Out.w = buf
return buf
}
func decodeDepthResult(t *testing.T, buf *bytes.Buffer) map[string]any {
t.Helper()
var out map[string]any
if err := json.Unmarshal(buf.Bytes(), &out); err != nil {
t.Fatalf("output is not JSON: %v\n%s", err, buf.String())
}
return out
}
func TestCrossPlatformCoverageEmitDriveDepthResult(t *testing.T) {
out := installDepthCaller(t, &scriptedToolCaller{})
items := []map[string]any{
{"fileName": "b-file.xlsx", "rel_path": "b", "depth": 1, "fileId": "f2"},
{"name": "a-file.xlsx", "rel_path": "a", "depth": 2, "fileId": "f1"},
{"name": "skip-me.csv", "rel_path": "c", "depth": 1, "fileId": "f3"},
}
if err := emitDriveDepthResult(items, nil, false, "*.xlsx", 0, 0, newDrivePanDepthRoute(), driveListFilter{}); err != nil {
t.Fatal(err)
}
result := decodeDepthResult(t, out)
got := result["items"].([]any)
if len(got) != 2 {
t.Fatalf("filtered items = %#v", got)
}
if got[0].(map[string]any)["rel_path"] != "a" || got[1].(map[string]any)["rel_path"] != "b" {
t.Fatalf("sort order = %#v", got)
}
if result["maxDepth"] != float64(2) {
t.Fatalf("maxDepth = %#v", result["maxDepth"])
}
if result["truncated"] != false {
t.Fatalf("truncated = %#v", result["truncated"])
}
out.Reset()
if err := emitDriveDepthResult(nil, nil, false, "", 0, 0, newDrivePanDepthRoute(), driveListFilter{}); err != nil {
t.Fatal(err)
}
result = decodeDepthResult(t, out)
if items, ok := result["items"].([]any); !ok || len(items) != 0 {
t.Fatalf("nil items = %#v", result["items"])
}
samePath := []map[string]any{
{"name": "dup", "rel_path": "p/dup", "fileId": "z9"},
{"name": "dup", "rel_path": "p/dup", "fileId": "a1"},
}
out.Reset()
if err := emitDriveDepthResult(samePath, nil, false, "", 0, 0, newDrivePanDepthRoute(), driveListFilter{}); err != nil {
t.Fatal(err)
}
got = decodeDepthResult(t, out)["items"].([]any)
if got[0].(map[string]any)["fileId"] != "a1" {
t.Fatalf("tie-break order = %#v", got)
}
deps.Out.w = failingWriter{}
if err := emitDriveDepthResult(nil, nil, false, "", 0, 0, newDrivePanDepthRoute(), driveListFilter{}); err == nil {
t.Fatal("failing writer returned nil")
}
}
func TestCrossPlatformCoveragePrintDriveDepthDryRun(t *testing.T) {
jsonOut := installDepthCaller(t, &scriptedToolCaller{format: "json", dry: true})
if err := printDriveDepthDryRun(newDrivePanDepthRoute(), map[string]any{"spaceId": "s1"}, 3); err != nil {
t.Fatal(err)
}
var payload map[string]any
if err := json.Unmarshal(jsonOut.Bytes(), &payload); err != nil {
t.Fatalf("json dry-run output: %v", err)
}
if payload["dry_run"] != true || payload["tool"] != "list_files" || payload["maxDepth"] != float64(3) {
t.Fatalf("json dry-run = %#v", payload)
}
installDepthCaller(t, &scriptedToolCaller{format: "table", dry: true})
if err := printDriveDepthDryRun(newDocDepthRoute(), map[string]any{"workspaceId": "w1"}, 2); err != nil {
t.Fatal(err)
}
}
func useDriveDepthArgs(t *testing.T) {
t.Helper()
old := os.Args
os.Args = []string{"dws", "drive", "list", "--depth", "2"}
t.Cleanup(func() { os.Args = old })
}
func runDepthBFS(t *testing.T, caller *scriptedToolCaller, route driveDepthRoute, root string, maxDepth int, pattern string) (map[string]any, error) {
t.Helper()
out := installDepthCaller(t, caller)
cmd := &cobra.Command{Use: "list"}
err := runDriveListDepth(cmd, route, map[string]any{}, root, maxDepth, pattern, true, 0, driveListFilter{})
return decodeDepthResult(t, out), err
}
func TestCrossPlatformCoverageRunDriveListDepthDryRun(t *testing.T) {
caller := &scriptedToolCaller{format: "json", dry: true}
out := installDepthCaller(t, caller)
cmd := &cobra.Command{Use: "list"}
if err := runDriveListDepth(cmd, newDrivePanDepthRoute(), map[string]any{}, "", 2, "", true, 0, driveListFilter{}); err != nil {
t.Fatal(err)
}
if caller.calls != 0 {
t.Fatalf("dry-run calls = %d", caller.calls)
}
var payload map[string]any
if err := json.Unmarshal(out.Bytes(), &payload); err != nil {
t.Fatalf("dry-run output: %v", err)
}
if payload["dry_run"] != true {
t.Fatalf("payload = %#v", payload)
}
}
func TestCrossPlatformCoverageRunDriveListDepthPanBFS(t *testing.T) {
useDriveDepthArgs(t)
caller := &scriptedToolCaller{steps: []scriptedToolStep{
{text: `{"items":[{"fileId":"fA","name":"dirA","type":"FOLDER"},{"fileId":"fX","name":"x.txt","type":"FILE"}]}`},
{text: `{"items":[{"fileId":"fY","name":"y.txt","type":"FILE"}]}`},
}}
out := installDepthCaller(t, caller)
cmd := &cobra.Command{Use: "list"}
if err := runDriveListDepth(cmd, newDrivePanDepthRoute(), map[string]any{}, "", 3, "", false, 0, driveListFilter{}); err != nil {
t.Fatal(err)
}
if caller.calls != 2 {
t.Fatalf("calls = %d, want 2", caller.calls)
}
items := decodeDepthResult(t, out)["items"].([]any)
if len(items) != 3 {
t.Fatalf("items = %#v", items)
}
var dirA, nested map[string]any
for _, raw := range items {
item := raw.(map[string]any)
switch item["rel_path"] {
case "dirA":
dirA = item
case "dirA/y.txt":
nested = item
}
}
if dirA == nil || nested == nil {
t.Fatalf("rel_path tree = %#v", items)
}
if dirA["depth"] != float64(1) || dirA["parentId"] != "" {
t.Fatalf("root item = %#v", dirA)
}
if nested["depth"] != float64(2) || nested["parentId"] != "fA" {
t.Fatalf("nested item = %#v", nested)
}
}
func TestCrossPlatformCoverageRunDriveListDepthMaxDepthSkipsEnqueue(t *testing.T) {
useDriveDepthArgs(t)
caller := &scriptedToolCaller{steps: []scriptedToolStep{
{text: `{"items":[{"fileId":"fA","name":"dirA","type":"FOLDER"}]}`},
}}
result, err := runDepthBFS(t, caller, newDrivePanDepthRoute(), "", 1, "")
if err != nil {
t.Fatal(err)
}
if caller.calls != 1 {
t.Fatalf("calls = %d, want 1", caller.calls)
}
if len(result["items"].([]any)) != 1 {
t.Fatalf("items = %#v", result["items"])
}
}
func TestCrossPlatformCoverageRunDriveListDepthDedup(t *testing.T) {
useDriveDepthArgs(t)
caller := &scriptedToolCaller{steps: []scriptedToolStep{
{text: `{"items":[
{"fileId":"fA","name":"dirA","type":"FOLDER"},
{"fileId":"fA","name":"dirA-copy","type":"FOLDER"},
{"fileId":"","name":"no-id","type":"FOLDER"},
{"fileId":"fB","name":"dirB","type":"FOLDER"}]}`},
{text: `{"items":[{"fileId":"f1","name":"a.txt","type":"FILE"}]}`},
{text: `{"items":[{"fileId":"f2","name":"b.txt","type":"FILE"}]}`},
}}
result, err := runDepthBFS(t, caller, newDrivePanDepthRoute(), "", 3, "")
if err != nil {
t.Fatal(err)
}
if caller.calls != 3 {
t.Fatalf("calls = %d, want 3 (dedup + empty id skipped)", caller.calls)
}
if len(result["items"].([]any)) != 6 {
t.Fatalf("items = %#v", result["items"])
}
}
func TestCrossPlatformCoverageRunDriveListDepthDocRouteAnomaly(t *testing.T) {
caller := &scriptedToolCaller{steps: []scriptedToolStep{
{text: `{"nodes":[{"nodeId":"nB","name":"folderB","nodeType":"folder"},{"nodeId":"nD","name":"doc1","nodeType":"doc"}],"hasMore":false,"nextPageToken":"ignored"}`},
{text: `{"nodes":[{"nodeId":"nE","name":"inner","nodeType":"doc"}],"hasMore":true}`},
}}
result, err := runDepthBFS(t, caller, newDocDepthRoute(), "root1", 3, "")
if err != nil {
t.Fatal(err)
}
if caller.calls != 2 {
t.Fatalf("calls = %d, want 2 (hasMore=false stops authoritative route)", caller.calls)
}
errs := result["errors"].([]any)
if len(errs) != 1 {
t.Fatalf("errors = %#v", result["errors"])
}
entry := errs[0].(map[string]any)
if entry["folderId"] != "nB" || entry["reason"] != "api_error" {
t.Fatalf("anomaly entry = %#v", entry)
}
if !strings.Contains(entry["message"].(string), "hasMore=true but nextToken is empty") {
t.Fatalf("anomaly message = %#v", entry)
}
if len(result["items"].([]any)) != 3 {
t.Fatalf("items = %#v", result["items"])
}
}
func TestCrossPlatformCoverageRunDriveListDepthRateLimitRetry(t *testing.T) {
useDriveDepthArgs(t)
caller := &scriptedToolCaller{steps: []scriptedToolStep{
{text: `{"items":[{"fileId":"fA","name":"dirA","type":"FOLDER"}]}`},
{text: `{"errorCode":"invalidRequest.rateLimited","errorMsg":"slow down"}`},
{text: `{"items":[{"fileId":"f1","name":"a.txt","type":"FILE"}]}`},
}}
result, err := runDepthBFS(t, caller, newDrivePanDepthRoute(), "", 3, "")
if err != nil {
t.Fatal(err)
}
if caller.calls != 3 {
t.Fatalf("calls = %d, want 3", caller.calls)
}
if errs := result["errors"].([]any); len(errs) != 0 {
t.Fatalf("errors = %#v", errs)
}
if len(result["items"].([]any)) != 2 {
t.Fatalf("items = %#v", result["items"])
}
}
func TestCrossPlatformCoverageRunDriveListDepthRateLimitResumesFromFailedPage(t *testing.T) {
useDriveDepthArgs(t)
caller := &depthArgsRecordingCaller{steps: []scriptedToolStep{
{text: `{"items":[{"fileId":"f1","name":"page1.txt","type":"FILE"}],"nextToken":"p2"}`},
{text: `{"errorCode":"invalidRequest.rateLimited","errorMsg":"slow down"}`},
{text: `{"items":[{"fileId":"f2","name":"page2.txt","type":"FILE"}]}`},
}}
previousDeps := deps
t.Cleanup(func() { deps = previousDeps })
InitDeps(caller)
out := &bytes.Buffer{}
deps.Out.w = out
deps.Out.errW = io.Discard
cmd := &cobra.Command{Use: "list"}
if err := runDriveListDepth(cmd, newDrivePanDepthRoute(), map[string]any{}, "", 3, "", true, 0, driveListFilter{}); err != nil {
t.Fatal(err)
}
if len(caller.calls) != 3 {
t.Fatalf("calls = %d, want 3", len(caller.calls))
}
if tok, _ := caller.calls[2]["nextToken"].(string); tok != "p2" {
t.Fatalf("retry call args = %#v, want resume with nextToken=p2", caller.calls[2])
}
items := decodeDepthResult(t, out)["items"].([]any)
if len(items) != 2 {
t.Fatalf("items = %#v, want 2 without duplicates", items)
}
}
func TestCrossPlatformCoverageRunDriveListDepthRateLimitExhausted(t *testing.T) {
useDriveDepthArgs(t)
caller := &scriptedToolCaller{steps: []scriptedToolStep{
{text: `{"items":[{"fileId":"fA","name":"dirA","type":"FOLDER"}]}`},
{text: `{"errorCode":"invalidRequest.rateLimited","errorMsg":"slow down"}`},
}}
result, err := runDepthBFS(t, caller, newDrivePanDepthRoute(), "", 3, "")
if err != nil {
t.Fatal(err)
}
if caller.calls != 3 {
t.Fatalf("calls = %d, want 3 (one retry)", caller.calls)
}
errs := result["errors"].([]any)
if len(errs) != 1 {
t.Fatalf("errors = %#v", errs)
}
entry := errs[0].(map[string]any)
if entry["reason"] != "rate_limited" || entry["folderId"] != "fA" {
t.Fatalf("rate limit entry = %#v", entry)
}
}
func TestCrossPlatformCoverageRunDriveListDepthRootFailure(t *testing.T) {
useDriveDepthArgs(t)
caller := &scriptedToolCaller{steps: []scriptedToolStep{
{text: `{"errorCode":"invalidRequest.rateLimited","errorMsg":"slow down"}`},
}}
installDepthCaller(t, caller)
cmd := &cobra.Command{Use: "list"}
err := runDriveListDepth(cmd, newDrivePanDepthRoute(), map[string]any{}, "", 3, "", true, 0, driveListFilter{})
if err == nil {
t.Fatal("root failure returned nil")
}
if caller.calls != 2 {
t.Fatalf("calls = %d, want 2 (single retry then fail)", caller.calls)
}
}
func TestCrossPlatformCoverageRunDriveListDepthUnrecoverable(t *testing.T) {
useDriveDepthArgs(t)
caller := &scriptedToolCaller{steps: []scriptedToolStep{
{text: `{"items":[{"fileId":"fA","name":"dirA","type":"FOLDER"},{"fileId":"fX","name":"x.txt","type":"FILE"}]}`},
{text: `{"errorCode":"DWS_SERVICE_UNAUTHORIZED"}`},
}}
out := installDepthCaller(t, caller)
cmd := &cobra.Command{Use: "list"}
err := runDriveListDepth(cmd, newDrivePanDepthRoute(), map[string]any{}, "", 3, "", true, 0, driveListFilter{})
if err == nil {
t.Fatal("unrecoverable returned nil")
}
var cliErr *CLIError
if !errors.As(err, &cliErr) || cliErr.Code != CodeAuthTokenExpired {
t.Fatalf("err = %T %v", err, err)
}
result := decodeDepthResult(t, out)
if len(result["items"].([]any)) != 2 {
t.Fatalf("partial items = %#v", result["items"])
}
if len(result["errors"].([]any)) != 1 {
t.Fatalf("errors = %#v", result["errors"])
}
}
func TestCrossPlatformCoverageRunDriveListDepthUnrecoverableEmitFailure(t *testing.T) {
useDriveDepthArgs(t)
caller := &scriptedToolCaller{steps: []scriptedToolStep{
{text: `{"errorCode":"DWS_SERVICE_UNAUTHORIZED"}`},
}}
installDepthCaller(t, caller)
deps.Out.w = failingWriter{}
cmd := &cobra.Command{Use: "list"}
err := runDriveListDepth(cmd, newDrivePanDepthRoute(), map[string]any{}, "", 3, "", true, 0, driveListFilter{})
if err == nil || !strings.Contains(err.Error(), "write failed") {
t.Fatalf("err = %v, want emit failure", err)
}
}
func TestCrossPlatformCoverageRunDriveListDepthPaginationLoop(t *testing.T) {
useDriveDepthArgs(t)
caller := &scriptedToolCaller{steps: []scriptedToolStep{
{text: `{"items":[],"nextToken":"t","hasMore":true}`},
}}
installDepthCaller(t, caller)
cmd := &cobra.Command{Use: "list"}
err := runDriveListDepth(cmd, newDrivePanDepthRoute(), map[string]any{}, "", 3, "", true, 0, driveListFilter{})
if err == nil || !strings.Contains(err.Error(), "cursor loop suspected") {
t.Fatalf("err = %v, want pagination anomaly", err)
}
maxPages := driveDepthMaxItems/driveDepthPageSize + 1
if caller.calls != maxPages {
t.Fatalf("calls = %d, want %d", caller.calls, maxPages)
}
}
func TestCrossPlatformCoverageRunDriveListDepthTruncation(t *testing.T) {
useDriveDepthArgs(t)
var sb strings.Builder
sb.WriteString(`{"items":[`)
for i := 0; i < driveDepthMaxItems; i++ {
if i > 0 {
sb.WriteString(",")
}
fmt.Fprintf(&sb, `{"fileId":"f%d","name":"file-%d.txt","type":"FILE"}`, i, i)
}
sb.WriteString(`]}`)
caller := &scriptedToolCaller{steps: []scriptedToolStep{{text: sb.String()}}}
result, err := runDepthBFS(t, caller, newDrivePanDepthRoute(), "", 3, "")
if err != nil {
t.Fatal(err)
}
if result["truncated"] != true {
t.Fatalf("truncated = %#v", result["truncated"])
}
if len(result["items"].([]any)) != driveDepthMaxItems {
t.Fatalf("items len = %d", len(result["items"].([]any)))
}
}
func TestCrossPlatformCoverageRunDriveListDepthCancelled(t *testing.T) {
useDriveDepthArgs(t)
caller := &scriptedToolCaller{}
out := installDepthCaller(t, caller)
ctx, cancel := context.WithCancel(context.Background())
cancel()
cmd := &cobra.Command{Use: "list"}
cmd.SetContext(ctx)
err := runDriveListDepth(cmd, newDrivePanDepthRoute(), map[string]any{}, "", 3, "", true, 0, driveListFilter{})
var cancelErr *driveDepthCancelledError
if !errors.As(err, &cancelErr) {
t.Fatalf("err = %T %v, want driveDepthCancelledError", err, err)
}
result := decodeDepthResult(t, out)
if result["truncated"] != true {
t.Fatalf("cancelled result = %#v", result)
}
}
func TestCrossPlatformCoverageRunDriveListDepthCancelledEmitFailure(t *testing.T) {
useDriveDepthArgs(t)
caller := &scriptedToolCaller{}
installDepthCaller(t, caller)
deps.Out.w = failingWriter{}
ctx, cancel := context.WithCancel(context.Background())
cancel()
cmd := &cobra.Command{Use: "list"}
cmd.SetContext(ctx)
err := runDriveListDepth(cmd, newDrivePanDepthRoute(), map[string]any{}, "", 3, "", true, 0, driveListFilter{})
if err == nil || !strings.Contains(err.Error(), "write failed") {
t.Fatalf("err = %v, want emit failure", err)
}
}
func TestCrossPlatformCoverageRunDriveListDepthFinalEmitFailure(t *testing.T) {
useDriveDepthArgs(t)
caller := &scriptedToolCaller{steps: []scriptedToolStep{
{text: `{"items":[{"fileId":"fX","name":"x.txt","type":"FILE"}]}`},
}}
installDepthCaller(t, caller)
deps.Out.w = failingWriter{}
cmd := &cobra.Command{Use: "list"}
err := runDriveListDepth(cmd, newDrivePanDepthRoute(), map[string]any{}, "", 3, "", true, 0, driveListFilter{})
if err == nil || !strings.Contains(err.Error(), "write failed") {
t.Fatalf("err = %v, want emit failure", err)
}
}
func TestCrossPlatformCoverageRunDriveListDepthPatternFilter(t *testing.T) {
useDriveDepthArgs(t)
caller := &scriptedToolCaller{steps: []scriptedToolStep{
{text: `{"items":[{"fileId":"fA","name":"dirA","type":"FOLDER"},{"fileId":"fX","name":"x.txt","type":"FILE"}]}`},
{text: `{"items":[{"fileId":"fY","name":"keep.xlsx","type":"FILE"}]}`},
}}
result, err := runDepthBFS(t, caller, newDrivePanDepthRoute(), "", 3, "*.xlsx")
if err != nil {
t.Fatal(err)
}
items := result["items"].([]any)
if len(items) != 1 || items[0].(map[string]any)["name"] != "keep.xlsx" {
t.Fatalf("filtered = %#v", items)
}
}
type cancelOnCallCaller struct {
scriptedToolCaller
cancel context.CancelFunc
}
func (c *cancelOnCallCaller) CallTool(ctx context.Context, productID, toolName string, args map[string]any) (*edition.ToolResult, error) {
c.cancel()
return c.scriptedToolCaller.CallTool(ctx, productID, toolName, args)
}
func TestCrossPlatformCoverageRunDriveListDepthCancelledInsidePagination(t *testing.T) {
useDriveDepthArgs(t)
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
route := newDrivePanDepthRoute()
baseParse := route.parsePage
route.parsePage = func(text string) ([]map[string]any, string, bool) {
cancel()
return baseParse(text)
}
caller := &scriptedToolCaller{steps: []scriptedToolStep{
{text: `{"items":[{"fileId":"fX","name":"x.txt","type":"FILE"}],"nextToken":"more"}`},
}}
out := installDepthCaller(t, caller)
cmd := &cobra.Command{Use: "list"}
cmd.SetContext(ctx)
err := runDriveListDepth(cmd, route, map[string]any{}, "", 3, "", true, 0, driveListFilter{})
var cancelErr *driveDepthCancelledError
if !errors.As(err, &cancelErr) {
t.Fatalf("err = %T %v, want driveDepthCancelledError", err, err)
}
result := decodeDepthResult(t, out)
if len(result["items"].([]any)) != 1 || result["truncated"] != true {
t.Fatalf("cancelled partial = %#v", result)
}
}
func TestCrossPlatformCoverageRunDriveListDepthCancelledAfterFetch(t *testing.T) {
useDriveDepthArgs(t)
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
caller := &cancelOnCallCaller{
scriptedToolCaller: scriptedToolCaller{steps: []scriptedToolStep{
{text: `{"items":[{"fileId":"fX","name":"x.txt","type":"FILE"}]}`},
}},
cancel: cancel,
}
previousDeps := deps
t.Cleanup(func() { deps = previousDeps })
InitDeps(caller)
out := &bytes.Buffer{}
deps.Out.w = out
deps.Out.errW = io.Discard
cmd := &cobra.Command{Use: "list"}
cmd.SetContext(ctx)
err := runDriveListDepth(cmd, newDrivePanDepthRoute(), map[string]any{}, "", 3, "", true, 0, driveListFilter{})
var cancelErr *driveDepthCancelledError
if !errors.As(err, &cancelErr) {
t.Fatalf("err = %T %v, want driveDepthCancelledError", err, err)
}
result := decodeDepthResult(t, out)
if result["truncated"] != true {
t.Fatalf("cancelled result = %#v", result)
}
}