100 lines
3.4 KiB
Go
100 lines
3.4 KiB
Go
package corecmd
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"errors"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/corecmd/contract"
|
|
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/output"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
func TestResultInvokeCarriesOneFrameworkResult(t *testing.T) {
|
|
calls := 0
|
|
ctx, store := output.WithResultStore(context.Background())
|
|
cmd := New(Spec{
|
|
Use: "result",
|
|
OutputRollout: output.RolloutUnifiedActive,
|
|
Safety: contract.SafetySpec{
|
|
Effect: "read", Risk: "low", Confirmation: "not_required", Idempotency: "idempotent",
|
|
},
|
|
ResultInvoke: func(*Ctx, map[string]any) (output.CommandResult, error) {
|
|
calls++
|
|
return output.Success(map[string]any{"id": "a"}), nil
|
|
},
|
|
})
|
|
cmd.SetContext(ctx)
|
|
cmd.PersistentFlags().String("format", "json", "")
|
|
var stdout bytes.Buffer
|
|
cmd.SetOut(&stdout)
|
|
cmd.PersistentPostRunE = func(executed *cobra.Command, _ []string) error {
|
|
_, _, err := output.EmitStoredResult(executed)
|
|
return err
|
|
}
|
|
if err := cmd.Execute(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if calls != 1 {
|
|
t.Fatalf("calls=%d, want 1", calls)
|
|
}
|
|
if code, emitted := output.StoredExitCode(store); !emitted || code != 0 {
|
|
t.Fatalf("stored code/emitted=%d/%v", code, emitted)
|
|
}
|
|
if !strings.Contains(stdout.String(), `"outcome": "success"`) || strings.Contains(stdout.String(), `"contract_version"`) {
|
|
t.Fatalf("stdout=%s", stdout.String())
|
|
}
|
|
if output.CommandRollout(cmd) != output.RolloutUnifiedActive {
|
|
t.Fatalf("rollout=%s", output.CommandRollout(cmd))
|
|
}
|
|
}
|
|
|
|
func TestFrameworkResultInvokeErrorLegacyAndStoreEdges(t *testing.T) {
|
|
wantErr := errors.New("invoke failed")
|
|
cases := []struct {
|
|
name string
|
|
rollout output.RolloutState
|
|
invoke func(*Ctx, map[string]any) (output.CommandResult, error)
|
|
want string
|
|
}{
|
|
{"invoke error", output.RolloutUnifiedActive, func(*Ctx, map[string]any) (output.CommandResult, error) { return nil, wantErr }, "invoke failed"},
|
|
{"legacy guard", output.RolloutLegacyOnly, func(*Ctx, map[string]any) (output.CommandResult, error) { return output.Success(nil), nil }, "without an active unified-result rollout"},
|
|
{"missing store", output.RolloutUnifiedActive, func(*Ctx, map[string]any) (output.CommandResult, error) { return output.Success(nil), nil }, "no result store"},
|
|
}
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
cmd := New(Spec{Use: "result", OutputRollout: tc.rollout, Safety: contract.SafetySpec{Effect: "read", Risk: "low", Confirmation: "not_required", Idempotency: "idempotent"}, ResultInvoke: tc.invoke})
|
|
cmd.SetArgs(nil)
|
|
err := cmd.Execute()
|
|
if err == nil || !strings.Contains(err.Error(), tc.want) {
|
|
t.Fatalf("Execute error=%v, want %q", err, tc.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestLegacyResultInvokeIsRejectedBeforeBusinessDispatch(t *testing.T) {
|
|
calls := 0
|
|
cmd := New(Spec{
|
|
Use: "result",
|
|
OutputRollout: output.RolloutLegacyOnly,
|
|
Safety: contract.SafetySpec{
|
|
Effect: "write", Risk: "high", Confirmation: "not_required", Idempotency: "unknown",
|
|
},
|
|
ResultInvoke: func(*Ctx, map[string]any) (output.CommandResult, error) {
|
|
calls++
|
|
return output.Success(map[string]any{"changed": true}), nil
|
|
},
|
|
})
|
|
cmd.SetArgs(nil)
|
|
err := cmd.Execute()
|
|
if err == nil || !strings.Contains(err.Error(), "without an active unified-result rollout") {
|
|
t.Fatalf("Execute error=%v", err)
|
|
}
|
|
if calls != 0 {
|
|
t.Fatalf("business dispatcher ran %d time(s), want 0", calls)
|
|
}
|
|
}
|