Files
Enterprise-Knowledge-Base/cli/cmd/agent/delete_test.go
T
nullkey 59132a56f6 feat(cli): agent CRUD + view full config rendering
Adds the three management verbs missing from v0.4's agent subtree
(create / edit / delete) and expands v0.4-shipped agent view to render
all 34 AgentConfig fields in human output (was 7).

Surface: hot-path flags (--model required + 7 optional) +
--config-file YAML/JSON tail + --generate-skeleton template emit.
Flag > file > server-default precedence for hybrid invocation.

- agent create <name> --model <id> [flags] + --from <agent-id> for
  copy-then-overlay (CopyAgent + UpdateAgent); preserves source
  config except for fields explicitly overridden
- agent edit <id> with --add-kb / --remove-kb idempotent pair,
  L-2 fetch-then-update, at-least-one-flag validation,
  --description "" clearing via Flags().Changed(). --config-file
  fully replaces the AgentConfig baseline (use surgical flags for
  partial edits; the Long help spells this out + a test pins the
  contract).
- agent delete <id> with ConfirmDestructive + exit-10 protocol;
  404 propagates resource.not_found (not idempotent)
- agent view: 10 grouped sections (Identity / LLM / KB attachment /
  Retrieval / Query rewrite / Tools / FAQ / Web search / Multi-turn /
  Fallback / Templates); --json field discovery includes all
  config.* keys

Shared helper cli/internal/cmdutil/agentconfig.go handles YAML/JSON
parsing, flag-overlay-file fusion, and skeleton emission.
2026-05-16 16:56:33 +08:00

108 lines
3.0 KiB
Go

package agentcmd
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/Tencent/WeKnora/cli/internal/cmdutil"
"github.com/Tencent/WeKnora/cli/internal/iostreams"
"github.com/Tencent/WeKnora/cli/internal/testutil"
)
type fakeDeleteSvc struct {
gotID string
err error
}
func (f *fakeDeleteSvc) DeleteAgent(_ context.Context, id string) error {
f.gotID = id
return f.err
}
func TestDelete_NonTTY_NoYes_ExitTen(t *testing.T) {
_, _ = iostreams.SetForTest(t) // non-TTY
svc := &fakeDeleteSvc{}
err := runDelete(
context.Background(),
&DeleteOptions{AgentID: "ag_abc", Yes: false},
&cmdutil.JSONOptions{}, svc, &testutil.ConfirmPrompter{},
)
require.Error(t, err)
var typed *cmdutil.Error
require.ErrorAs(t, err, &typed)
assert.Equal(t, cmdutil.CodeInputConfirmationRequired, typed.Code)
assert.Empty(t, svc.gotID, "must not call DeleteAgent without confirm")
assert.Equal(t, 10, cmdutil.ExitCode(err), "exit code 10 per destructive-write protocol")
}
func TestDelete_NonTTY_WithYes_Direct(t *testing.T) {
out, _ := iostreams.SetForTest(t)
svc := &fakeDeleteSvc{}
require.NoError(t, runDelete(
context.Background(),
&DeleteOptions{AgentID: "ag_abc", Yes: true},
nil, svc, &testutil.ConfirmPrompter{},
))
assert.Equal(t, "ag_abc", svc.gotID)
assert.Contains(t, out.String(), "ag_abc")
}
func TestDelete_404_PropagatesNotFound(t *testing.T) {
_, _ = iostreams.SetForTest(t)
svc := &fakeDeleteSvc{err: errBadHTTP404}
err := runDelete(
context.Background(),
&DeleteOptions{AgentID: "ag_missing", Yes: true},
nil, svc, &testutil.ConfirmPrompter{},
)
require.Error(t, err)
var typed *cmdutil.Error
require.ErrorAs(t, err, &typed)
assert.Equal(t, cmdutil.CodeResourceNotFound, typed.Code)
}
func TestDelete_TTY_ConfirmYes(t *testing.T) {
_, _ = iostreams.SetForTestWithTTY(t)
svc := &fakeDeleteSvc{}
p := &testutil.ConfirmPrompter{Answer: true}
require.NoError(t, runDelete(
context.Background(),
&DeleteOptions{AgentID: "ag_abc"},
nil, svc, p,
))
assert.True(t, p.Asked)
assert.Equal(t, "ag_abc", svc.gotID)
}
func TestDelete_TTY_ConfirmNo(t *testing.T) {
_, errBuf := iostreams.SetForTestWithTTY(t)
svc := &fakeDeleteSvc{}
p := &testutil.ConfirmPrompter{Answer: false}
err := runDelete(
context.Background(),
&DeleteOptions{AgentID: "ag_abc"},
nil, svc, p,
)
require.Error(t, err)
var typed *cmdutil.Error
require.ErrorAs(t, err, &typed)
assert.Equal(t, cmdutil.CodeUserAborted, typed.Code)
assert.Empty(t, svc.gotID, "answer=no must not call DeleteAgent")
assert.Contains(t, errBuf.String(), "Aborted")
}
func TestDelete_JSON_BareObject(t *testing.T) {
out, _ := iostreams.SetForTest(t)
svc := &fakeDeleteSvc{}
require.NoError(t, runDelete(
context.Background(),
&DeleteOptions{AgentID: "ag_abc", Yes: true},
&cmdutil.JSONOptions{}, svc, &testutil.ConfirmPrompter{},
))
assert.Contains(t, out.String(), `"id":"ag_abc"`)
assert.Contains(t, out.String(), `"deleted":true`)
}