From fbd2bb3f58d2be446037c9b04fa407b7b6e2b880 Mon Sep 17 00:00:00 2001 From: Alberto Ricart Date: Sat, 4 Jan 2025 13:46:00 -0600 Subject: [PATCH] [ci] increased coverage Signed-off-by: Alberto Ricart --- .github/workflows/pushes.yaml | 54 ++++------------- Makefile | 3 +- 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 | 81 ++++++++++++++++++++++++++ cmd/keys_test.go | 16 +++++- cmd/nkeyconfigbuilder_test.go | 4 +- cmd/rtttool_test.go | 51 +++++++++++++++++ cmd/test_test.go | 45 +++++++++++++++ cmd/usercontextparams.go | 8 ++- cmd/util_test.go | 10 +++- 15 files changed, 444 insertions(+), 81 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/.github/workflows/pushes.yaml b/.github/workflows/pushes.yaml index 1057a438..a92ba5dd 100644 --- a/.github/workflows/pushes.yaml +++ b/.github/workflows/pushes.yaml @@ -60,26 +60,10 @@ jobs: go-version: ${{ matrix.go }} # We're not doing releases, just checks, so we can live without check-latest here - - name: Export Go environment to Actions outputs - id: go-settings - run: | - echo "::set-output name=arch::$(go env GOARCH)" - echo "::set-output name=hostarch::$(go env GOHOSTARCH)" - echo "::set-output name=os::$(go env GOOS)" - echo "::set-output name=hostos::$(go env GOHOSTOS)" - echo "::set-output name=go-version::$(go env GOVERSION)" - # Use with: - # ${{ steps.go-settings.outputs.go-version }} - # which will look like `go1.17.1` if matrix `1.17.x` matches `1.17.1`. - # These are independent of how the matrix is setup, or if a matrix is even used. - # - # You can see the individual values in the "Set up Go" output, collapsed inside a "go env" group at the end. - name: Install additional check/lint tools id: tools-install run: | - go install github.com/mattn/goveralls@latest - go install github.com/wadey/gocovmerge@latest go install honnef.co/go/tools/cmd/staticcheck@2021.1.2 if: matrix.canonical @@ -92,38 +76,22 @@ jobs: - name: Run Tests (with coverage enabled) id: coverage run: | - mkdir cov - echo "::group::Coverage of ./cmd" - go test -v -failfast -covermode=atomic -coverprofile=./cov/cmd.out ./cmd - echo "::endgroup::" - echo "::group::Coverage of ./cmd/store" - go test -v -failfast -covermode=atomic -coverprofile=./cov/store.out ./cmd/store - echo "::endgroup::" + go test -v -failfast -coverpkg=./... -coverprofile=./coverage.out ./... if: runner.os != 'Windows' - - name: Run Tests (Windows) - id: wintest - # nb2: if we use the coverage approach on Windows, the -coverprofile flag appears to be looked for as a package, and I've no idea why (am not a Windows dev) - # cannot find package "github.com/nats-io/nsc/cov/cmd.out" in any of: - # C:\hostedtoolcache\windows\go\1.16.13\x64\src\github.com\nats-io\nsc\cov\cmd.out (from $GOROOT) - # D:\a\nsc\nsc\go\src\github.com\nats-io\nsc\cov\cmd.out (from $GOPATH) + - name: Run Tests (windows) run: | - echo "::group::Testing of ./cmd" - go test -v -failfast ./cmd - echo "::endgroup::" - echo "::group::Testing of ./cmd/store" - go test -v -failfast ./cmd/store - echo "::endgroup::" + go test -v -failfast ./... if: runner.os == 'Windows' - - name: Upload coverage results - id: coverage-upload - run: | - gocovmerge ./cov/*.out > coverage.out - goveralls -coverprofile=coverage.out -service=github - env: - COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }} - if: matrix.canonical + - name: Upload coverage + uses: coverallsapp/github-action@v2 + continue-on-error: true + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + flag-name: ${{ matrix.module }} + file: ./coverage.out + if: runner.os != 'Windows' - name: Bad versions creep defense id: go-module-versions diff --git a/Makefile b/Makefile index 9fbfe7f8..a3724e38 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,8 @@ test: go vet ./... rm -rf ./coverage.out staticcheck -f text ./... - unset $$(env | sed -nEe 's/^(NSC_[^=]*_OPERATOR)=.*/\1/p'); go test -coverpkg=./... -coverprofile=./coverage.out ./... + #unset $$(env | sed -nEe 's/^(NSC_[^=]*_OPERATOR)=.*/\1/p'); go test -coverpkg=./... -coverprofile=./coverage.out ./... + unset $$(env | sed -nEe 's/^(NSC_[^=]*_OPERATOR)=.*/\1/p'); go test -coverpkg=$(go list ./...) -covermode=atomic -coverprofile=./coverage.out ./... staticcheck ./... release: fmt test compile 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..804ab464 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 - looking at output hangs") + } + 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..9a8800cb --- /dev/null +++ b/cmd/generatediagram_test.go @@ -0,0 +1,81 @@ +package cmd + +import ( + "runtime" + "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) { + if runtime.GOOS == "windows" { + t.Skip("running in windows - looking at output hangs") + } + 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) { + if runtime.GOOS == "windows" { + t.Skip("running in windows - looking at output hangs") + } + 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..7d129e8b 100644 --- a/cmd/keys_test.go +++ b/cmd/keys_test.go @@ -19,6 +19,7 @@ import ( "fmt" "os" "path/filepath" + "runtime" "testing" "github.com/nats-io/nkeys" @@ -98,6 +99,18 @@ func Test_HasOldStructure(t *testing.T) { store.KeyStorePath = old } +func Test_NoMigration(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("running in windows - looking at output hangs") + } + 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 +138,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..78ae4575 --- /dev/null +++ b/cmd/rtttool_test.go @@ -0,0 +1,51 @@ +package cmd + +import ( + "github.com/nats-io/nats-server/v2/server" + "github.com/stretchr/testify/require" + "path/filepath" + "runtime" + "testing" + "time" +) + +func Test_RttTool(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("running in windows - looking at output hangs") + } + 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..fec377d8 --- /dev/null +++ b/cmd/test_test.go @@ -0,0 +1,45 @@ +package cmd + +import ( + "github.com/stretchr/testify/require" + "path/filepath" + "runtime" + "testing" +) + +func Test_FlagTable(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("running in windows - looking at output hangs") + } + 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) { + if runtime.GOOS == "windows" { + t.Skip("running in windows - looking at output hangs") + } + 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 := filepath.Join(ts.Dir, "doc") + _, _, err := ExecuteCmd(GetRootCmd(), "test", "doc", docs) + require.NoError(t, err) + require.DirExists(t, docs) + require.FileExists(t, filepath.Join(docs, "nsc_add.md")) + require.FileExists(t, filepath.Join(docs, "nsc_validate.md")) +} 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)