161 lines
5.5 KiB
Go
161 lines
5.5 KiB
Go
package helpers
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"testing"
|
|
|
|
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/corecmd/contractfinal"
|
|
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/executor"
|
|
"github.com/DingTalk-Real-AI/dingtalk-workspace-cli/internal/output"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
type countingDevUnifiedRunner struct {
|
|
calls int
|
|
}
|
|
|
|
func (r *countingDevUnifiedRunner) Run(_ context.Context, invocation executor.Invocation) (executor.Result, error) {
|
|
r.calls++
|
|
invocation.Implemented = true
|
|
return executor.Result{
|
|
Invocation: invocation,
|
|
Response: map[string]any{"content": map[string]any{
|
|
"success": true,
|
|
"result": map[string]any{"id": "dev-1", "hasMore": false},
|
|
}},
|
|
}, nil
|
|
}
|
|
|
|
func newDevUnifiedRoot(runner executor.Runner) *cobra.Command {
|
|
root := &cobra.Command{Use: "dws", SilenceErrors: true, SilenceUsage: true}
|
|
ctx, _ := output.WithResultStore(context.Background())
|
|
root.SetContext(ctx)
|
|
root.PersistentFlags().String("format", "json", "")
|
|
root.PersistentFlags().String("fields", "", "")
|
|
root.PersistentFlags().String("jq", "", "")
|
|
root.PersistentFlags().Bool("dry-run", false, "")
|
|
root.PersistentFlags().Bool("yes", false, "")
|
|
root.PersistentPostRunE = func(cmd *cobra.Command, _ []string) error {
|
|
_, _, err := output.EmitStoredResult(cmd)
|
|
return err
|
|
}
|
|
root.AddCommand(devHandler{}.Command(runner))
|
|
return root
|
|
}
|
|
|
|
func TestDevAppUnifiedActiveExecutesOnceAndReturnsFrameworkResult(t *testing.T) {
|
|
runner := &countingDevUnifiedRunner{}
|
|
root := newDevUnifiedRoot(runner)
|
|
var stdout bytes.Buffer
|
|
root.SetOut(&stdout)
|
|
root.SetArgs([]string{"dev", "app", "list"})
|
|
if err := root.Execute(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if runner.calls != 1 {
|
|
t.Fatalf("runner calls=%d, want exactly 1", runner.calls)
|
|
}
|
|
if !bytes.Contains(stdout.Bytes(), []byte(`"outcome": "success"`)) || !bytes.Contains(stdout.Bytes(), []byte(`"id": "dev-1"`)) {
|
|
t.Fatalf("stdout=%s", stdout.String())
|
|
}
|
|
}
|
|
|
|
func TestMigratedDevAppDefaultsToUnifiedFramework(t *testing.T) {
|
|
runner := &countingDevUnifiedRunner{}
|
|
root := newDevUnifiedRoot(runner)
|
|
var stdout bytes.Buffer
|
|
root.SetOut(&stdout)
|
|
root.SetErr(&bytes.Buffer{})
|
|
root.SetArgs([]string{"dev", "app", "list"})
|
|
if err := root.Execute(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if runner.calls != 1 {
|
|
t.Fatalf("runner calls=%d, want 1", runner.calls)
|
|
}
|
|
if !bytes.Contains(stdout.Bytes(), []byte(`"outcome": "success"`)) || bytes.Contains(stdout.Bytes(), []byte(`"contract_version"`)) {
|
|
t.Fatalf("migrated dev command did not use unified output by default: %s", stdout.String())
|
|
}
|
|
}
|
|
|
|
func TestDevDocSearchStaysLegacyUntilPagePaginationContractExists(t *testing.T) {
|
|
cmd := newDevDocSearchCommand(&countingDevUnifiedRunner{})
|
|
if got := output.CommandRollout(cmd); got != output.RolloutLegacyOnly {
|
|
t.Fatalf("dev doc search rollout=%s, want legacy_only until page pagination is modeled", got)
|
|
}
|
|
final, ok := contractfinal.RuntimeContractFinal(cmd)
|
|
if !ok {
|
|
t.Fatal("dev doc search is missing ContractFinal")
|
|
}
|
|
if final.Result != nil || final.Pagination != nil {
|
|
t.Fatalf("legacy dev doc search must not publish unified result/pagination schema: %#v", final)
|
|
}
|
|
}
|
|
|
|
func TestDevTerminalRolloutKeepsPublishedConnectStatusLegacy(t *testing.T) {
|
|
root := newDevUnifiedRoot(&countingDevUnifiedRunner{})
|
|
dev, _, err := root.Find([]string{"dev"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var walk func(*cobra.Command)
|
|
walk = func(cmd *cobra.Command) {
|
|
children := cmd.Commands()
|
|
if cmd.Runnable() && len(children) == 0 {
|
|
want := output.RolloutUnifiedActive
|
|
switch cmd.CommandPath() {
|
|
case "dws dev connect status", "dws dev connect list", "dws dev doc search":
|
|
want = output.RolloutLegacyOnly
|
|
}
|
|
if got := output.CommandRollout(cmd); got != want {
|
|
t.Errorf("%s rollout=%s, want %s", cmd.CommandPath(), got, want)
|
|
}
|
|
}
|
|
if cmd.CommandPath() == "dws dev connect" && output.CommandRollout(cmd) != output.RolloutLegacyOnly {
|
|
t.Errorf("%s must remain legacy until a streaming contract exists", cmd.CommandPath())
|
|
}
|
|
for _, child := range children {
|
|
walk(child)
|
|
}
|
|
}
|
|
walk(dev)
|
|
}
|
|
|
|
func TestDevConnectStatusPreservesPublishedHumanAndJSONShapes(t *testing.T) {
|
|
connectDaemonDirOverride = t.TempDir()
|
|
t.Cleanup(func() { connectDaemonDirOverride = "" })
|
|
|
|
humanRoot := newDevUnifiedRoot(&countingDevUnifiedRunner{})
|
|
var humanOut bytes.Buffer
|
|
humanRoot.SetOut(&humanOut)
|
|
humanRoot.SetArgs([]string{"dev", "connect", "status", "--robot-client-id", "missing"})
|
|
if err := humanRoot.Execute(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !bytes.Contains(humanOut.Bytes(), []byte("not_running")) || bytes.Contains(humanOut.Bytes(), []byte(`"outcome"`)) {
|
|
t.Fatalf("default status output no longer uses the legacy human view: %s", humanOut.String())
|
|
}
|
|
|
|
jsonRoot := newDevUnifiedRoot(&countingDevUnifiedRunner{})
|
|
var jsonOut bytes.Buffer
|
|
jsonRoot.SetOut(&jsonOut)
|
|
jsonRoot.SetArgs([]string{"dev", "connect", "status", "--robot-client-id", "missing", "--json"})
|
|
if err := jsonRoot.Execute(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var payload map[string]any
|
|
if err := json.Unmarshal(jsonOut.Bytes(), &payload); err != nil {
|
|
t.Fatalf("legacy --json output is invalid: %v\n%s", err, jsonOut.String())
|
|
}
|
|
if payload["state"] != "not_running" || payload["supervised"] != false {
|
|
t.Fatalf("legacy health fields moved or changed: %#v", payload)
|
|
}
|
|
for _, forbidden := range []string{"ok", "outcome", "data"} {
|
|
if _, exists := payload[forbidden]; exists {
|
|
t.Fatalf("legacy --json unexpectedly gained unified key %q: %#v", forbidden, payload)
|
|
}
|
|
}
|
|
}
|