Files
goclaw/cmd/skills_lifecycle_cmd_test.go

160 lines
4.3 KiB
Go

package cmd
import (
"bytes"
"io"
"net/http"
"os"
"reflect"
"testing"
)
func TestSkillsDepsInstallUsesPerSkillInstallEndpoint(t *testing.T) {
calls := captureSkillGatewayCalls(t)
cmd := skillsDepsCmd()
cmd.SetArgs([]string{"install", "skill-123", "--json"})
cmd.SetOut(io.Discard)
cmd.SetErr(io.Discard)
if err := cmd.Execute(); err != nil {
t.Fatalf("execute: %v", err)
}
if len(calls.requests) != 1 {
t.Fatalf("requests = %d, want 1", len(calls.requests))
}
got := calls.requests[0]
if got.method != http.MethodPost || got.path != "/v1/skills/skill-123/dependencies/install" {
t.Fatalf("request = %+v", got)
}
}
func TestSkillsAccessSetUsesPatchModeBody(t *testing.T) {
calls := captureSkillGatewayCalls(t)
cmd := skillsAccessCmd()
cmd.SetArgs([]string{"set", "skill-123", "--mode", "public", "--json"})
cmd.SetOut(io.Discard)
cmd.SetErr(io.Discard)
if err := cmd.Execute(); err != nil {
t.Fatalf("execute: %v", err)
}
if len(calls.requests) != 1 {
t.Fatalf("requests = %d, want 1", len(calls.requests))
}
got := calls.requests[0]
if got.method != http.MethodPatch || got.path != "/v1/skills/skill-123/access" {
t.Fatalf("request = %+v", got)
}
if !reflect.DeepEqual(got.body, map[string]any{"mode": "public"}) {
t.Fatalf("body = %#v", got.body)
}
}
func TestSkillsGrantAgentUsesPluralGrantEndpoint(t *testing.T) {
calls := captureSkillGatewayCalls(t)
cmd := skillsGrantCmd()
cmd.SetArgs([]string{"agent", "skill-123", "agent-456", "--can-manage", "--pinned-version", "7", "--json"})
cmd.SetOut(io.Discard)
cmd.SetErr(io.Discard)
if err := cmd.Execute(); err != nil {
t.Fatalf("execute: %v", err)
}
if len(calls.requests) != 1 {
t.Fatalf("requests = %d, want 1", len(calls.requests))
}
got := calls.requests[0]
if got.method != http.MethodPost || got.path != "/v1/skills/skill-123/grants/agents" {
t.Fatalf("request = %+v", got)
}
want := map[string]any{"agent_id": "agent-456", "can_manage": true, "pinned_version": 7}
if !reflect.DeepEqual(got.body, want) {
t.Fatalf("body = %#v, want %#v", got.body, want)
}
}
func TestSkillsAccessEffectiveBuildsOptionalSkillURL(t *testing.T) {
calls := captureSkillGatewayCalls(t)
cmd := skillsAccessCmd()
cmd.SetArgs([]string{"effective", "skill-123", "--agent", "agent-456", "--user", "user-789", "--json"})
cmd.SetOut(io.Discard)
cmd.SetErr(io.Discard)
if err := cmd.Execute(); err != nil {
t.Fatalf("execute: %v", err)
}
if len(calls.requests) != 1 {
t.Fatalf("requests = %d, want 1", len(calls.requests))
}
got := calls.requests[0]
wantPath := "/v1/skills/skill-123/access/effective?agent_id=agent-456&user_id=user-789"
if got.method != http.MethodGet || got.path != wantPath {
t.Fatalf("request = %+v, want path %s", got, wantPath)
}
}
type skillGatewayCall struct {
method string
path string
body any
}
type capturedSkillGatewayCalls struct {
requests []skillGatewayCall
}
func captureSkillGatewayCalls(t *testing.T) *capturedSkillGatewayCalls {
t.Helper()
calls := &capturedSkillGatewayCalls{}
prevDo := skillsGatewayDo
prevDelete := skillsGatewayDelete
prevRequire := skillsRequireGateway
prevStdout := os.Stdout
r, w, err := os.Pipe()
if err != nil {
t.Fatalf("pipe: %v", err)
}
os.Stdout = w
t.Cleanup(func() {
_ = w.Close()
_, _ = io.Copy(io.Discard, r)
_ = r.Close()
os.Stdout = prevStdout
skillsGatewayDo = prevDo
skillsGatewayDelete = prevDelete
skillsRequireGateway = prevRequire
})
skillsRequireGateway = func() {}
skillsGatewayDo = func(method, path string, body any) (map[string]any, error) {
calls.requests = append(calls.requests, skillGatewayCall{method: method, path: path, body: body})
return map[string]any{"ok": true}, nil
}
skillsGatewayDelete = func(path string) error {
calls.requests = append(calls.requests, skillGatewayCall{method: http.MethodDelete, path: path})
return nil
}
return calls
}
func TestRunLocalSkillDepsStatusPrintsJSON(t *testing.T) {
dir := t.TempDir()
if err := os.WriteFile(dir+"/SKILL.md", []byte("---\nname: Demo\ndeps:\n - system:goclaw-missing-test-bin\n---\n"), 0o644); err != nil {
t.Fatalf("write SKILL.md: %v", err)
}
var out bytes.Buffer
if err := runLocalSkillDepsStatus(&out, dir, true); err != nil {
t.Fatalf("runLocalSkillDepsStatus: %v", err)
}
if !bytes.Contains(out.Bytes(), []byte(`"missing_count": 1`)) {
t.Fatalf("output = %s", out.String())
}
}