--- /dev/null
+/*
+ Copyright (c) 2021 AT&T Intellectual Property.
+ Copyright (c) 2018-2021 Nokia.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/*
+ * This source code is part of the near-RT RIC (RAN Intelligent Controller)
+ * platform project (RICP).
+ */
+
+package cli
+
+import (
+ "fmt"
+ "github.com/spf13/cobra"
+ "os"
+ "sort"
+ "strings"
+)
+
+func init() {
+ getCmd.AddCommand(newNamespacesCmd(newDatabase))
+}
+
+func newNamespacesCmd(dbCreateCb DbCreateCb) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "namespaces",
+ Short: "List all the namespaces in database",
+ Long: "List all the namespaces in database",
+ Args: cobra.ExactArgs(0),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ showPerDb, _ := cmd.Flags().GetBool("group")
+ nsMap, err := runNamespaces(dbCreateCb)
+ if err != nil {
+ cmd.PrintErrf("%s\n", buf.String())
+ return err
+ }
+ if showPerDb {
+ printNamespacesPerDb(cmd, nsMap)
+ } else {
+ printNamespaces(cmd, nsMap)
+ }
+ return err
+ },
+ }
+ cmd.SetOut(os.Stdout)
+ cmd.Flags().BoolP("group", "g", false, "Show namespaces per SDL DB cluster group")
+ return cmd
+}
+
+func runNamespaces(dbCreateCb DbCreateCb) (map[string][]string, error) {
+ nsMap := make(map[string][]string)
+ for _, dbInst := range dbCreateCb().Instances {
+ keys, err := dbInst.Keys("*")
+ if err != nil {
+ return nil, err
+ }
+ id, err := getServiceAddress(dbInst)
+ if err != nil {
+ return nil, err
+ }
+ for _, key := range keys {
+ namespace, err := parseKeyNamespace(key)
+ if err != nil {
+ return nil, err
+ }
+ if isUniqueNamespace(nsMap[id], namespace) {
+ nsMap[id] = append(nsMap[id], namespace)
+ }
+ }
+ }
+ return nsMap, nil
+}
+
+func getServiceAddress(db iDatabase) (string, error) {
+ state, err := db.State()
+ if err != nil {
+ return "", err
+ }
+ return state.MasterDbState.GetAddress(), nil
+}
+
+func parseKeyNamespace(key string) (string, error) {
+ sIndex := strings.Index(key, "{")
+ if sIndex == -1 {
+ return "", fmt.Errorf("Namespace parsing error, no '{' in key string '%s'", key)
+ }
+ str := key[sIndex+len("{"):]
+ eIndex := strings.Index(str, "}")
+ if eIndex == -1 {
+ return "", fmt.Errorf("Namespace parsing error, no '}' in key string '%s'", key)
+ }
+ return str[:eIndex], nil
+}
+
+func isUniqueNamespace(namespaces []string, newNs string) bool {
+ for _, n := range namespaces {
+ if n == newNs {
+ return false
+ }
+ }
+ return true
+}
+
+func printNamespaces(cmd *cobra.Command, nsMap map[string][]string) {
+ var namespaces []string
+ for _, nsList := range nsMap {
+ namespaces = append(namespaces, nsList...)
+ }
+
+ sort.Strings(namespaces)
+ for _, ns := range namespaces {
+ cmd.Println(ns)
+ }
+}
+
+func printNamespacesPerDb(cmd *cobra.Command, nsMap map[string][]string) {
+ for addr, nsList := range nsMap {
+ sort.Strings(nsList)
+ for _, ns := range nsList {
+ if addr == "" {
+ cmd.Printf("%s\n", ns)
+ } else {
+ cmd.Printf("%s: %s\n", addr, ns)
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ Copyright (c) 2021 AT&T Intellectual Property.
+ Copyright (c) 2018-2021 Nokia.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/*
+ * This source code is part of the near-RT RIC (RAN Intelligent Controller)
+ * platform project (RICP).
+ */
+
+package cli_test
+
+import (
+ "bytes"
+ "errors"
+ "gerrit.o-ran-sc.org/r/ric-plt/sdlgo/internal/cli"
+ "gerrit.o-ran-sc.org/r/ric-plt/sdlgo/internal/mocks"
+ "gerrit.o-ran-sc.org/r/ric-plt/sdlgo/internal/sdlgoredis"
+ "github.com/stretchr/testify/assert"
+ "testing"
+)
+
+var mNs *nsMock
+
+type nsMock struct {
+ dbIface *mocks.MockDB
+ dbKeys []string
+ dbState sdlgoredis.DbState
+ dbKeysErr error
+ dbStateErr error
+}
+
+func setupNamespacesCliMock(keys []string, addr string, keysErr, stateErr error) {
+ mNs = new(nsMock)
+ mNs.dbKeys = keys
+ mNs.dbState.MasterDbState.Fields.Role = "Master"
+ mNs.dbState.MasterDbState.Fields.Ip = addr
+ if addr != "" {
+ mNs.dbState.MasterDbState.Fields.Port = "6379"
+ }
+ mNs.dbKeysErr = keysErr
+ mNs.dbStateErr = stateErr
+}
+
+func newNsMockDatabase() *cli.Database {
+ db := &cli.Database{}
+ mNs.dbIface = new(mocks.MockDB)
+ mNs.dbIface.On("Keys", "*").Return(mNs.dbKeys, mNs.dbKeysErr)
+ mNs.dbIface.On("State").Return(&mNs.dbState, mNs.dbStateErr).Maybe()
+ db.Instances = append(db.Instances, mNs.dbIface)
+ return db
+}
+
+func TestNamespacesCmdShowHelp(t *testing.T) {
+ var expOkErr error
+ expNokErrTooManyArgs := errors.New("accepts 0 arg(s), received 1")
+ expHelp := "Usage:\n namespaces [flags]"
+ tests := []struct {
+ args []string
+ expOut string
+ expErr error
+ }{
+ {args: []string{"-h"}, expErr: expOkErr, expOut: expHelp},
+ {args: []string{"--help"}, expErr: expOkErr, expOut: expHelp},
+ {args: []string{"extra-arg"}, expErr: expNokErrTooManyArgs, expOut: expHelp},
+ }
+
+ for _, test := range tests {
+ buf := new(bytes.Buffer)
+ cmd := cli.NewNamespacesCmdForTest(newNsMockDatabase)
+ cmd.SetOut(buf)
+ cmd.SetErr(buf)
+ cmd.SetArgs(test.args)
+ err := cmd.Execute()
+ result := buf.String()
+
+ assert.Equal(t, test.expErr, err)
+ assert.Contains(t, result, test.expOut)
+ }
+}
+
+func TestNamespacesCmdSuccess(t *testing.T) {
+ expOut := "ns1\n" + "ns2\n" + "ns3\n"
+ buf := new(bytes.Buffer)
+ setupNamespacesCliMock([]string{
+ "{ns1},key1",
+ "{ns3},key1",
+ "{ns2},key1",
+ "{ns1},key2",
+ }, "1.2.3.4", nil, nil)
+ cmd := cli.NewNamespacesCmdForTest(newNsMockDatabase)
+ cmd.SetOut(buf)
+ cmd.SetErr(buf)
+
+ err := cmd.Execute()
+ result := buf.String()
+
+ assert.Nil(t, err)
+ assert.Equal(t, expOut, result)
+ mNs.dbIface.AssertExpectations(t)
+}
+
+func TestNamespacesCmdWithPerDbFlagSuccess(t *testing.T) {
+ expOut := "1.2.3.4:6379: ns1\n" + "1.2.3.4:6379: ns2\n" + "1.2.3.4:6379: ns3\n"
+ buf := new(bytes.Buffer)
+ setupNamespacesCliMock([]string{
+ "{ns1},key1",
+ "{ns3},key1",
+ "{ns2},key1",
+ "{ns1},key2",
+ }, "1.2.3.4", nil, nil)
+ cmd := cli.NewNamespacesCmdForTest(newNsMockDatabase)
+ cmd.SetOut(buf)
+ cmd.SetErr(buf)
+ cmd.SetArgs([]string{"--group"})
+
+ err := cmd.Execute()
+ result := buf.String()
+
+ assert.Nil(t, err)
+ assert.Equal(t, expOut, result)
+ mNs.dbIface.AssertExpectations(t)
+}
+
+func TestNamespacesCmdNoKeysInDbSuccess(t *testing.T) {
+ expOut := ""
+ buf := new(bytes.Buffer)
+ setupNamespacesCliMock([]string{}, "1.2.3.4", nil, nil)
+ cmd := cli.NewNamespacesCmdForTest(newNsMockDatabase)
+ cmd.SetOut(buf)
+ cmd.SetErr(buf)
+
+ err := cmd.Execute()
+ result := buf.String()
+
+ assert.Nil(t, err)
+ assert.Equal(t, expOut, result)
+ mNs.dbIface.AssertExpectations(t)
+}
+
+func TestNamespacesCmdWithPerDbFlagNoKeysInDbSuccess(t *testing.T) {
+ expOut := ""
+ buf := new(bytes.Buffer)
+ setupNamespacesCliMock([]string{}, "1.2.3.4", nil, nil)
+ cmd := cli.NewNamespacesCmdForTest(newNsMockDatabase)
+ cmd.SetOut(buf)
+ cmd.SetErr(buf)
+ cmd.SetArgs([]string{"--group"})
+
+ err := cmd.Execute()
+ result := buf.String()
+
+ assert.Nil(t, err)
+ assert.Equal(t, expOut, result)
+ mNs.dbIface.AssertExpectations(t)
+}
+
+func TestNamespacesCmdWithPerDbFlagStandaloneRedisAddressMissingSuccess(t *testing.T) {
+ expOut := "ns1\n" + "ns2\n" + "ns3\n"
+ buf := new(bytes.Buffer)
+ setupNamespacesCliMock([]string{
+ "{ns1},key1",
+ "{ns3},key1",
+ "{ns2},key1",
+ "{ns1},key2",
+ }, "", nil, nil)
+ cmd := cli.NewNamespacesCmdForTest(newNsMockDatabase)
+ cmd.SetOut(buf)
+ cmd.SetErr(buf)
+ cmd.SetArgs([]string{"--group"})
+
+ err := cmd.Execute()
+ result := buf.String()
+
+ assert.Nil(t, err)
+ assert.Equal(t, expOut, result)
+ mNs.dbIface.AssertExpectations(t)
+}
+
+func TestNamespacesCmdDbKeysFailure(t *testing.T) {
+ expNokErr := errors.New("Some error")
+ expOut := "Error: Some error"
+
+ buf := new(bytes.Buffer)
+ setupNamespacesCliMock(nil, "1.2.3.4", expNokErr, nil)
+ cmd := cli.NewNamespacesCmdForTest(newNsMockDatabase)
+ cmd.SetOut(buf)
+ cmd.SetErr(buf)
+
+ err := cmd.Execute()
+ result := buf.String()
+
+ assert.Equal(t, expNokErr, err)
+ assert.Contains(t, result, expOut)
+ mNs.dbIface.AssertExpectations(t)
+}
+
+func TestNamespacesCmdDbStateFailure(t *testing.T) {
+ expNokErr := errors.New("Some error")
+ expOut := "Error: Some error"
+
+ buf := new(bytes.Buffer)
+ setupNamespacesCliMock(nil, "1.2.3.4", nil, expNokErr)
+ cmd := cli.NewNamespacesCmdForTest(newNsMockDatabase)
+ cmd.SetOut(buf)
+ cmd.SetErr(buf)
+
+ err := cmd.Execute()
+ result := buf.String()
+
+ assert.Equal(t, expNokErr, err)
+ assert.Contains(t, result, expOut)
+ mNs.dbIface.AssertExpectations(t)
+}
+
+func TestNamespacesCmdNsStartMarkerFailure(t *testing.T) {
+ expNokErr := errors.New("Namespace parsing error, no '{' in key string 'ns2},key1'")
+ expOut := "Error: Namespace parsing error, no '{' in key string 'ns2},key1'"
+
+ buf := new(bytes.Buffer)
+ setupNamespacesCliMock([]string{
+ "{ns1},key1",
+ "ns2},key1",
+ "{ns1},key2",
+ }, "1.2.3.4", nil, nil)
+ cmd := cli.NewNamespacesCmdForTest(newNsMockDatabase)
+ cmd.SetOut(buf)
+ cmd.SetErr(buf)
+
+ err := cmd.Execute()
+ result := buf.String()
+
+ assert.Equal(t, expNokErr, err)
+ assert.Contains(t, result, expOut)
+ mNs.dbIface.AssertExpectations(t)
+}
+
+func TestNamespacesCmdNsEndMarkerFailure(t *testing.T) {
+ expNokErr := errors.New("Namespace parsing error, no '}' in key string '{ns2,key1'")
+ expOut := "Error: Namespace parsing error, no '}' in key string '{ns2,key1'"
+
+ buf := new(bytes.Buffer)
+ setupNamespacesCliMock([]string{
+ "{ns1},key1",
+ "{ns2,key1",
+ "{ns1},key2",
+ }, "1.2.3.4", nil, nil)
+ cmd := cli.NewNamespacesCmdForTest(newNsMockDatabase)
+ cmd.SetOut(buf)
+ cmd.SetErr(buf)
+
+ err := cmd.Execute()
+ result := buf.String()
+
+ assert.Equal(t, expNokErr, err)
+ assert.Contains(t, result, expOut)
+ mNs.dbIface.AssertExpectations(t)
+}