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  }