github.com/nats-io/nsc/v2@v2.8.7-0.20240307184528-efd7023c6896/cmd/describeaccount_test.go (about)

     1  /*
     2   * Copyright 2018-2023 The NATS Authors
     3   * Licensed under the Apache License, Version 2.0 (the "License");
     4   * you may not use this file except in compliance with the License.
     5   * You may obtain a copy of the License at
     6   *
     7   * http://www.apache.org/licenses/LICENSE-2.0
     8   *
     9   * Unless required by applicable law or agreed to in writing, software
    10   * distributed under the License is distributed on an "AS IS" BASIS,
    11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12   * See the License for the specific language governing permissions and
    13   * limitations under the License.
    14   */
    15  
    16  package cmd
    17  
    18  import (
    19  	"encoding/json"
    20  	"fmt"
    21  	"os"
    22  	"path/filepath"
    23  	"strings"
    24  	"testing"
    25  
    26  	"github.com/nats-io/jwt/v2"
    27  	"github.com/stretchr/testify/require"
    28  )
    29  
    30  func TestDescribeAccount_Single(t *testing.T) {
    31  	ts := NewTestStore(t, "operator")
    32  	defer ts.Done(t)
    33  
    34  	opub := ts.GetOperatorPublicKey(t)
    35  
    36  	ts.AddAccount(t, "A")
    37  	pub := ts.GetAccountPublicKey(t, "A")
    38  
    39  	stdout, _, err := ExecuteCmd(createDescribeAccountCmd())
    40  	require.NoError(t, err)
    41  	// account A public key
    42  	require.Contains(t, stdout, pub)
    43  	// operator public key
    44  	require.Contains(t, stdout, opub)
    45  	// name for the account
    46  	require.Contains(t, stdout, " A ")
    47  }
    48  
    49  func TestDescribeAccountRaw(t *testing.T) {
    50  	ts := NewTestStore(t, "operator")
    51  	defer ts.Done(t)
    52  	ts.AddAccount(t, "A")
    53  
    54  	Raw = true
    55  	stdout, _, err := ExecuteCmd(createDescribeAccountCmd())
    56  	require.NoError(t, err)
    57  
    58  	ac, err := jwt.DecodeAccountClaims(stdout)
    59  	require.NoError(t, err)
    60  
    61  	require.NotNil(t, ac)
    62  	require.Equal(t, "A", ac.Name)
    63  }
    64  
    65  func TestDescribeAccount_Multiple(t *testing.T) {
    66  	ts := NewTestStore(t, "operator")
    67  	defer ts.Done(t)
    68  
    69  	ts.AddAccount(t, "A")
    70  	ts.AddAccount(t, "B")
    71  
    72  	out, _, err := ExecuteCmd(createDescribeAccountCmd())
    73  	require.NoError(t, err)
    74  	out = StripTableDecorations(out)
    75  	require.Contains(t, out, "Name B")
    76  }
    77  
    78  func TestDescribeAccount_MultipleAccountRequired(t *testing.T) {
    79  	ts := NewTestStore(t, "operator")
    80  	defer ts.Done(t)
    81  
    82  	ts.AddAccount(t, "A")
    83  	ts.AddAccount(t, "B")
    84  	require.NoError(t, GetConfig().SetAccount(""))
    85  
    86  	_, _, err := ExecuteCmd(createDescribeAccountCmd())
    87  	require.Error(t, err)
    88  	require.Contains(t, err.Error(), "account is required")
    89  }
    90  
    91  func TestDescribeAccount_MultipleWithContext(t *testing.T) {
    92  	ts := NewTestStore(t, "operator")
    93  	defer ts.Done(t)
    94  
    95  	ts.AddAccount(t, "A")
    96  	ts.AddAccount(t, "B")
    97  
    98  	err := GetConfig().SetAccount("B")
    99  	require.NoError(t, err)
   100  
   101  	opub := ts.GetOperatorPublicKey(t)
   102  	require.NoError(t, err)
   103  
   104  	pub := ts.GetAccountPublicKey(t, "B")
   105  
   106  	stdout, _, err := ExecuteCmd(createDescribeAccountCmd())
   107  	require.NoError(t, err)
   108  	require.Contains(t, stdout, pub)
   109  	require.Contains(t, stdout, opub)
   110  	require.Contains(t, stdout, " B ")
   111  }
   112  
   113  func TestDescribeAccount_MultipleWithFlag(t *testing.T) {
   114  	ts := NewTestStore(t, "operator")
   115  	defer ts.Done(t)
   116  
   117  	ts.AddAccount(t, "A")
   118  	ts.AddAccount(t, "B")
   119  
   120  	pub := ts.GetAccountPublicKey(t, "B")
   121  
   122  	stdout, _, err := ExecuteCmd(createDescribeAccountCmd(), "--name", "B")
   123  	require.NoError(t, err)
   124  	require.Contains(t, stdout, pub)
   125  	require.Contains(t, stdout, " B ")
   126  }
   127  
   128  func TestDescribeAccount_MultipleWithBadAccount(t *testing.T) {
   129  	ts := NewTestStore(t, "operator")
   130  	defer ts.Done(t)
   131  
   132  	ts.AddAccount(t, "A")
   133  	ts.AddAccount(t, "B")
   134  
   135  	_, _, err := ExecuteCmd(createDescribeAccountCmd(), "--name", "C")
   136  	require.Error(t, err)
   137  }
   138  
   139  func TestDescribeAccount_Interactive(t *testing.T) {
   140  	ts := NewTestStore(t, "operator")
   141  	defer ts.Done(t)
   142  
   143  	ts.AddAccount(t, "A")
   144  	ts.AddAccount(t, "B")
   145  
   146  	_, _, err := ExecuteInteractiveCmd(createDescribeAccountCmd(), []interface{}{0})
   147  	require.NoError(t, err)
   148  }
   149  
   150  func TestDescribeAccount_Latency(t *testing.T) {
   151  	ts := NewTestStore(t, "O")
   152  	defer ts.Done(t)
   153  
   154  	ts.AddAccount(t, "A")
   155  	ts.AddExport(t, "A", jwt.Service, "q", 0, true)
   156  	ac, err := ts.Store.ReadAccountClaim("A")
   157  	require.NoError(t, err)
   158  	ac.Exports[0].Latency = &jwt.ServiceLatency{Sampling: 10, Results: "lat"}
   159  	token, err := ac.Encode(ts.OperatorKey)
   160  	require.NoError(t, err)
   161  	_, err = ts.Store.StoreClaim([]byte(token))
   162  	require.NoError(t, err)
   163  
   164  	out, _, err := ExecuteInteractiveCmd(createDescribeAccountCmd(), []interface{}{0})
   165  	require.NoError(t, err)
   166  	require.Contains(t, out, "lat (10%)")
   167  }
   168  
   169  func TestDescribeAccount_Json(t *testing.T) {
   170  	ts := NewTestStore(t, "O")
   171  	defer ts.Done(t)
   172  
   173  	ts.AddAccount(t, "A")
   174  	out, _, err := ExecuteCmd(rootCmd, "describe", "account", "--json")
   175  	require.NoError(t, err)
   176  	m := make(map[string]interface{})
   177  	err = json.Unmarshal([]byte(out), &m)
   178  	require.NoError(t, err)
   179  	ac, err := ts.Store.ReadAccountClaim("A")
   180  	require.NoError(t, err)
   181  	require.Equal(t, ac.Subject, m["sub"])
   182  }
   183  
   184  func TestDescribeAccount_JsonPath(t *testing.T) {
   185  	ts := NewTestStore(t, "O")
   186  	defer ts.Done(t)
   187  
   188  	ts.AddAccount(t, "A")
   189  
   190  	out, _, err := ExecuteCmd(rootCmd, "describe", "account", "--field", "sub")
   191  	require.NoError(t, err)
   192  	ac, err := ts.Store.ReadAccountClaim("A")
   193  	require.NoError(t, err)
   194  	require.Equal(t, fmt.Sprintf("\"%s\"\n", ac.Subject), out)
   195  }
   196  
   197  func TestDescribeAccount_JSTiers(t *testing.T) {
   198  	ts := NewTestStore(t, "O")
   199  	defer ts.Done(t)
   200  
   201  	ts.AddAccount(t, "A")
   202  	ac, err := ts.Store.ReadAccountClaim("A")
   203  	require.NoError(t, err)
   204  	ac.Limits.JetStreamTieredLimits = jwt.JetStreamTieredLimits{}
   205  	ac.Limits.JetStreamTieredLimits["R1"] = jwt.JetStreamLimits{
   206  		DiskStorage: 1024, Streams: 10, MaxBytesRequired: true, DiskMaxStreamBytes: 512}
   207  	ac.Limits.JetStreamTieredLimits["R3"] = jwt.JetStreamLimits{
   208  		MemoryStorage: 1024, Streams: 10, MaxBytesRequired: false,
   209  		MemoryMaxStreamBytes: 512, MaxAckPending: 99}
   210  	token, err := ac.Encode(ts.OperatorKey)
   211  	require.NoError(t, err)
   212  	_, err = ts.Store.StoreClaim([]byte(token))
   213  	require.NoError(t, err)
   214  	out, _, err := ExecuteInteractiveCmd(createDescribeAccountCmd(), []interface{}{0})
   215  	require.NoError(t, err)
   216  	require.Contains(t, out, " | R1")
   217  	require.Contains(t, out, " | R3")
   218  	require.Contains(t, out, " | required")
   219  	require.Contains(t, out, " | optional")
   220  	require.Contains(t, out, " | 99")
   221  }
   222  
   223  func TestDescribeAccount_Callout(t *testing.T) {
   224  	ts := NewTestStore(t, "test")
   225  	defer ts.Done(t)
   226  
   227  	ts.AddAccount(t, "A")
   228  
   229  	_, uPK, _ := CreateUserKey(t)
   230  	_, aPK, _ := CreateAccountKey(t)
   231  	_, xPK, _ := CreateCurveKey(t)
   232  	_, _, err := ExecuteCmd(createEditAuthorizationCallout(),
   233  		"--auth-user", uPK,
   234  		"--allowed-account", aPK,
   235  		"--curve", xPK)
   236  	require.NoError(t, err)
   237  
   238  	out, _, err := ExecuteCmd(createDescribeAccountCmd())
   239  	require.NoError(t, err)
   240  	require.Contains(t, out, fmt.Sprintf(" | %s", uPK))
   241  	require.Contains(t, out, fmt.Sprintf(" | %s", aPK))
   242  	require.Contains(t, out, fmt.Sprintf(" | %s", xPK))
   243  }
   244  
   245  func TestDescribeAccount_SubjectEncoding(t *testing.T) {
   246  	ts := NewTestStore(t, "test")
   247  	defer ts.Done(t)
   248  
   249  	ts.AddAccount(t, "A")
   250  	ts.AddExport(t, "A", jwt.Stream, "foo.>", 0, true)
   251  
   252  	out, _, err := ExecuteCmd(rootCmd, "describe", "account", "--json")
   253  	require.NoError(t, err)
   254  	require.Contains(t, out, "foo.>")
   255  }
   256  
   257  func TestDescribeAccount_Output(t *testing.T) {
   258  	ts := NewTestStore(t, "O")
   259  	defer ts.Done(t)
   260  
   261  	ts.AddAccount(t, "A")
   262  
   263  	p := filepath.Join(ts.Dir, "A.json")
   264  	_, _, err := ExecuteCmd(rootCmd, "describe", "account", "--json", "--output-file", p)
   265  	require.NoError(t, err)
   266  	data, err := os.ReadFile(p)
   267  	require.NoError(t, err)
   268  
   269  	ac := jwt.AccountClaims{}
   270  	require.NoError(t, json.Unmarshal(data, &ac))
   271  	require.Equal(t, "A", ac.Name)
   272  
   273  	p = filepath.Join(ts.Dir, "A.txt")
   274  	_, _, err = ExecuteCmd(rootCmd, "describe", "account", "--output-file", p)
   275  	require.NoError(t, err)
   276  	data, err = os.ReadFile(p)
   277  	require.NoError(t, err)
   278  	strings.Contains(string(data), "Account Details")
   279  
   280  	p = filepath.Join(ts.Dir, "A.jwt")
   281  	_, _, err = ExecuteCmd(rootCmd, "describe", "account", "--raw", "--output-file", p)
   282  	require.NoError(t, err)
   283  	data, err = os.ReadFile(p)
   284  	require.NoError(t, err)
   285  	require.Contains(t, string(data), "-----BEGIN NATS ACCOUNT JWT-----\ney")
   286  }
   287  
   288  func TestDescribeAccount_Exports(t *testing.T) {
   289  	ts := NewTestStore(t, "O")
   290  	defer ts.Done(t)
   291  
   292  	ts.AddAccount(t, "A")
   293  	ts.AddExport(t, "A", jwt.Stream, "foo.bar.*.>", 0, true)
   294  
   295  	out, _, err := ExecuteCmd(rootCmd, "describe", "account")
   296  	require.NoError(t, err)
   297  	require.Contains(t, out, "| Account Token Position |")
   298  	require.Contains(t, out, "foo.bar.*.> | -")
   299  
   300  	ts.AddAccount(t, "B")
   301  	ts.AddExport(t, "B", jwt.Stream, "foo.bar.*.>", 3, true)
   302  
   303  	out, _, err = ExecuteCmd(rootCmd, "describe", "account", "-n", "B")
   304  	require.NoError(t, err)
   305  	require.Contains(t, out, "| Account Token Position |")
   306  	require.Contains(t, out, "foo.bar.*.> | 3")
   307  }