From d781a4e51a4fb22869ea985a94a3586d0fb85fa9 Mon Sep 17 00:00:00 2001 From: Alberto Ricart Date: Sat, 4 Jan 2025 16:59:39 -0600 Subject: [PATCH] [TEST] increase coverage Signed-off-by: Alberto Ricart --- cmd/accountusercontextparams_test.go | 66 +++++++++++++++++++++ cmd/deleteimport_test.go | 10 ++-- cmd/describeaccount_test.go | 86 ++++++++++++++++++++++++++++ cmd/describeuser_test.go | 1 - cmd/fixenv_test.go | 49 ++++++++++++---- cmd/generatediagram.go | 41 +++++++++---- cmd/generatediagram_test.go | 74 ++++++++++++++++++++++++ cmd/keys_test.go | 12 +++- cmd/nkeyconfigbuilder_test.go | 4 +- cmd/rtttool_test.go | 47 +++++++++++++++ cmd/test_test.go | 38 ++++++++++++ cmd/usercontextparams.go | 8 ++- cmd/util_test.go | 10 +++- 13 files changed, 409 insertions(+), 37 deletions(-) create mode 100644 cmd/accountusercontextparams_test.go create mode 100644 cmd/generatediagram_test.go create mode 100644 cmd/rtttool_test.go create mode 100644 cmd/test_test.go diff --git a/cmd/accountusercontextparams_test.go b/cmd/accountusercontextparams_test.go new file mode 100644 index 00000000..26afa4a4 --- /dev/null +++ b/cmd/accountusercontextparams_test.go @@ -0,0 +1,66 @@ +package cmd + +import ( + "github.com/nats-io/cliprompts/v2" + "github.com/nats-io/nsc/v2/cmd/store" + "github.com/spf13/cobra" + "github.com/stretchr/testify/require" + "testing" +) + +type tp struct { + AccountUserContextParams +} + +func (p *tp) SetDefaults(ctx ActionCtx) error { + return p.AccountUserContextParams.SetDefaults(ctx) +} + +func (p *tp) Validate(ctx ActionCtx) error { + return p.AccountUserContextParams.Validate(ctx) +} + +func (p *tp) Load(ctx ActionCtx) error { + return nil +} + +func (p *tp) Run(ctx ActionCtx) (store.Status, error) { + return nil, nil +} + +func (p *tp) PreInteractive(ctx ActionCtx) error { + return p.AccountUserContextParams.Edit(ctx) +} + +func (p *tp) PostInteractive(ctx ActionCtx) error { + return nil +} + +func Test_AccountUserContextParams(t *testing.T) { + ts := NewTestStore(t, "O") + defer ts.Done(t) + + ts.AddAccount(t, "A") + ts.AddUser(t, "A", "a") + ts.AddAccount(t, "B") + ts.AddUser(t, "B", "b") + + var params tp + cmd := &cobra.Command{ + Use: "ucp", + SilenceUsage: true, + + RunE: func(cmd *cobra.Command, args []string) error { + return RunAction(cmd, args, ¶ms) + }, + } + + cliprompts.LogFn = t.Log + // A, a + inputs := []interface{}{0, 0} + + _, _, err := ExecuteInteractiveCmd(cmd, inputs) + require.NoError(t, err) + require.Equal(t, "A", params.AccountContextParams.Name) + require.Equal(t, "a", params.UserContextParams.Name) +} diff --git a/cmd/deleteimport_test.go b/cmd/deleteimport_test.go index 9a967b54..7b11b403 100644 --- a/cmd/deleteimport_test.go +++ b/cmd/deleteimport_test.go @@ -31,8 +31,8 @@ func Test_DeleteImport(t *testing.T) { ts.AddExport(t, "A", jwt.Stream, "bar", 0, false) ts.AddAccount(t, "B") - ts.AddImport(t, "A", "foo", "B") - ts.AddImport(t, "A", "bar", "B") + ts.AddImport(t, "A", jwt.Stream, "foo", "B") + ts.AddImport(t, "A", jwt.Stream, "bar", "B") tests := CmdTests{ {createDeleteImportCmd(), []string{"delete", "import", "--account", "A"}, nil, []string{"account \"A\" doesn't have imports"}, true}, @@ -51,7 +51,7 @@ func Test_DeleteImportAccountRequired(t *testing.T) { ts.AddAccount(t, "A") ts.AddExport(t, "A", jwt.Stream, "foo", 0, false) ts.AddAccount(t, "B") - ts.AddImport(t, "A", "foo", "B") + ts.AddImport(t, "A", jwt.Stream, "foo", "B") GetConfig().SetAccount("") _, _, err := ExecuteCmd(createDeleteImportCmd(), "--subject", "A") @@ -68,8 +68,8 @@ func Test_DeleteImportInteractive(t *testing.T) { ts.AddExport(t, "A", jwt.Stream, "bar", 0, false) ts.AddAccount(t, "B") - ts.AddImport(t, "A", "foo", "B") - ts.AddImport(t, "A", "bar", "B") + ts.AddImport(t, "A", jwt.Stream, "foo", "B") + ts.AddImport(t, "A", jwt.Stream, "bar", "B") input := []interface{}{1, 0, 0} cmd := createDeleteImportCmd() diff --git a/cmd/describeaccount_test.go b/cmd/describeaccount_test.go index 21ec296e..22110dec 100644 --- a/cmd/describeaccount_test.go +++ b/cmd/describeaccount_test.go @@ -18,11 +18,13 @@ package cmd import ( "encoding/json" "fmt" + "github.com/nats-io/nkeys" "os" "path/filepath" "runtime" "strings" "testing" + "time" "github.com/nats-io/jwt/v2" "github.com/stretchr/testify/require" @@ -309,3 +311,87 @@ func TestDescribeAccount_Exports(t *testing.T) { require.Contains(t, out, "| Account Token Position |") require.Contains(t, out, "foo.bar.*.> | 3") } + +func TestDescribeAccountMore(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("running in windows - hangs while command works by hand") + } + ts := NewTestStore(t, "O") + defer ts.Done(t) + ts.AddAccount(t, "A") + ac, err := ts.Store.ReadAccountClaim("A") + require.NoError(t, err) + ac.Description = "hello" + ac.InfoURL = "https://example.com" + _, signingKey, _ := CreateAccountKey(t) + ac.SigningKeys.Add(signingKey) + + _, issuer, _ := CreateAccountKey(t) + scope := jwt.NewUserScope() + scope.Key = issuer + scope.Role = "nothing" + scope.Description = "no permissions" + scope.Template = jwt.UserPermissionLimits{ + Permissions: jwt.Permissions{ + Sub: jwt.Permission{Deny: []string{">"}}, + Pub: jwt.Permission{Deny: []string{">"}}, + }, + } + ac.SigningKeys.AddScopedSigner(scope) + + ac.Limits.JetStreamLimits = jwt.JetStreamLimits{DiskStorage: -1, MemoryStorage: -1} + ac.Limits.LeafNodeConn = 1 + + _, user, _ := CreateUserKey(t) + ac.Revocations = jwt.RevocationList{} + ac.Revocations.Revoke(user, time.Now()) + + ac.Trace = &jwt.MsgTrace{ + Destination: "foo", + Sampling: 100, + } + + ekp, err := nkeys.CreateUser() + require.NoError(t, err) + a, err := ekp.PublicKey() + require.NoError(t, err) + ac.Imports.Add(&jwt.Import{ + Name: "hello", + Subject: "bar.>", + LocalSubject: "fromA.>", + Type: jwt.Stream, + AllowTrace: true, + Share: true, + Account: a, + }) + + ac.Mappings = make(map[jwt.Subject][]jwt.WeightedMapping) + ac.Mappings["mapfoo"] = []jwt.WeightedMapping{jwt.WeightedMapping{Subject: "map.>", Weight: 20, Cluster: "a"}} + + token, err := ac.Encode(ts.OperatorKey) + require.NoError(t, err) + _, err = ts.Store.StoreClaim([]byte(token)) + require.NoError(t, err) + + out, _, err := ExecuteCmd(rootCmd, "describe", "account", "-n", "A") + require.NoError(t, err) + + out = StripMultipleSpaces(out) + t.Log(out) + require.Contains(t, out, "| Description | hello") + require.Contains(t, out, "| Info Url | https://example.com") + // order of the key may be unexpected, just find the key + require.Contains(t, out, signingKey) + require.Contains(t, out, "| Max Disk Storage | Unlimited") + require.Contains(t, out, "| Max Mem Storage | Unlimited") + require.Contains(t, out, "| Max Leaf Node Connections | 1") + require.Contains(t, out, "| Revocations | 1") + require.Contains(t, out, "| Subject | foo") + require.Contains(t, out, "| Sampling | 100%") + require.Contains(t, out, "| hello | Stream | bar.> | fromA.>") + require.Contains(t, out, "| mapfoo | map.> | 20") + + require.Contains(t, out, "| Key | "+issuer) + require.Contains(t, out, "| Role | nothing") + require.Contains(t, out, "| Description | no permissions") +} diff --git a/cmd/describeuser_test.go b/cmd/describeuser_test.go index 2ad83170..f8b4dbfe 100644 --- a/cmd/describeuser_test.go +++ b/cmd/describeuser_test.go @@ -24,7 +24,6 @@ import ( "testing" "github.com/nats-io/jwt/v2" - "github.com/stretchr/testify/require" ) diff --git a/cmd/fixenv_test.go b/cmd/fixenv_test.go index 16a7899c..62d33c6c 100644 --- a/cmd/fixenv_test.go +++ b/cmd/fixenv_test.go @@ -17,13 +17,12 @@ package cmd import ( "fmt" - "path/filepath" - "testing" - "time" - "github.com/nats-io/jwt/v2" "github.com/nats-io/nsc/v2/cmd/store" "github.com/stretchr/testify/require" + "path/filepath" + "testing" + "time" ) func Test_FixRequiresInArg(t *testing.T) { @@ -62,13 +61,6 @@ func Test_FixBasics(t *testing.T) { require.NoError(t, err) require.NoError(t, Write(filepath.Join(in, "o.jwt"), []byte(otok))) - // and another with a tag - oc.Tags.Add("test") - time.Sleep(time.Second) - otok2, err := oc.Encode(okp) - require.NoError(t, err) - require.NoError(t, Write(filepath.Join(in, "o2.jwt"), []byte(otok2))) - ask, apk, akp := CreateAccountKey(t) require.NoError(t, Write(filepath.Join(in, "apk.nk"), ask)) ac := jwt.NewAccountClaims(apk) @@ -85,8 +77,35 @@ func Test_FixBasics(t *testing.T) { require.NoError(t, err) require.NoError(t, Write(filepath.Join(in, "u.jwt"), []byte(utok))) + usk2, upk2, _ := CreateUserKey(t) + uc2 := jwt.NewUserClaims(upk2) + uc2.Name = "U2" + u2tok, err := uc2.Encode(akp) + require.NoError(t, err) + creds, err := jwt.FormatUserConfig(u2tok, usk2) + require.NoError(t, err) + require.NoError(t, Write(filepath.Join(in, "u2.creds"), creds)) + + // and copy of operator with a tag (and newer date) + time.Sleep(time.Second) + + oc.Tags.Add("test") + otok2, err := oc.Encode(okp) + require.NoError(t, err) + require.NoError(t, Write(filepath.Join(in, "o2.jwt"), []byte(otok2))) + + ac.Tags.Add("test") + atok, err = ac.Encode(okp) + require.NoError(t, err) + require.NoError(t, Write(filepath.Join(in, "a2.jwt"), []byte(atok))) + + uc.Tags.Add("test") + utok, err = uc.Encode(akp) + require.NoError(t, err) + require.NoError(t, Write(filepath.Join(in, "u2.jwt"), []byte(utok))) + ofp := filepath.Join(ts.Dir, "out") - _, _, err = ExecuteCmd(createFixCmd(), "--in", in, "--out", ofp) + _, _, err = ExecuteCmd(createFixCmd(), "--creds", "--in", in, "--out", ofp) require.NoError(t, err) s, err := store.LoadStore(filepath.Join(ofp, "operators", "O")) @@ -102,11 +121,17 @@ func Test_FixBasics(t *testing.T) { require.NoError(t, err) require.Equal(t, apk, aac.Subject) require.Equal(t, "A", aac.Name) + require.True(t, aac.Tags.Contains("test")) uuc, err := s.ReadUserClaim("A", "U") require.NoError(t, err) require.Equal(t, upk, uuc.Subject) require.Equal(t, "U", uuc.Name) + require.True(t, uuc.Tags.Contains("test")) + + uuc2, err := s.ReadUserClaim("A", "U2") + require.NoError(t, err) + require.Equal(t, upk2, uuc2.Subject) okf := filepath.Join(ofp, "keys", "keys", opk[:1], opk[1:3], fmt.Sprintf("%s.nk", opk)) require.FileExists(t, okf) diff --git a/cmd/generatediagram.go b/cmd/generatediagram.go index 0be20cc5..d7ce746c 100644 --- a/cmd/generatediagram.go +++ b/cmd/generatediagram.go @@ -27,17 +27,22 @@ import ( "github.com/spf13/cobra" ) +var accDetail bool var outputFile string +var users, showKeys, detail bool -func init() { +func createDiagramCmd() *cobra.Command { diagram := &cobra.Command{ Use: "diagram", Short: "Generate diagrams for this store", Args: MaxArgs(0), SilenceUsage: true, } - accDetail := false - comp := &cobra.Command{ + return diagram +} + +func createComponentDiagreamCmd() *cobra.Command { + cmd := &cobra.Command{ Use: "component", Short: "Generate a plantuml component diagram for this store", Args: MaxArgs(0), @@ -47,10 +52,14 @@ func init() { return componentDiagram(accDetail) }, } - comp.Flags().BoolVarP(&accDetail, "detail", "", false, "Include account descriptions") - diagram.AddCommand(comp) - showKeys, detail, users := false, false, false - object := &cobra.Command{ + cmd.Flags().BoolVarP(&accDetail, "detail", "", false, "Include account descriptions") + cmd.Flags().StringVarP(&outputFile, "output-file", "o", "--", "output file, '--' is stdout") + + return cmd +} + +func createObjectDiagramCmd() *cobra.Command { + cmd := &cobra.Command{ Use: "object", Short: "Generate a plantuml object diagram for this store", Args: MaxArgs(0), @@ -60,12 +69,20 @@ func init() { return objectDiagram(users, showKeys, detail) }, } - object.Flags().BoolVarP(&showKeys, "show-keys", "", false, "Include keys in diagram") - object.Flags().BoolVarP(&users, "users", "", false, "Include User") - object.Flags().BoolVarP(&detail, "detail", "", false, "Include empty/unlimited values") - diagram.AddCommand(object) - diagram.PersistentFlags().StringVarP(&outputFile, "output-file", "o", "--", "output file, '--' is stdout") + + cmd.Flags().BoolVarP(&showKeys, "show-keys", "", false, "Include keys in diagram") + cmd.Flags().BoolVarP(&users, "users", "", false, "Include User") + cmd.Flags().BoolVarP(&detail, "detail", "", false, "Include empty/unlimited values") + cmd.Flags().StringVarP(&outputFile, "output-file", "o", "--", "output file, '--' is stdout") + + return cmd +} + +func init() { + diagram := createDiagramCmd() generateCmd.AddCommand(diagram) + diagram.AddCommand(createComponentDiagreamCmd()) + diagram.AddCommand(createObjectDiagramCmd()) } const rename = "<&resize-width>" diff --git a/cmd/generatediagram_test.go b/cmd/generatediagram_test.go new file mode 100644 index 00000000..97752709 --- /dev/null +++ b/cmd/generatediagram_test.go @@ -0,0 +1,74 @@ +package cmd + +import ( + "testing" + + "github.com/nats-io/jwt/v2" + "github.com/stretchr/testify/require" +) + +func buildDiagreamStore(t *testing.T, ts *TestStore) { + ts.AddAccount(t, "A") + ts.AddExport(t, "A", jwt.Stream, "a", 0, true) + ts.AddExport(t, "A", jwt.Service, "q", 0, true) + ac, err := ts.Store.ReadAccountClaim("A") + require.NoError(t, err) + _, pub, _ := CreateAccountKey(t) + ac.SigningKeys.Add(pub) + + ac.DefaultPermissions.Pub.Allow.Add("a.hello") + ac.DefaultPermissions.Pub.Deny.Add("a.bye") + ac.DefaultPermissions.Sub.Allow.Add("a.hi") + ac.DefaultPermissions.Sub.Allow.Add("a.goodbye") + + token, err := ac.Encode(ts.OperatorKey) + require.NoError(t, err) + require.NoError(t, ts.Store.StoreRaw([]byte(token))) + + ts.AddAccount(t, "B") + ts.AddImport(t, "A", jwt.Stream, "a", "B") + ts.AddImport(t, "A", jwt.Service, "q", "B") + ts.AddUser(t, "B", "b") + + uc, err := ts.Store.ReadUserClaim("B", "b") + require.NoError(t, err) + uc.Permissions.Pub.Allow.Add("a.>") + uc.Permissions.Pub.Deny.Add("b.>") + uc.Permissions.Sub.Allow.Add("a.>") + uc.Permissions.Sub.Deny.Add("b.>") + token, err = uc.Encode(ts.GetAccountKey(t, "B")) + require.NoError(t, err) + require.NoError(t, ts.Store.StoreRaw([]byte(token))) +} + +func Test_ObjectDiagram(t *testing.T) { + ts := NewTestStore(t, "O") + defer ts.Done(t) + buildDiagreamStore(t, ts) + + stdOut, _, err := ExecuteCmd(createObjectDiagramCmd(), "--show-keys", "--users", "--detail") + require.NoError(t, err) + require.Contains(t, stdOut, "@startuml") + require.Contains(t, stdOut, "object \"O\" as") + require.Contains(t, stdOut, "object \"A\" as") + require.Contains(t, stdOut, "object \"B\" as") + require.Contains(t, stdOut, "object \"b\" as") + require.Contains(t, stdOut, "@enduml") +} + +func Test_ComponentDiagram(t *testing.T) { + ts := NewTestStore(t, "O") + defer ts.Done(t) + buildDiagreamStore(t, ts) + + stdOut, _, err := ExecuteCmd(createComponentDiagreamCmd(), "--detail") + require.NoError(t, err) + + require.Contains(t, stdOut, "@startuml") + require.Contains(t, stdOut, "Component Diagram of Accounts - Operator O") + require.Contains(t, stdOut, "component [A]") + require.Contains(t, stdOut, "component [B]") + require.Contains(t, stdOut, "\"a\" << public stream >>") + require.Contains(t, stdOut, "\"q\" << public service >>") + require.Contains(t, stdOut, "@enduml") +} diff --git a/cmd/keys_test.go b/cmd/keys_test.go index d004b3bd..91630020 100644 --- a/cmd/keys_test.go +++ b/cmd/keys_test.go @@ -98,6 +98,15 @@ func Test_HasOldStructure(t *testing.T) { store.KeyStorePath = old } +func Test_NoMigration(t *testing.T) { + ts := NewTestStore(t, "O") + defer ts.Done(t) + + _, stdErr, err := ExecuteCmd(createMigrateKeysCmd()) + require.NoError(t, err) + require.Contains(t, stdErr, "does not need migration") +} + func Test_MigrateKeys(t *testing.T) { ts := NewEmptyStore(t) defer ts.Done(t) @@ -125,9 +134,8 @@ func Test_MigrateKeys(t *testing.T) { require.NoError(t, err) require.True(t, needsUpdate) - old, err := store.Migrate() + _, _, err = ExecuteCmd(createMigrateKeysCmd()) require.NoError(t, err) - require.DirExists(t, old) // directory for keystore has a "keys" and "creds" keysDir := filepath.Join(ks, "keys") diff --git a/cmd/nkeyconfigbuilder_test.go b/cmd/nkeyconfigbuilder_test.go index ed9d1c8d..2c806981 100644 --- a/cmd/nkeyconfigbuilder_test.go +++ b/cmd/nkeyconfigbuilder_test.go @@ -133,8 +133,8 @@ func Test_NkeyResolverMapsImporter(t *testing.T) { ts.AddAccount(t, "B") - ts.AddImport(t, "A", "service.b", "B") - ts.AddImport(t, "A", "stream.a", "B") + ts.AddImport(t, "A", jwt.Service, "service.b", "B") + ts.AddImport(t, "A", jwt.Stream, "stream.a", "B") builder := NewNKeyConfigBuilder() diff --git a/cmd/rtttool_test.go b/cmd/rtttool_test.go new file mode 100644 index 00000000..badafe63 --- /dev/null +++ b/cmd/rtttool_test.go @@ -0,0 +1,47 @@ +package cmd + +import ( + "github.com/nats-io/nats-server/v2/server" + "github.com/stretchr/testify/require" + "path/filepath" + "testing" + "time" +) + +func Test_RttTool(t *testing.T) { + ts := NewTestStore(t, "O") + defer ts.Done(t) + + ts.AddAccount(t, "SYS") + + oc, err := ts.Store.ReadOperatorClaim() + require.NoError(t, err) + oc.SystemAccount = ts.GetAccountPublicKey(t, "SYS") + oc.OperatorServiceURLs.Add("nats://127.0.0.1:4222") + token, err := oc.Encode(ts.OperatorKey) + require.NoError(t, err) + require.NoError(t, ts.Store.StoreRaw([]byte(token))) + + ts.AddAccount(t, "A") + ts.AddUser(t, "A", "a") + + serverconf := filepath.Join(ts.Dir, "server.conf") + _, _, err = ExecuteCmd(createServerConfigCmd(), "--mem-resolver", "--config-file", serverconf) + require.NoError(t, err) + + var opts server.Options + require.NoError(t, opts.ProcessConfigFile(serverconf)) + + s, err := server.NewServer(&opts) + require.NoError(t, err) + + go s.Start() + if !s.ReadyForConnections(10 * time.Second) { + t.Fatal("Unable to start NATS Server in Go Routine") + } + defer s.Shutdown() + + _, stdErr, err := ExecuteCmd(createToolRTTCmd(), "--account", "A", "--user", "a") + require.NoError(t, err) + require.Contains(t, stdErr, "round trip time to [nats://127.0.0.1:4222]") +} diff --git a/cmd/test_test.go b/cmd/test_test.go new file mode 100644 index 00000000..c2fb33e5 --- /dev/null +++ b/cmd/test_test.go @@ -0,0 +1,38 @@ +package cmd + +import ( + "fmt" + "github.com/stretchr/testify/require" + "testing" +) + +func Test_FlagTable(t *testing.T) { + ts := NewTestStore(t, "O") + defer ts.Done(t) + + stdout, _, err := ExecuteCmd(GetRootCmd(), "test", "flags") + require.NoError(t, err) + require.Contains(t, stdout, "nsc validate") + require.Contains(t, stdout, "nsc add account") +} + +func Test_WhoFlagTable(t *testing.T) { + ts := NewTestStore(t, "O") + defer ts.Done(t) + + stdout, _, err := ExecuteCmd(GetRootCmd(), "test", "whoflag", "allow-pub") + require.NoError(t, err) + require.Contains(t, stdout, "nsc add user") +} + +func Test_Doc(t *testing.T) { + ts := NewTestStore(t, "O") + defer ts.Done(t) + + docs := fmt.Sprintf("%s/doc", ts.Dir) + _, _, err := ExecuteCmd(GetRootCmd(), "test", "doc", docs) + require.NoError(t, err) + require.DirExists(t, docs) + require.FileExists(t, fmt.Sprintf("%s/nsc_add.md", docs)) + require.FileExists(t, fmt.Sprintf("%s/nsc_validate.md", docs)) +} diff --git a/cmd/usercontextparams.go b/cmd/usercontextparams.go index 12ea261a..52a3e8ec 100644 --- a/cmd/usercontextparams.go +++ b/cmd/usercontextparams.go @@ -57,9 +57,13 @@ func (p *UserContextParams) SetDefaults(ctx ActionCtx) error { } func (p *UserContextParams) Edit(ctx ActionCtx) error { - config := GetConfig() + account := ctx.StoreCtx().Account.Name + if account == "" { + config := GetConfig() + account = config.Account + } var err error - p.Name, err = PickUser(ctx.StoreCtx(), config.Account) + p.Name, err = PickUser(ctx.StoreCtx(), account) if err != nil { return err } diff --git a/cmd/util_test.go b/cmd/util_test.go index 11155915..43c10906 100644 --- a/cmd/util_test.go +++ b/cmd/util_test.go @@ -340,8 +340,11 @@ func (ts *TestStore) ImportRequiresToken(t *testing.T, srcAccount string, subjec return false } -func (ts *TestStore) AddImport(t *testing.T, srcAccount string, subject string, targetAccountName string) { +func (ts *TestStore) AddImport(t *testing.T, srcAccount string, kind jwt.ExportType, subject string, targetAccountName string) { flags := []string{"--account", targetAccountName} + if kind == jwt.Service { + flags = append(flags, "--service") + } if ts.ImportRequiresToken(t, srcAccount, subject) { token := ts.GenerateActivation(t, srcAccount, subject, targetAccountName) @@ -455,6 +458,11 @@ func StripTableDecorations(s string) string { return re.ReplaceAllString(s, " ") } +func StripMultipleSpaces(s string) string { + re := regexp.MustCompile(` +`) + return re.ReplaceAllString(s, " ") +} + func (ts *TestStore) GetAccountKey(t *testing.T, name string) nkeys.KeyPair { ac, err := ts.Store.ReadAccountClaim(name) require.NoError(t, err)