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 }