/* 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 columnNamesOut = `CLUSTER ROLE ADDRESS STATISTICS ` var primaryOut = `0 Primary 192.168.10.1:6379 UptimeInDays:1 ConnectedClients:1 ClientRecentMaxInputBuffer:2 ClientRecentMaxOutputBuffer:0 UsedMemory:2073528 UsedMemoryHuman:1.98M UsedMemoryRss:13721600 UsedMemoryRssHuman:13.09M UsedMemoryPeak:6706008 UsedMemoryPeakHuman:6.40M UsedMemoryPeakPerc:30.92% MemFragmentationRatio:6.66 MemFragmentationBytes:11379232 TotalConnectionsReceived:566 TotalCommandsProcessed:3635063 SyncFull:2 SyncPartialOk:21 SyncPartialErr:0 PubsubChannels:1 UsedCpuSys:1457.472805 UsedCpuUser:861.060018 CmdstatReplconf:calls=1090183 usec:2790911 usecPerCall:2.56 CmdstatKeys:calls=20 usec:233 usecPerCall:11.65 CmdstatRole:calls=2 usec:84 usecPerCall:42.00 CmdstatPsync:calls=23 usec:3582 usecPerCall:155.74 CmdstatMset:calls=4 usec:30 usecPerCall:7.50 CmdstatPublish:calls=804867 usec:12965499 usecPerCall:16.11 CmdstatInfo:calls=164255 usec:57935065 usecPerCall:352.71 CmdstatPing:calls=1582493 usec:3466844 usecPerCall:2.19 CmdstatClient:calls=6 usec:11 usecPerCall:2.17 CmdstatCommand:calls=482 usec:1462633 usecPerCall:3034.51 CmdstatSubscribe:calls=3 usec:11 usecPerCall:3.67 CmdstatMonitor:calls=3 usec:6 usecPerCall:2.00 Db0:keys=123 ` var replicaOut = `0 Replica 192.168.10.2:6379 UptimeInDays:2 ConnectedClients:8 ClientRecentMaxInputBuffer:3 ClientRecentMaxOutputBuffer:1 UsedMemory:2135768 UsedMemoryHuman:2.04M UsedMemoryRss:13721720 UsedMemoryRssHuman:12.48M UsedMemoryPeak:6706009 UsedMemoryPeakHuman:6.41M UsedMemoryPeakPerc:30.93% MemFragmentationRatio:6.67 MemFragmentationBytes:11379233 TotalConnectionsReceived:567 TotalCommandsProcessed:3635064 SyncFull:0 SyncPartialOk:0 SyncPartialErr:0 PubsubChannels:1 UsedCpuSys:1457.472806 UsedCpuUser:861.060019 CmdstatRole:calls=1 usec:3 usecPerCall:32.00 CmdstatMset:calls=3 usec:14 usecPerCall:7.51 CmdstatPublish:calls=804868 usec:12965498 usecPerCall:16.15 CmdstatInfo:calls=164256 usec:57935066 usecPerCall:352.72 CmdstatPing:calls=1582494 usec:3466845 usecPerCall:2.20 CmdstatCommand:calls=483 usec:1462634 usecPerCall:3034.52 CmdstatSubscribe:calls=3 usec:12 usecPerCall:3.68 CmdstatMonitor:calls=6 usec:11 usecPerCall:2.11 CmdstatConfig:calls=2 usec:1462 usecPerCall:146.74 CmdstatSlaveof:calls=1 usec:412 usecPerCall:412.00 Db0:keys=123 ` var statsMock *statisticsMock type statisticsMock struct { dbIface *mocks.MockDB dbErr error dbStatistics sdlgoredis.DbStatistics } func newStatisticsDatabaseMock() *cli.Database { db := &cli.Database{} statsMock.dbIface = new(mocks.MockDB) statsMock.dbIface.On("Statistics").Return(&statsMock.dbStatistics, statsMock.dbErr) db.Instances = append(db.Instances, statsMock.dbIface) return db } func setupStatisticsMockDb() { if statsMock == nil { statsMock = new(statisticsMock) } statsMock.dbStatistics.Stats = []*sdlgoredis.DbStatisticsInfo{} } func setupStatisticsTestcase(tb testing.TB) func(tb testing.TB) { setupStatisticsMockDb() return func(tb testing.TB) { statsMock.dbStatistics.Stats = nil } } func setupStatisticsMockDbWithPrimaryInfo() { statsMock.dbStatistics.Stats = append(statsMock.dbStatistics.Stats, &sdlgoredis.DbStatisticsInfo{ IPAddr: "192.168.10.1", Port: "6379", Info: &sdlgoredis.DbInfo{ Fields: sdlgoredis.DbInfoFields{ PrimaryRole: true, Server: sdlgoredis.ServerInfoFields{ UptimeInDays: 1, }, Clients: sdlgoredis.ClientsInfoFields{ ConnectedClients: 1, ClientRecentMaxInputBuffer: 2, ClientRecentMaxOutputBuffer: 0, }, Memory: sdlgoredis.MeroryInfoFields{ UsedMemory: 2073528, UsedMemoryHuman: "1.98M", UsedMemoryRss: 13721600, UsedMemoryRssHuman: "13.09M", UsedMemoryPeak: 6706008, UsedMemoryPeakHuman: "6.40M", UsedMemoryPeakPerc: "30.92%", MemFragmentationRatio: 6.66, MemFragmentationBytes: 11379232, }, Stats: sdlgoredis.StatsInfoFields{ TotalConnectionsReceived: 566, TotalCommandsProcessed: 3635063, SyncFull: 2, SyncPartialOk: 21, SyncPartialErr: 0, PubsubChannels: 1, }, Cpu: sdlgoredis.CpuInfoFields{ UsedCpuSys: 1457.472805, UsedCpuUser: 861.060018, }, Commandstats: sdlgoredis.CommandstatsInfoFields{ CmdstatReplconf: sdlgoredis.CommandstatsValues{ Calls: 1090183, Usec: 2790911, UsecPerCall: 2.56, }, CmdstatKeys: sdlgoredis.CommandstatsValues{ Calls: 20, Usec: 233, UsecPerCall: 11.65, }, CmdstatRole: sdlgoredis.CommandstatsValues{ Calls: 2, Usec: 84, UsecPerCall: 42.00, }, CmdstatConfig: sdlgoredis.CommandstatsValues{}, CmdstatPsync: sdlgoredis.CommandstatsValues{ Calls: 23, Usec: 3582, UsecPerCall: 155.74, }, CmdstatMset: sdlgoredis.CommandstatsValues{ Calls: 4, Usec: 30, UsecPerCall: 7.50, }, CmdstatPublish: sdlgoredis.CommandstatsValues{ Calls: 804867, Usec: 12965499, UsecPerCall: 16.11, }, CmdstatInfo: sdlgoredis.CommandstatsValues{ Calls: 164255, Usec: 57935065, UsecPerCall: 352.71, }, CmdstatPing: sdlgoredis.CommandstatsValues{ Calls: 1582493, Usec: 3466844, UsecPerCall: 2.19, }, CmdstatClient: sdlgoredis.CommandstatsValues{ Calls: 6, Usec: 11, UsecPerCall: 2.17, }, CmdstatCommand: sdlgoredis.CommandstatsValues{ Calls: 482, Usec: 1462633, UsecPerCall: 3034.51, }, CmdstatSubscribe: sdlgoredis.CommandstatsValues{ Calls: 3, Usec: 11, UsecPerCall: 3.67, }, CmdstatMonitor: sdlgoredis.CommandstatsValues{ Calls: 3, Usec: 6, UsecPerCall: 2.00, }, CmdstatSlaveof: sdlgoredis.CommandstatsValues{}, }, Keyspace: sdlgoredis.KeyspaceInfoFields{ Db: sdlgoredis.KeyspaceValues{ Keys: 123, }, }, }, }, }, ) } func setupStatisticsMockDbWithReplicaInfo() { statsMock.dbStatistics.Stats = append(statsMock.dbStatistics.Stats, &sdlgoredis.DbStatisticsInfo{ IPAddr: "192.168.10.2", Port: "6379", Info: &sdlgoredis.DbInfo{ Fields: sdlgoredis.DbInfoFields{ PrimaryRole: false, Server: sdlgoredis.ServerInfoFields{ UptimeInDays: 2, }, Clients: sdlgoredis.ClientsInfoFields{ ConnectedClients: 8, ClientRecentMaxInputBuffer: 3, ClientRecentMaxOutputBuffer: 1, }, Memory: sdlgoredis.MeroryInfoFields{ UsedMemory: 2135768, UsedMemoryHuman: "2.04M", UsedMemoryRss: 13721720, UsedMemoryRssHuman: "12.48M", UsedMemoryPeak: 6706009, UsedMemoryPeakHuman: "6.41M", UsedMemoryPeakPerc: "30.93%", MemFragmentationRatio: 6.67, MemFragmentationBytes: 11379233, }, Stats: sdlgoredis.StatsInfoFields{ TotalConnectionsReceived: 567, TotalCommandsProcessed: 3635064, SyncFull: 0, SyncPartialOk: 0, SyncPartialErr: 0, PubsubChannels: 1, }, Cpu: sdlgoredis.CpuInfoFields{ UsedCpuSys: 1457.472806, UsedCpuUser: 861.060019, }, Commandstats: sdlgoredis.CommandstatsInfoFields{ CmdstatReplconf: sdlgoredis.CommandstatsValues{}, CmdstatKeys: sdlgoredis.CommandstatsValues{}, CmdstatRole: sdlgoredis.CommandstatsValues{ Calls: 1, Usec: 3, UsecPerCall: 32.00, }, CmdstatConfig: sdlgoredis.CommandstatsValues{ Calls: 2, Usec: 1462, UsecPerCall: 146.74, }, CmdstatPsync: sdlgoredis.CommandstatsValues{}, CmdstatMset: sdlgoredis.CommandstatsValues{ Calls: 3, Usec: 14, UsecPerCall: 7.51, }, CmdstatPublish: sdlgoredis.CommandstatsValues{ Calls: 804868, Usec: 12965498, UsecPerCall: 16.15, }, CmdstatInfo: sdlgoredis.CommandstatsValues{ Calls: 164256, Usec: 57935066, UsecPerCall: 352.72, }, CmdstatPing: sdlgoredis.CommandstatsValues{ Calls: 1582494, Usec: 3466845, UsecPerCall: 2.20, }, CmdstatClient: sdlgoredis.CommandstatsValues{}, CmdstatCommand: sdlgoredis.CommandstatsValues{ Calls: 483, Usec: 1462634, UsecPerCall: 3034.52, }, CmdstatSubscribe: sdlgoredis.CommandstatsValues{ Calls: 3, Usec: 12, UsecPerCall: 3.68, }, CmdstatMonitor: sdlgoredis.CommandstatsValues{ Calls: 6, Usec: 11, UsecPerCall: 2.11, }, CmdstatSlaveof: sdlgoredis.CommandstatsValues{ Calls: 1, Usec: 412, UsecPerCall: 412.00, }, }, Keyspace: sdlgoredis.KeyspaceInfoFields{ Db: sdlgoredis.KeyspaceValues{ Keys: 123, }, }, }, }, }, ) } func runStatisticsCli() (string, error) { buf := new(bytes.Buffer) cmd := cli.NewStatisticsCmd(newStatisticsDatabaseMock) cmd.SetOut(buf) err := cmd.Execute() return buf.String(), err } func TestCliStatisticsCanShowHelp(t *testing.T) { var expOkErr error expHelp := "Usage:\n " + "statistics [flags]" expNokErr := errors.New("unknown flag: --some-unknown-flag") expArgCntErr := errors.New("accepts 0 arg(s), received 1") tests := []struct { args string expErr error expOutput string }{ {args: "-h", expErr: expOkErr, expOutput: expHelp}, {args: "--help", expErr: expOkErr, expOutput: expHelp}, {args: "--some-unknown-flag", expErr: expNokErr, expOutput: expHelp}, {args: "some-extra-argument", expErr: expArgCntErr, expOutput: expHelp}, } for _, test := range tests { buf := new(bytes.Buffer) cmd := cli.NewStatisticsCmd(newStatisticsDatabaseMock) cmd.SetOut(buf) cmd.SetArgs([]string{test.args}) err := cmd.Execute() stdout := buf.String() assert.Equal(t, test.expErr, err) assert.Contains(t, stdout, test.expOutput) } } func TestCliStatisticsShowOnlyColumnsNames(t *testing.T) { teardownTest := setupStatisticsTestcase(t) defer teardownTest(t) expOut := "CLUSTER ROLE ADDRESS STATISTICS\n" stdout, err := runStatisticsCli() assert.Nil(t, err) assert.Equal(t, expOut, stdout) } func TestCliStatisticsShowPrimaryInfo(t *testing.T) { teardownTest := setupStatisticsTestcase(t) defer teardownTest(t) setupStatisticsMockDbWithPrimaryInfo() expOut := columnNamesOut + primaryOut stdout, err := runStatisticsCli() assert.Nil(t, err) assert.Equal(t, expOut, stdout) } func TestCliStatisticsShowPrimaryAndReplicaInfo(t *testing.T) { teardownTest := setupStatisticsTestcase(t) defer teardownTest(t) setupStatisticsMockDbWithPrimaryInfo() setupStatisticsMockDbWithReplicaInfo() expOut := columnNamesOut + primaryOut + replicaOut stdout, err := runStatisticsCli() assert.Nil(t, err) assert.Equal(t, expOut, stdout) } func TestCliStatisticsRaisesError(t *testing.T) { teardownTest := setupStatisticsTestcase(t) defer teardownTest(t) expErr := errors.New("Boom!") expOut := "Usage:\n statistics [flags]" statsMock.dbErr = errors.New("Boom!") stdout, err := runStatisticsCli() assert.Equal(t, expErr, err) assert.Contains(t, stdout, expOut) }