github.com/nats-io/nsc@v0.0.0-20221206222106-35db9400b257/cmd/addexport_test.go (about) 1 /* 2 * Copyright 2018-2021 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 "testing" 20 "time" 21 22 "github.com/nats-io/jwt/v2" 23 "github.com/stretchr/testify/require" 24 ) 25 26 func Test_AddExport(t *testing.T) { 27 ts := NewTestStore(t, "add_export") 28 defer ts.Done(t) 29 30 ts.AddAccount(t, "A") 31 32 tests := CmdTests{ 33 {createAddExportCmd(), []string{"add", "export"}, nil, []string{"subject is required"}, true}, 34 {createAddExportCmd(), []string{"add", "export", "--subject", "foo"}, nil, []string{"added public stream export \"foo\""}, false}, 35 {createAddExportCmd(), []string{"add", "export", "--subject", "bar", "--service"}, nil, []string{"added public service export \"bar\""}, false}, 36 {createAddExportCmd(), []string{"add", "export", "--subject", "bar"}, nil, []string{"added public stream export \"bar\""}, false}, 37 {createAddExportCmd(), []string{"add", "export", "--subject", "foo", "--service"}, nil, []string{"added public service export \"foo\""}, false}, 38 {createAddExportCmd(), []string{"add", "export", "--subject", "baz.>"}, nil, []string{"added public stream export \"baz.>\""}, false}, 39 {createAddExportCmd(), []string{"add", "export", "--subject", "ar", "--name", "mar"}, nil, []string{"added public stream export \"mar\""}, false}, 40 {createAddExportCmd(), []string{"add", "export", "--subject", "mar", "--name", "ar", "--service"}, nil, []string{"added public service export \"ar\""}, false}, 41 {createAddExportCmd(), []string{"add", "export", "--subject", "pubstream", "--private"}, nil, []string{"added private stream export \"pubstream\""}, false}, 42 {createAddExportCmd(), []string{"add", "export", "--subject", "pubservice", "--private", "--service"}, nil, []string{"added private service export \"pubservice\""}, false}, 43 {createAddExportCmd(), []string{"add", "export", "--subject", "th.1", "--service", "--response-threshold", "1s"}, nil, []string{"added public service export \"th.1\""}, false}, 44 {createAddExportCmd(), []string{"add", "export", "--subject", "th.2", "--response-threshold", "1whatever"}, nil, []string{`time: unknown unit`}, true}, 45 {createAddExportCmd(), []string{"add", "export", "--subject", "re", "--response-type", "stream"}, nil, []string{"response type can only be specified in conjunction with service"}, true}, 46 } 47 48 tests.Run(t, "root", "add") 49 } 50 51 func Test_AddPublicExport(t *testing.T) { 52 ts := NewTestStore(t, "add_export") 53 defer ts.Done(t) 54 55 ts.AddAccount(t, "A") 56 tests := CmdTests{ 57 {createAddExportCmd(), []string{"add", "export", "--private=false", "--subject", "hello"}, nil, []string{"added public stream export \"hello\""}, false}, 58 {createAddExportCmd(), []string{"add", "export", "--private=false", "--subject", "hello", "--account-token-position", "1"}, nil, []string{"Account Token Position can only be used with wildcard subjects"}, true}, 59 {createAddExportCmd(), []string{"add", "export", "--private=false", "--subject", "*.hello", "--account-token-position", "2"}, nil, []string{"Account Token Position 2 matches 'hello' but must match a *"}, true}, 60 {createAddExportCmd(), []string{"add", "export", "--private=false", "--subject", "*.hello", "--account-token-position", "3"}, nil, []string{"Account Token Position 3 exceeds length of subject"}, true}, 61 {createAddExportCmd(), []string{"add", "export", "--private=false", "--subject", "*.hello", "--account-token-position", "1"}, nil, []string{" added public stream export \"*.hello\""}, false}, 62 } 63 tests.Run(t, "root", "add") 64 } 65 66 func Test_AddExportVerify(t *testing.T) { 67 ts := NewTestStore(t, "add_export") 68 defer ts.Done(t) 69 70 ts.AddAccount(t, "A") 71 72 tests := CmdTests{ 73 {createAddExportCmd(), []string{"add", "export", "--subject", "pubfoo"}, nil, []string{"added public stream export \"pubfoo\""}, false}, 74 {createAddExportCmd(), []string{"add", "export", "--subject", "privfoo", "--private"}, nil, []string{"added private stream export \"privfoo\""}, false}, 75 {createAddExportCmd(), []string{"add", "export", "--subject", "pubbar", "--service"}, nil, []string{"added public service export \"pubbar\""}, false}, 76 {createAddExportCmd(), []string{"add", "export", "--subject", "privbar", "--service", "--private"}, nil, []string{"added private service export \"privbar\""}, false}, 77 } 78 tests.Run(t, "root", "add") 79 validateAddExports(t, ts) 80 } 81 82 func validateAddExports(t *testing.T, ts *TestStore) { 83 ac, err := ts.Store.ReadAccountClaim("A") 84 require.NoError(t, err) 85 86 require.Len(t, ac.Exports, 4) 87 m := make(map[string]*jwt.Export) 88 for _, v := range ac.Exports { 89 m[v.Name] = v 90 } 91 92 pubfoo := m["pubfoo"] 93 require.NotNil(t, pubfoo) 94 require.Equal(t, "pubfoo", string(pubfoo.Subject)) 95 require.Equal(t, jwt.Stream, pubfoo.Type) 96 require.False(t, pubfoo.TokenReq) 97 98 privfoo := m["privfoo"] 99 require.NotNil(t, privfoo) 100 require.Equal(t, "privfoo", string(privfoo.Subject)) 101 require.Equal(t, jwt.Stream, privfoo.Type) 102 require.True(t, privfoo.TokenReq) 103 104 pubbar := m["pubbar"] 105 require.NotNil(t, pubbar) 106 require.Equal(t, "pubbar", string(pubbar.Subject)) 107 require.Equal(t, jwt.Service, pubbar.Type) 108 require.False(t, pubbar.TokenReq) 109 110 privbar := m["privbar"] 111 require.NotNil(t, privbar) 112 require.Equal(t, "privbar", string(privbar.Subject)) 113 require.Equal(t, jwt.Service, privbar.Type) 114 require.True(t, privbar.TokenReq) 115 } 116 117 func Test_AddExportManagedStore(t *testing.T) { 118 as, m := RunTestAccountServer(t) 119 defer as.Close() 120 121 ts := NewTestStoreWithOperatorJWT(t, string(m["operator"])) 122 defer ts.Done(t) 123 124 ts.AddAccount(t, "A") 125 _, _, err := ExecuteCmd(createAddExportCmd(), "--subject", "aaaa") 126 require.NoError(t, err) 127 128 ac, err := ts.Store.ReadAccountClaim("A") 129 require.NoError(t, err) 130 require.Len(t, ac.Exports, 1) 131 require.Equal(t, "aaaa", string(ac.Exports[0].Subject)) 132 } 133 134 func Test_AddExportAccountNameRequired(t *testing.T) { 135 as, m := RunTestAccountServer(t) 136 defer as.Close() 137 138 ts := NewTestStoreWithOperatorJWT(t, string(m["operator"])) 139 defer ts.Done(t) 140 141 ts.AddAccount(t, "A") 142 t.Log("A", ts.GetAccountPublicKey(t, "A")) 143 ts.AddAccount(t, "B") 144 t.Log("B", ts.GetAccountPublicKey(t, "B")) 145 146 _, _, err := ExecuteCmd(createAddExportCmd(), "--subject", "bbbb") 147 require.NoError(t, err) 148 149 ac, err := ts.Store.ReadAccountClaim("B") 150 require.NoError(t, err) 151 require.Len(t, ac.Exports, 1) 152 require.Equal(t, "bbbb", ac.Exports[0].Name) 153 } 154 155 func TestAddStreamExportInteractive(t *testing.T) { 156 ts := NewTestStore(t, "test") 157 defer ts.Done(t) 158 159 ts.AddAccount(t, "A") 160 ts.AddAccount(t, "B") 161 162 input := []interface{}{0, 0, "foo.>", "Foo Stream", false, 0} 163 cmd := createAddExportCmd() 164 HoistRootFlags(cmd) 165 _, _, err := ExecuteInteractiveCmd(cmd, input, "-i") 166 require.NoError(t, err) 167 168 ac, err := ts.Store.ReadAccountClaim("A") 169 require.NoError(t, err) 170 require.Len(t, ac.Exports, 1) 171 require.Equal(t, "Foo Stream", ac.Exports[0].Name) 172 require.Equal(t, "foo.>", string(ac.Exports[0].Subject)) 173 require.Equal(t, jwt.Stream, ac.Exports[0].Type) 174 175 } 176 func TestAddServiceExportInteractive(t *testing.T) { 177 ts := NewTestStore(t, "test") 178 defer ts.Done(t) 179 180 ts.AddAccount(t, "A") 181 ts.AddAccount(t, "B") 182 183 input := []interface{}{0, 1, "bar.>", "Bar Stream", true, true, "header", "foo", 0, "1s", 0} 184 cmd := createAddExportCmd() 185 HoistRootFlags(cmd) 186 _, _, err := ExecuteInteractiveCmd(cmd, input, "-i") 187 require.NoError(t, err) 188 189 ac, err := ts.Store.ReadAccountClaim("A") 190 require.NoError(t, err) 191 require.Len(t, ac.Exports, 1) 192 require.Equal(t, "Bar Stream", ac.Exports[0].Name) 193 require.Equal(t, "bar.>", string(ac.Exports[0].Subject)) 194 require.Equal(t, jwt.Service, ac.Exports[0].Type) 195 require.Equal(t, time.Second, ac.Exports[0].ResponseThreshold) 196 require.Equal(t, jwt.Headers, ac.Exports[0].Latency.Sampling) 197 198 } 199 200 func TestAddExportNonInteractive(t *testing.T) { 201 ts := NewTestStore(t, t.Name()) 202 defer ts.Done(t) 203 204 ts.AddAccount(t, "A") 205 206 cmd := createAddExportCmd() 207 HoistRootFlags(cmd) 208 _, _, err := ExecuteCmd(cmd, "--service", "--name", "q", "--subject", "q", "--response-type", jwt.ResponseTypeChunked) 209 require.NoError(t, err) 210 211 ac, err := ts.Store.ReadAccountClaim("A") 212 require.NoError(t, err) 213 require.Len(t, ac.Exports, 1) 214 require.Equal(t, jwt.Service, ac.Exports[0].Type) 215 require.Equal(t, "q", ac.Exports[0].Name) 216 require.Equal(t, "q", string(ac.Exports[0].Subject)) 217 require.EqualValues(t, jwt.ResponseTypeChunked, ac.Exports[0].ResponseType) 218 } 219 220 func TestAddServiceLatency(t *testing.T) { 221 ts := NewTestStore(t, "O") 222 defer ts.Done(t) 223 224 ts.AddAccount(t, "A") 225 cmd := createAddExportCmd() 226 227 _, _, err := ExecuteCmd(cmd, "--service", "--subject", "q", "--latency", "q.lat", "--sampling", "100", "--response-type", jwt.ResponseTypeStream) 228 require.NoError(t, err) 229 230 ac, err := ts.Store.ReadAccountClaim("A") 231 require.NoError(t, err) 232 require.Len(t, ac.Exports, 1) 233 require.Equal(t, "q", string(ac.Exports[0].Subject)) 234 require.NotNil(t, ac.Exports[0].Latency) 235 require.Equal(t, "q.lat", string(ac.Exports[0].Latency.Results)) 236 require.Equal(t, jwt.SamplingRate(100), ac.Exports[0].Latency.Sampling) 237 require.EqualValues(t, jwt.ResponseTypeStream, ac.Exports[0].ResponseType) 238 } 239 240 func Test_AddExportBadResponseType(t *testing.T) { 241 ts := NewTestStore(t, "O") 242 defer ts.Done(t) 243 244 ts.AddAccount(t, "A") 245 cmd := createAddExportCmd() 246 247 _, _, err := ExecuteCmd(cmd, "--service", "--subject", "q", "--response-type", "foo") 248 require.Error(t, err) 249 require.Contains(t, err.Error(), "invalid response type") 250 } 251 252 func TestAddServiceLatencyInteractive(t *testing.T) { 253 ts := NewTestStore(t, "O") 254 defer ts.Done(t) 255 256 ts.AddAccount(t, "A") 257 cmd := createAddExportCmd() 258 259 // service, subject, name, private, track, freq 260 args := []interface{}{1, "q", "q", false, true, "100", "q.lat", 1, "0"} 261 _, _, err := ExecuteInteractiveCmd(cmd, args) 262 require.NoError(t, err) 263 264 ac, err := ts.Store.ReadAccountClaim("A") 265 require.NoError(t, err) 266 require.Len(t, ac.Exports, 1) 267 require.Equal(t, "q", string(ac.Exports[0].Subject)) 268 require.NotNil(t, ac.Exports[0].Latency) 269 require.Equal(t, "q.lat", string(ac.Exports[0].Latency.Results)) 270 require.Equal(t, jwt.SamplingRate(100), ac.Exports[0].Latency.Sampling) 271 require.EqualValues(t, jwt.ResponseTypeStream, ac.Exports[0].ResponseType) 272 require.Equal(t, time.Duration(0), ac.Exports[0].ResponseThreshold) 273 }