package command import ( "bytes" "errors" "os" "path/filepath" "strings" "testing" dto "code.zhecent.com/open/shop-crm-agent/internal/api" "google.golang.org/protobuf/encoding/protojson" ) func TestRootCommandExposesOnlyCrmOperations(t *testing.T) { cmd := New("test-version") want := map[string]bool{ "init": true, "customer-list": true, "project": true, "quotation": true, "catalog-search": true, "edit": true, } for _, child := range cmd.Commands() { if child.Name() == "credential" { t.Fatal("external client exposes credential administration") } if child.Name() == "progress-template-list" { t.Fatal("external client exposes retired progress template query") } delete(want, child.Name()) } if len(want) != 0 { t.Fatalf("missing root commands = %v", want) } if cmd.Version != "test-version" { t.Fatalf("version = %q", cmd.Version) } } func TestProjectCommandsExcludeProgressAndTemplateFlag(t *testing.T) { root := New("test-version") project, _, err := root.Find([]string{"project"}) if err != nil { t.Fatal(err) } for _, child := range project.Commands() { if child.Name() == "progress-complete" { t.Fatal("project command exposes retired progress completion") } } for _, name := range []string{"create", "update"} { command, _, findErr := root.Find([]string{"project", name}) if findErr != nil { t.Fatal(findErr) } if command.Flags().Lookup("progress-template-key") != nil { t.Fatalf("project %s exposes retired progress template flag", name) } } } func TestRemoteCommandRequiresCredentialConfiguration(t *testing.T) { t.Setenv("LIGHTCORE_API_BASE_URL", "") t.Setenv("LIGHTCORE_SHOP_CRM_AGENT_TOKEN", "") repoRoot := t.TempDir() if err := os.WriteFile(filepath.Join(repoRoot, "go.mod"), []byte("module code.zhecent.com/open/shop-crm-agent\n"), 0o600); err != nil { t.Fatal(err) } t.Chdir(repoRoot) cmd := New("test") cmd.SetArgs([]string{"customer-list"}) if err := cmd.Execute(); err == nil || !strings.Contains(err.Error(), "shop-crm-agent init") { t.Fatalf("error = %v", err) } } func TestWriteCrmAgentResultPrintsStructuredBusinessError(t *testing.T) { commandErr := errors.New("CRM Agent API 错误 400: 报价已锁定") response := &dto.ProjectResponse{Header: &dto.ResponseHeader{ Code: 400, Message: "报价已锁定", RequestId: "request-123", Replayed: true, }} var output bytes.Buffer err := writeCrmAgentResult(&output, response, commandErr) if !errors.Is(err, commandErr) { t.Fatalf("command error = %v", err) } printed := &dto.ProjectResponse{} if err := protojson.Unmarshal(output.Bytes(), printed); err != nil { t.Fatalf("decode output: %v", err) } if printed.GetHeader() == nil || printed.GetHeader().Code != 400 || printed.GetHeader().RequestId != "request-123" || !printed.GetHeader().Replayed { t.Fatalf("printed header = %#v", printed.GetHeader()) } } func TestWriteCrmAgentResultSkipsMissingTransportResponse(t *testing.T) { commandErr := errors.New("connection refused") var output bytes.Buffer err := writeCrmAgentResult(&output, &dto.ProjectResponse{}, commandErr) if !errors.Is(err, commandErr) || output.Len() != 0 { t.Fatalf("error=%v output=%q", err, output.String()) } }