SDL CLI 'get' reads keys data in the given namespace 76/7076/3
authorPetri Ovaska <petri.ovaska@nokia.com>
Tue, 16 Nov 2021 06:36:13 +0000 (08:36 +0200)
committerPetri Ovaska <petri.ovaska@nokia.com>
Wed, 17 Nov 2021 13:25:55 +0000 (15:25 +0200)
Implement SDL CLI 'get' command that reads keys data in the given
namespace. The 'get' reads one or multiple keys data:

 sdlcli get <namespace> <key> [<key2> <key3>... <keyN>]

Issue-Id: RIC-113
Change-Id: Ibe2cad1a986fa48bee4dba20eb4e886f62b09bf0
Signed-off-by: Petri Ovaska <petri.ovaska@nokia.com>
internal/cli/get.go
internal/cli/get_test.go
internal/cli/types.go
internal/mocks/db_mocks_private_testing.go

index 5577663..de4f80c 100644 (file)
 package cli
 
 import (
+       "fmt"
+       "os"
+       "sort"
+
+       "gerrit.o-ran-sc.org/r/ric-plt/sdlgo"
+       "gerrit.o-ran-sc.org/r/ric-plt/sdlgo/internal/sdlgoredis"
        "github.com/spf13/cobra"
 )
 
-var getCmd = newGetCmd()
+var getCmd = newGetCmd(func() ISyncStorage {
+       return sdlgo.NewSyncStorage()
+})
 
 func init() {
        rootCmd.AddCommand(getCmd)
@@ -35,17 +43,60 @@ func init() {
 var (
        getLong = `Display one or many resources.
 
-Prints important information about the specified resources.`
+Prints keys and keys data in the given namespace.`
+
+       getExample = `  # Get reads keys data in the given namespace.
+  sdlcli get sdlns key1
+
+  # Get reads multiple keys data in the given namespace.
+  sdlcli get sdlns key1 key2 key3
 
-       getExample = `  # List keys in the given namespace.
+  # List keys in the given namespace.
   sdlcli get keys sdlns`
 )
 
-func newGetCmd() *cobra.Command {
+func newGetCmd(sdlCb SyncStorageCreateCb) *cobra.Command {
        return &cobra.Command{
-               Use:     "get",
+               Use:     "get <namespace> <key> [<key2> <key3>... <keyN>]",
                Short:   "Display one or many resources",
                Long:    getLong,
                Example: getExample,
+               RunE: func(cmd *cobra.Command, args []string) error {
+                       sdlgoredis.SetDbLogger(&buf)
+                       if len(args) < 2 {
+                               return fmt.Errorf("accepts command or arguments, received %d", len(args))
+                       }
+                       data, err := runGet(sdlCb, args)
+                       if err != nil {
+                               fmt.Fprintf(os.Stderr, "%s", buf.String())
+                               return err
+                       }
+                       printData(cmd, data)
+                       return nil
+               },
+       }
+}
+
+func runGet(sdlCb SyncStorageCreateCb, args []string) (map[string]interface{}, error) {
+       data, err := sdlCb().Get(args[0], args[1:])
+       if err != nil {
+               return nil, err
+       }
+       return data, nil
+}
+
+func printData(cmd *cobra.Command, data map[string]interface{}) {
+       var str string
+       var sortedKeys []string
+       for key := range data {
+               sortedKeys = append(sortedKeys, key)
+       }
+       sort.Strings(sortedKeys)
+       for _, k := range sortedKeys {
+               value, ok := data[k]
+               if ok && value != nil {
+                       str = fmt.Sprintf("%s:%s", k, value)
+                       cmd.Printf(str + "\n")
+               }
        }
 }
index 759ab11..22301b9 100644 (file)
@@ -26,14 +26,55 @@ 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"
        "github.com/stretchr/testify/assert"
        "testing"
 )
 
+var getMocks *GetMocks
+
+type GetMocks struct {
+       sdlIface *mocks.MockSdlApi
+       ns       string
+       keys     []string
+       result   map[string]interface{}
+       ret      error
+}
+
+func setupGetMock(ns string, keys []string, result map[string]interface{}, ret error) {
+       getMocks = new(GetMocks)
+       getMocks.ns = ns
+       getMocks.keys = keys
+       getMocks.result = result
+       getMocks.ret = ret
+}
+
+func newSdlGetApiMock() cli.ISyncStorage {
+       getMocks.sdlIface = new(mocks.MockSdlApi)
+       getMocks.sdlIface.On("Get", getMocks.ns, getMocks.keys).Return(getMocks.result, getMocks.ret)
+       return getMocks.sdlIface
+}
+
+func runGetCmdCli() (string, string, error) {
+       bufOut := new(bytes.Buffer)
+       bufErr := new(bytes.Buffer)
+
+       cmd := cli.NewGetCmdForTest(newSdlGetApiMock)
+       cmd.SetOut(bufOut)
+       cmd.SetErr(bufErr)
+       args := []string{getMocks.ns}
+       args = append(args, getMocks.keys...)
+       cmd.SetArgs(args)
+       err := cmd.Execute()
+
+       return bufOut.String(), bufErr.String(), err
+}
+
 func TestGetCmdShowHelp(t *testing.T) {
        var expOkErr error
-       expHelp := "Display one or many resources.\n\nPrints important information about the specified resources."
-       expExamples := "Examples:\n  # List keys in the given namespace."
+       expHelp := "Display one or many resources.\n\nPrints keys and keys data in the given namespace."
+       expHelpUsage := "Usage:\n  get <namespace> <key> [<key2> <key3>... <keyN>] [flags]"
+       expArgsErr := errors.New("accepts command or arguments, received 0")
        expNokErr := errors.New("unknown flag: --ff")
        tests := []struct {
                args   []string
@@ -42,13 +83,13 @@ func TestGetCmdShowHelp(t *testing.T) {
        }{
                {args: []string{"-h"}, expErr: expOkErr, expOut: expHelp},
                {args: []string{"--help"}, expErr: expOkErr, expOut: expHelp},
-               {args: []string{}, expErr: expOkErr, expOut: expHelp},
-               {args: []string{"--ff"}, expErr: expNokErr, expOut: expExamples},
+               {args: []string{}, expErr: expArgsErr, expOut: expHelpUsage},
+               {args: []string{"--ff"}, expErr: expNokErr, expOut: expHelpUsage},
        }
 
        for _, test := range tests {
                buf := new(bytes.Buffer)
-               cmd := cli.NewGetCmdForTest()
+               cmd := cli.NewGetCmdForTest(newSdlGetApiMock)
                cmd.SetOut(buf)
                cmd.SetErr(buf)
                cmd.SetArgs(test.args)
@@ -59,3 +100,40 @@ func TestGetCmdShowHelp(t *testing.T) {
                assert.Contains(t, result, test.expOut)
        }
 }
+
+func TestGetCmdSuccess(t *testing.T) {
+
+       tests := []struct {
+               ns     string
+               keys   []string
+               result map[string]interface{}
+               expOut string
+               expErr error
+       }{
+               {ns: "testns", keys: []string{"key1"}, result: map[string]interface{}{}, expOut: "", expErr: nil},
+               {ns: "testns", keys: []string{"key1"}, result: map[string]interface{}{"key1": "1"}, expOut: "key1:1\n", expErr: nil},
+               {ns: "testns", keys: []string{"key1 key2"}, result: map[string]interface{}{"key1": "1", "key2": "2"}, expOut: "key1:1\nkey2:2\n", expErr: nil},
+               {ns: "testns", keys: []string{"key1 key3 key2"}, result: map[string]interface{}{"key1": "1", "key3": "3", "key2": "2"}, expOut: "key1:1\nkey2:2\nkey3:3\n", expErr: nil},
+               {ns: "testns", keys: []string{"key1 keyDoesNotExist"}, result: map[string]interface{}{"key1": "1"}, expOut: "key1:1\n", expErr: nil},
+       }
+       for _, test := range tests {
+               setupGetMock(test.ns, test.keys, test.result, test.expErr)
+               stdout, stderr, err := runGetCmdCli()
+
+               assert.Nil(t, err)
+               assert.Equal(t, test.expOut, stdout)
+               assert.Equal(t, "", stderr)
+               getMocks.sdlIface.AssertExpectations(t)
+       }
+}
+
+func TestGetCmdFails(t *testing.T) {
+       expErr := errors.New("Boom!")
+
+       setupGetMock("testns", []string{"key1"}, map[string]interface{}{}, expErr)
+       _, stderr, err := runGetCmdCli()
+
+       assert.Equal(t, expErr, err)
+       assert.Contains(t, stderr, expErr.Error())
+       getMocks.sdlIface.AssertExpectations(t)
+}
index dbe410b..53953a8 100644 (file)
@@ -41,6 +41,7 @@ type DbCreateCb func() *Database
 
 //iSyncStorage is an interface towards SDL SyncStorage API
 type ISyncStorage interface {
+       Get(ns string, keys []string) (map[string]interface{}, error)
        ListKeys(ns string, pattern string) ([]string, error)
        Set(ns string, pairs ...interface{}) error
        Remove(ns string, keys []string) error
index 06927cb..a17f7d3 100644 (file)
@@ -59,3 +59,8 @@ func (m *MockSdlApi) Remove(ns string, keys []string) error {
        a := m.Called(ns, keys)
        return a.Error(0)
 }
+
+func (m *MockSdlApi) Get(ns string, keys []string) (map[string]interface{}, error) {
+       a := m.Called(ns, keys)
+       return a.Get(0).(map[string]interface{}), a.Error(1)
+}