bf9395e022
CI / license-header (push) Has been skipped
CI / e2e-dry-run (push) Has been skipped
CI / fast-gate (push) Failing after 0s
Test PR Label Logic / test-pr-labels (push) Failing after 1s
Skill Format Check / check-format (push) Failing after 2s
CI / security (push) Failing after 5s
CI / unit-test (push) Has been skipped
CI / lint (push) Has been skipped
CI / script-test (push) Has been skipped
CI / deterministic-gate (push) Has been skipped
CI / coverage (push) Has been skipped
CI / results (push) Has been cancelled
CI / deadcode (push) Has been cancelled
CI / e2e-live (push) Has been cancelled
64 lines
2.1 KiB
Go
64 lines
2.1 KiB
Go
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package common
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"testing"
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
"github.com/larksuite/cli/internal/cmdutil"
|
|
"github.com/larksuite/cli/internal/core"
|
|
"github.com/larksuite/cli/internal/output"
|
|
)
|
|
|
|
// TestOutPartialFailure pins the batch / multi-status contract: the result
|
|
// rides on stdout as an ok:false envelope (carrying the full payload), and the
|
|
// returned error is the typed partial-failure exit signal (ExitAPI), distinct
|
|
// from ErrBare (the silent-exit signal).
|
|
func TestOutPartialFailure(t *testing.T) {
|
|
cfg := &core.CliConfig{Brand: core.BrandFeishu, AppID: "cli_x"}
|
|
f, stdout, _, _ := cmdutil.TestFactory(t, cfg)
|
|
rt := TestNewRuntimeContextForAPI(context.Background(), &cobra.Command{Use: "+push"}, cfg, f, core.AsUser)
|
|
|
|
payload := map[string]interface{}{
|
|
"summary": map[string]interface{}{"uploaded": 1, "failed": 1},
|
|
"items": []map[string]interface{}{
|
|
{"rel_path": "a.txt", "action": "uploaded"},
|
|
{"rel_path": "b.txt", "action": "failed", "error": "boom"},
|
|
},
|
|
}
|
|
|
|
err := rt.OutPartialFailure(payload, nil)
|
|
|
|
// 1) typed partial-failure exit signal
|
|
var pfErr *output.PartialFailureError
|
|
if !errors.As(err, &pfErr) {
|
|
t.Fatalf("expected *output.PartialFailureError, got %T: %v", err, err)
|
|
}
|
|
if pfErr.Code != output.ExitAPI {
|
|
t.Errorf("exit code = %d, want %d (ExitAPI)", pfErr.Code, output.ExitAPI)
|
|
}
|
|
|
|
// 2) stdout envelope reports ok:false but still carries the full payload
|
|
// (both the succeeded and failed items) — consistent with a success Out().
|
|
var env struct {
|
|
OK bool `json:"ok"`
|
|
Data map[string]interface{} `json:"data"`
|
|
}
|
|
if err := json.Unmarshal(stdout.Bytes(), &env); err != nil {
|
|
t.Fatalf("unmarshal stdout envelope: %v\nstdout: %s", err, stdout.String())
|
|
}
|
|
if env.OK {
|
|
t.Errorf("ok must be false on partial failure, got ok:true\nstdout: %s", stdout.String())
|
|
}
|
|
items, _ := env.Data["items"].([]interface{})
|
|
if len(items) != 2 {
|
|
t.Fatalf("both succeeded and failed items must ride on stdout, got %d items\nstdout: %s", len(items), stdout.String())
|
|
}
|
|
}
|