"gerrit.o-ran-sc.org/r/ric-plt/sdlgo/internal/sdlgoredis"
"github.com/spf13/cobra"
"os"
+ "text/tabwriter"
)
func init() {
func newHealthCheckCmd(dbCreateCb DbCreateCb) *cobra.Command {
cmd := &cobra.Command{
Use: "healthcheck",
- Short: "Validate database healthiness",
- Long: `Validate database healthiness`,
+ Short: "Validate SDL database healthiness",
+ Long: `Validate SDL database healthiness`,
Args: cobra.ExactArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
- out, err := runHealthCheck(dbCreateCb)
- cmd.Println(out)
- if err != nil {
- cmd.PrintErrf("%s\n", buf.String())
- }
+ states, err := runHealthCheck(dbCreateCb)
+ printHealthStatus(cmd, states)
return err
},
}
return cmd
}
-func runHealthCheck(dbCreateCb DbCreateCb) (string, error) {
+func runHealthCheck(dbCreateCb DbCreateCb) ([]sdlgoredis.DbState, error) {
var anyErr error
- var str string
var states []sdlgoredis.DbState
for _, dbInst := range dbCreateCb().Instances {
state, err := dbInst.State()
}
states = append(states, *state)
}
- str = writeStateResults(states)
- return str, anyErr
+ return states, anyErr
}
-func writeStateResults(dbStates []sdlgoredis.DbState) string {
- var str string
+func printHealthStatus(cmd *cobra.Command, dbStates []sdlgoredis.DbState) {
var anyErr error
+ w := tabwriter.NewWriter(cmd.OutOrStdout(), 6, 4, 3, ' ', 0)
+ fmt.Fprintln(w, "CLUSTER\tROLE\tADDRESS\tSTATUS\tERROR\t")
+
for i, dbState := range dbStates {
if err := dbState.IsOnline(); err != nil {
anyErr = err
}
- str = str + fmt.Sprintf(" SDL DB backend #%d\n", (i+1))
- pAddr := dbState.PrimaryDbState.GetAddress()
- err := dbState.PrimaryDbState.IsOnline()
- if err == nil {
- str = str + fmt.Sprintf(" Primary (%s): OK\n", pAddr)
- } else {
- str = str + fmt.Sprintf(" Primary (%s): NOK\n", pAddr)
- str = str + fmt.Sprintf(" %s\n", err.Error())
+ if err := printPrimaryHealthStatus(w, i, &dbState); err != nil {
+ anyErr = err
+ }
+ if err := printReplicasHealthStatus(w, i, &dbState); err != nil {
+ anyErr = err
}
- if dbState.ReplicasDbState != nil {
- for j, rInfo := range dbState.ReplicasDbState.States {
- err := rInfo.IsOnline()
- if err == nil {
- str = str + fmt.Sprintf(" Replica #%d (%s): OK\n", (j+1), rInfo.GetAddress())
- } else {
- str = str + fmt.Sprintf(" Replica #%d (%s): NOK\n", (j+1), rInfo.GetAddress())
- str = str + fmt.Sprintf(" %s\n", err.Error())
- }
- }
+ if err := printSentinelsHealthStatus(w, i, &dbState); err != nil {
+ anyErr = err
}
- if dbState.SentinelsDbState != nil {
- for k, sInfo := range dbState.SentinelsDbState.States {
- err := sInfo.IsOnline()
- if err != nil {
- str = str + fmt.Sprintf(" Sentinel #%d (%s): NOK\n", (k+1), sInfo.GetAddress())
- str = str + fmt.Sprintf(" %s\n", err.Error())
- }
+ }
+ if anyErr == nil {
+ cmd.Println("Overall status: OK")
+ } else {
+ cmd.Println("Overall status: NOK")
+ }
+ cmd.Println("")
+ w.Flush()
+}
+
+func printPrimaryHealthStatus(w *tabwriter.Writer, clusterID int, dbState *sdlgoredis.DbState) error {
+ addr := printAddress(dbState.PrimaryDbState.GetAddress())
+ err := dbState.PrimaryDbState.IsOnline()
+ if err != nil {
+ fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t\n", clusterID, "primary", addr, "NOK", err.Error())
+ } else {
+ fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t\n", clusterID, "primary", addr, "OK", "<none>")
+ }
+ return err
+}
+
+func printReplicasHealthStatus(w *tabwriter.Writer, clusterID int, dbState *sdlgoredis.DbState) error {
+ var anyErr error
+
+ if dbState.ReplicasDbState != nil {
+ if dbState.ConfigNodeCnt > len(dbState.ReplicasDbState.States)+1 {
+ err := fmt.Errorf("Configured DBAAS nodes %d but only 1 primary and %d replicas",
+ dbState.ConfigNodeCnt, len(dbState.ReplicasDbState.States))
+ fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t\n", clusterID, "replica", "<none>", "NOK", err.Error())
+ anyErr = err
+ }
+ for _, state := range dbState.ReplicasDbState.States {
+ if err := printReplicaHealthStatus(w, clusterID, state); err != nil {
+ anyErr = err
}
}
}
- if anyErr == nil {
- str = fmt.Sprintf("Overall status: OK\n\n") + str
+ return anyErr
+}
+
+func printReplicaHealthStatus(w *tabwriter.Writer, clusterID int, dbState *sdlgoredis.ReplicaDbState) error {
+ addr := printAddress(dbState.GetAddress())
+ err := dbState.IsOnline()
+ if err != nil {
+ fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t\n", clusterID, "replica", addr, "NOK", err.Error())
} else {
- str = fmt.Sprintf("Overall status: NOK\n\n") + str
+ fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t\n", clusterID, "replica", addr, "OK", "<none>")
+ }
+ return err
+}
+
+func printSentinelsHealthStatus(w *tabwriter.Writer, clusterID int, dbState *sdlgoredis.DbState) error {
+ var anyErr error
+ if dbState.SentinelsDbState != nil {
+ for _, state := range dbState.SentinelsDbState.States {
+ if err := printSentinelHealthStatus(w, clusterID, state); err != nil {
+ anyErr = err
+ }
+ }
+ }
+ return anyErr
+}
+func printSentinelHealthStatus(w *tabwriter.Writer, clusterID int, dbState *sdlgoredis.SentinelDbState) error {
+ err := dbState.IsOnline()
+ if err != nil {
+ fmt.Fprintf(w, "%d\t%s\t%s\t%s\t%s\t\n", clusterID, "sentinel", dbState.GetAddress(), "NOK", err.Error())
+ }
+ return err
+}
+
+func printAddress(address string) string {
+ if address == "" {
+ return "<none>"
}
- return str
+ return address
}
dbState sdlgoredis.DbState
}
-func setupHcMockPrimaryDb(ip, port string) {
+func setupHcMockPrimaryDb(ip, port string, nodes int) {
hcMocks = new(healthCheckMocks)
+ hcMocks.dbState.ConfigNodeCnt = nodes
hcMocks.dbState.PrimaryDbState.Fields.Role = "master"
hcMocks.dbState.PrimaryDbState.Fields.Ip = ip
hcMocks.dbState.PrimaryDbState.Fields.Port = port
hcMocks.dbState.PrimaryDbState.Fields.Flags = "master"
+ hcMocks.dbState.ReplicasDbState = new(sdlgoredis.ReplicasDbState)
+ hcMocks.dbState.ReplicasDbState.States = []*sdlgoredis.ReplicaDbState{}
+ hcMocks.dbState.SentinelsDbState = new(sdlgoredis.SentinelsDbState)
+ hcMocks.dbState.SentinelsDbState.States = []*sdlgoredis.SentinelDbState{}
}
-func setupHcMockReplicaDb(ip, port string) {
+func setupHcMockReplicaDb(nodes int) {
hcMocks = new(healthCheckMocks)
+ hcMocks.dbState.ConfigNodeCnt = nodes
hcMocks.dbState.ReplicasDbState = new(sdlgoredis.ReplicasDbState)
- hcMocks.dbState.ReplicasDbState.States = []*sdlgoredis.ReplicaDbState{
- &sdlgoredis.ReplicaDbState{
- Fields: sdlgoredis.ReplicaDbStateFields{
- Role: "slave",
- },
- },
- }
+ hcMocks.dbState.ReplicasDbState.States = []*sdlgoredis.ReplicaDbState{}
+ hcMocks.dbState.SentinelsDbState = new(sdlgoredis.SentinelsDbState)
+ hcMocks.dbState.SentinelsDbState.States = []*sdlgoredis.SentinelDbState{}
}
-func setupHcMockSentinelDb(ip, port string) {
+func setupHcMockSentinelDb(ip, port string, nodes int) {
hcMocks = new(healthCheckMocks)
+ hcMocks.dbState.ConfigNodeCnt = nodes
hcMocks.dbState.SentinelsDbState = new(sdlgoredis.SentinelsDbState)
- hcMocks.dbState.SentinelsDbState.States = []*sdlgoredis.SentinelDbState{
- &sdlgoredis.SentinelDbState{
- Fields: sdlgoredis.SentinelDbStateFields{
- Ip: ip,
- Port: port,
- },
- },
- }
+ hcMocks.dbState.SentinelsDbState.States = []*sdlgoredis.SentinelDbState{}
}
func addHcMockReplicaDbState(ip, port, primaryLinkOk string) {
}
func TestCliHealthCheckCanShowHaDeploymentOkStatusCorrectly(t *testing.T) {
- setupHcMockPrimaryDb("10.20.30.40", "6379")
+ expOut :=
+ "Overall status: OK\n\n" +
+ "CLUSTER ROLE ADDRESS STATUS ERROR \n" +
+ "0 primary 10.20.30.40:6379 OK <none> \n" +
+ "0 replica 1.2.3.4:6379 OK <none> \n" +
+ "0 replica 5.6.7.8:6379 OK <none> \n"
+ setupHcMockPrimaryDb("10.20.30.40", "6379", 3)
addHcMockReplicaDbState("1.2.3.4", "6379", "ok")
addHcMockReplicaDbState("5.6.7.8", "6379", "ok")
addHcMockSentinelDbState("1.2.3.4", "26379", "sentinel")
stdout, err := runHcCli()
assert.Nil(t, err)
- assert.Contains(t, stdout, "Overall status: OK")
- assert.Contains(t, stdout, "Primary (10.20.30.40:6379): OK")
- assert.Contains(t, stdout, "Replica #1 (1.2.3.4:6379): OK")
- assert.Contains(t, stdout, "Replica #2 (5.6.7.8:6379): OK")
-
+ assert.Equal(t, expOut, stdout)
}
func TestCliHealthCheckCanShowHaDeploymentStatusCorrectlyWhenOneReplicaStateNotUp(t *testing.T) {
- setupHcMockPrimaryDb("10.20.30.40", "6379")
+ expOut :=
+ "Overall status: NOK\n\n" +
+ "CLUSTER ROLE ADDRESS STATUS ERROR \n" +
+ "0 primary 10.20.30.40:6379 OK <none> \n" +
+ "0 replica 1.2.3.4:6379 OK <none> \n" +
+ "0 replica 5.6.7.8:6379 NOK Replica link to the primary is down \n"
+ setupHcMockPrimaryDb("10.20.30.40", "6379", 3)
addHcMockReplicaDbState("1.2.3.4", "6379", "ok")
addHcMockReplicaDbState("5.6.7.8", "6379", "nok")
addHcMockSentinelDbState("1.2.3.4", "26379", "sentinel")
stdout, err := runHcCli()
assert.Nil(t, err)
- assert.Contains(t, stdout, "Overall status: NOK")
- assert.Contains(t, stdout, "Replica #2 (5.6.7.8:6379): NOK")
- assert.Contains(t, stdout, "Replica link to the primary is down")
+ assert.Equal(t, expOut, stdout)
}
func TestCliHealthCheckCanShowHaDeploymentStatusCorrectlyWhenOneSentinelStateNotUp(t *testing.T) {
- setupHcMockPrimaryDb("10.20.30.40", "6379")
+ expOut :=
+ "Overall status: NOK\n\n" +
+ "CLUSTER ROLE ADDRESS STATUS ERROR \n" +
+ "0 primary 10.20.30.40:6379 OK <none> \n" +
+ "0 replica 1.2.3.4:6379 OK <none> \n" +
+ "0 replica 5.6.7.8:6379 OK <none> \n" +
+ "0 sentinel 1.2.3.4:26379 NOK Sentinel flags are 'some-failure', expected 'sentinel' \n"
+ setupHcMockPrimaryDb("10.20.30.40", "6379", 3)
addHcMockReplicaDbState("1.2.3.4", "6379", "ok")
addHcMockReplicaDbState("5.6.7.8", "6379", "ok")
addHcMockSentinelDbState("1.2.3.4", "26379", "some-failure")
stdout, err := runHcCli()
assert.Nil(t, err)
- assert.Contains(t, stdout, "Overall status: NOK")
- assert.Contains(t, stdout, "Replica #1 (1.2.3.4:6379): OK")
- assert.Contains(t, stdout, "Replica #2 (5.6.7.8:6379): OK")
- assert.Contains(t, stdout, "Sentinel #1 (1.2.3.4:26379): NOK")
- assert.Contains(t, stdout, "Sentinel flags are 'some-failure', expected 'sentinel'")
+ assert.Equal(t, expOut, stdout)
+}
+
+func TestCliHealthCheckCanShowHaDeploymentStatusCorrectlyWhenNoReplicas(t *testing.T) {
+ expOut :=
+ "Overall status: NOK\n\n" +
+ "CLUSTER ROLE ADDRESS STATUS ERROR \n" +
+ "0 primary 10.20.30.40:6379 OK <none> \n" +
+ "0 replica <none> NOK Configured DBAAS nodes 3 but only 1 primary and 0 replicas \n"
+ setupHcMockPrimaryDb("10.20.30.40", "6379", 3)
+ addHcMockSentinelDbState("1.2.3.4", "26379", "sentinel")
+ addHcMockSentinelDbState("5.6.7.8", "26379", "sentinel")
+
+ stdout, err := runHcCli()
+
+ assert.Nil(t, err)
+ assert.Equal(t, expOut, stdout)
}
func TestCliHealthCheckCanShowHaDeploymentStatusCorrectlyWhenDbStateQueryFails(t *testing.T) {
- setupHcMockPrimaryDb("10.20.30.40", "6379")
+ setupHcMockPrimaryDb("10.20.30.40", "6379", 3)
hcMocks.dbErr = errors.New("Some error")
buf := new(bytes.Buffer)
stderr := buf.String()
assert.Equal(t, hcMocks.dbErr, err)
- assert.Contains(t, stderr, "Error: "+hcMocks.dbErr.Error())
+ assert.Contains(t, stderr, "Error: Some error")
}
func TestCliHealthCheckCanShowHaDeploymentOkStatusCorrectlyWhenDbStateIsFromReplicaOnly(t *testing.T) {
- setupHcMockReplicaDb("1.2.3.4", "6379")
+ expOut :=
+ "Overall status: NOK\n\n" +
+ "CLUSTER ROLE ADDRESS STATUS ERROR \n" +
+ "0 primary <none> NOK No primary DB, current role '' \n" +
+ "0 replica 1.2.3.4:6379 NOK Replica link to the primary is down \n" +
+ "0 replica 5.6.7.8:6379 NOK Replica link to the primary is down \n"
+ setupHcMockReplicaDb(3)
+ addHcMockReplicaDbState("1.2.3.4", "6379", "nok")
+ addHcMockReplicaDbState("5.6.7.8", "6379", "nok")
stdout, err := runHcCli()
assert.Nil(t, err)
- assert.Contains(t, stdout, "Overall status: NOK")
- assert.Contains(t, stdout, "Primary (): NOK")
+ assert.Equal(t, expOut, stdout)
}
func TestCliHealthCheckCanShowHaDeploymentOkStatusCorrectlyWhenDbStateIsFromSentinelOnly(t *testing.T) {
- setupHcMockSentinelDb("1.2.3.4", "26379")
+ expOut :=
+ "Overall status: NOK\n\n" +
+ "CLUSTER ROLE ADDRESS STATUS ERROR \n" +
+ "0 primary <none> NOK No primary DB, current role '' \n"
+ setupHcMockSentinelDb("1.2.3.4", "26379", 3)
stdout, err := runHcCli()
assert.Nil(t, err)
- assert.Contains(t, stdout, "Overall status: NOK")
- assert.Contains(t, stdout, "Primary (): NOK")
+ assert.Equal(t, expOut, stdout)
}
func TestCliHealthCheckCanShowStandaloneDeploymentOkStatusCorrectly(t *testing.T) {
- setupHcMockPrimaryDb("10.20.30.40", "6379")
+ expOut :=
+ "Overall status: OK\n\n" +
+ "CLUSTER ROLE ADDRESS STATUS ERROR \n" +
+ "0 primary 10.20.30.40:6379 OK <none> \n"
+ setupHcMockPrimaryDb("10.20.30.40", "6379", 1)
stdout, err := runHcCli()
assert.Nil(t, err)
- assert.Contains(t, stdout, "Overall status: OK")
- assert.Contains(t, stdout, "Primary (10.20.30.40:6379): OK")
+ assert.Equal(t, expOut, stdout)
}
}
func setupHaEnv(commandsExists bool) (*pubSubMock, *clientMock, *sdlgoredis.DB) {
- psm, cm, _, db := setupHaEnvWithSentinels(commandsExists)
+ psm, cm, _, db := setupHaEnvWithSentinels(commandsExists, "3")
return psm, cm, db
}
-func setupHaEnvWithSentinels(commandsExists bool) (*pubSubMock, *clientMock, []*MockRedisSentinel, *sdlgoredis.DB) {
+func setupHaEnvWithSentinels(commandsExists bool, nodeCnt string) (*pubSubMock, *clientMock, []*MockRedisSentinel, *sdlgoredis.DB) {
setupVals := setupEnv(
commandsExists,
"service-ricplt-dbaas-tcp-cluster-0.ricplt",
"dbaasmaster",
"26376",
"",
- "3",
+ nodeCnt,
)
return setupVals.pubSubMock[0], setupVals.rClient[0], setupVals.rSentinel, setupVals.db[0]
}
-func setupSingleEnv(commandsExists bool) (*pubSubMock, *clientMock, *sdlgoredis.DB) {
+func setupSingleEnv(commandsExists bool, nodeCnt string) (*pubSubMock, *clientMock, *sdlgoredis.DB) {
setupVals := setupEnv(
commandsExists,
"service-ricplt-dbaas-tcp-cluster-0.ricplt",
- "6376", "", "", "", "",
+ "6376", "", "", "", nodeCnt,
)
return setupVals.pubSubMock[0], setupVals.rClient[0], setupVals.db[0]
}
osmock.On("Getenv", "DBAAS_MASTER_NAME", "").Return(msname)
osmock.On("Getenv", "DBAAS_SERVICE_SENTINEL_PORT", "").Return(sntport)
osmock.On("Getenv", "DBAAS_CLUSTER_ADDR_LIST", "").Return(clsaddrlist)
- osmock.On("Getenv", "DBAAS_SERVICE_NODE_COUNT", "").Return(nodeCnt)
+ osmock.On("Getenv", "DBAAS_NODE_COUNT", "1").Return(nodeCnt)
pubSubMock, subscribeNotifications := setSubscribeNotifications()
smock := new(MockRedisSentinel)
return ret
}
+func newMockRedisMasterCallResp(role, ip, port, flag string) map[string]string {
+ resp := map[string]string{}
+ if role != "" {
+ resp["role-reported"] = role
+ resp["ip"] = ip
+ resp["port"] = port
+ resp["flags"] = flag
+ }
+ return resp
+}
+
+type mockRedisSlaves struct {
+ resp []interface{}
+}
+
+func newMockRedisSlavesCall() *mockRedisSlaves {
+ return new(mockRedisSlaves)
+}
+
+func (mrr *mockRedisSlaves) add(role, ip, port, link, flag string) {
+ mrr.resp = append(mrr.resp,
+ []interface{}{
+ "role-reported", role,
+ "ip", ip,
+ "port", port,
+ "master-link-status", link,
+ "flags", flag,
+ },
+ )
+}
+
+type mockRedisSentinels struct {
+ resp []interface{}
+}
+
+func newMockRedisSentinelsCall() *mockRedisSentinels {
+ return new(mockRedisSentinels)
+}
+
+func (mrs *mockRedisSentinels) add(ip, port, flag string) {
+ mrs.resp = append(mrs.resp,
+ []interface{}{
+ "ip", ip,
+ "port", port,
+ "flags", flag,
+ },
+ )
+}
+
+type ExpDbState struct {
+ s sdlgoredis.DbState
+}
+
+func newExpDbState(nodeCnt int, err error) *ExpDbState {
+ state := new(ExpDbState)
+ state.s.ConfigNodeCnt = nodeCnt
+ state.s.Err = err
+ return state
+}
+
+func (edbs *ExpDbState) addPrimary(role, ip, port, flag string, err error) {
+ edbs.s.PrimaryDbState.Err = err
+ edbs.s.PrimaryDbState.Fields = sdlgoredis.PrimaryDbStateFields{
+ Role: role,
+ Ip: ip,
+ Port: port,
+ Flags: flag,
+ }
+}
+
+func (edbs *ExpDbState) addReplica(role, ip, port, link, flag string, err error) {
+ if edbs.s.ReplicasDbState == nil {
+ edbs.s.ReplicasDbState = new(sdlgoredis.ReplicasDbState)
+ edbs.s.ReplicasDbState.States = make([]*sdlgoredis.ReplicaDbState, 0)
+ }
+ edbs.s.ReplicasDbState.Err = err
+ if ip != "" || port != "" || link != "" || flag != "" {
+ edbs.s.ReplicasDbState.States = append(edbs.s.ReplicasDbState.States,
+ &sdlgoredis.ReplicaDbState{
+ Fields: sdlgoredis.ReplicaDbStateFields{
+ Role: role,
+ Ip: ip,
+ Port: port,
+ PrimaryLinkStatus: link,
+ Flags: flag,
+ },
+ },
+ )
+ }
+}
+
+func (edbs *ExpDbState) addSentinel(ip, port, flag string, err error) {
+ if edbs.s.SentinelsDbState == nil {
+ edbs.s.SentinelsDbState = new(sdlgoredis.SentinelsDbState)
+ edbs.s.SentinelsDbState.States = make([]*sdlgoredis.SentinelDbState, 0)
+ }
+ edbs.s.SentinelsDbState.Err = err
+ if ip != "" || port != "" || flag != "" {
+ edbs.s.SentinelsDbState.States = append(edbs.s.SentinelsDbState.States,
+ &sdlgoredis.SentinelDbState{
+ Fields: sdlgoredis.SentinelDbStateFields{
+ Ip: ip,
+ Port: port,
+ Flags: flag,
+ },
+ },
+ )
+ }
+}
+
func TestCloseDbSuccessfully(t *testing.T) {
_, r, db := setupHaEnv(true)
r.On("Close").Return(nil)
r.AssertExpectations(t)
}
+func TestInfoOfStandalonePrimaryRedisFailureWhenIntConversionFails(t *testing.T) {
+ expErr := errors.New("Info reply error: strconv.ParseUint: parsing \"not-int\": invalid syntax")
+ _, r, db := setupHaEnv(true)
+ redisInfo := "# Replication\r\n" +
+ "role:master\r\n" +
+ "connected_slaves:not-int\r\n" +
+ "min_slaves_good_slaves:0\r\n"
+ expInfo := &sdlgoredis.DbInfo{
+ Fields: sdlgoredis.DbInfoFields{
+ PrimaryRole: true,
+ ConnectedReplicaCnt: 0,
+ },
+ }
+
+ r.On("Info", []string{"all"}).Return(redis.NewStringResult(redisInfo, nil))
+ info, err := db.Info()
+ assert.Equal(t, expErr, err)
+ assert.Equal(t, expInfo, info)
+ r.AssertExpectations(t)
+}
+
func TestInfoWithGibberishContentSuccessfully(t *testing.T) {
_, r, db := setupHaEnv(true)
redisInfo := "!#¤%&?+?´-\r\n"
}
func TestStateWithPrimaryAndTwoReplicaRedisSuccessfully(t *testing.T) {
- _, r, s, db := setupHaEnvWithSentinels(true)
- redisPrimaryState := map[string]string{
- "role-reported": "master",
- }
- redisReplicasState := make([]interface{}, 2)
- redisReplicasState[0] = []interface{}{
- "role-reported", "slave",
- "ip", "10.20.30.40",
- "port", "6379",
- "flags", "slave",
- "master-link-status", "up",
- }
- redisReplicasState[1] = []interface{}{
- "master-link-status", "up",
- "ip", "10.20.30.50",
- "flags", "slave",
- "port", "30000",
- "role-reported", "slave",
- }
- redisSentinelsState := make([]interface{}, 2)
- redisSentinelsState[0] = []interface{}{
- "ip", "10.20.30.40",
- "port", "26379",
- "flags", "sentinel",
- }
- redisSentinelsState[1] = []interface{}{
- "ip", "10.20.30.50",
- "flags", "sentinel",
- "port", "30001",
- }
-
- expState := &sdlgoredis.DbState{
- PrimaryDbState: sdlgoredis.PrimaryDbState{
- Fields: sdlgoredis.PrimaryDbStateFields{
- Role: "master",
- },
- },
- ReplicasDbState: &sdlgoredis.ReplicasDbState{
- States: []*sdlgoredis.ReplicaDbState{
- &sdlgoredis.ReplicaDbState{
- Fields: sdlgoredis.ReplicaDbStateFields{
- Role: "slave",
- Ip: "10.20.30.40",
- Port: "6379",
- PrimaryLinkStatus: "up",
- Flags: "slave",
- },
- },
- &sdlgoredis.ReplicaDbState{
- Fields: sdlgoredis.ReplicaDbStateFields{
- Role: "slave",
- Ip: "10.20.30.50",
- Port: "30000",
- PrimaryLinkStatus: "up",
- Flags: "slave",
- },
- },
- },
- },
- SentinelsDbState: &sdlgoredis.SentinelsDbState{
- States: []*sdlgoredis.SentinelDbState{
- &sdlgoredis.SentinelDbState{
- Fields: sdlgoredis.SentinelDbStateFields{
- Ip: "10.20.30.40",
- Port: "26379",
- Flags: "sentinel",
- },
- },
- &sdlgoredis.SentinelDbState{
- Fields: sdlgoredis.SentinelDbStateFields{
- Ip: "10.20.30.50",
- Port: "30001",
- Flags: "sentinel",
- },
- },
- },
- },
- }
+ _, r, s, db := setupHaEnvWithSentinels(true, "3")
+
+ redisPrimaryState := newMockRedisMasterCallResp("master", "10.20.30.30", "6379", "master")
+ redisReplicasState := newMockRedisSlavesCall()
+ redisReplicasState.add("slave", "10.20.30.40", "6379", "up", "slave")
+ redisReplicasState.add("slave", "10.20.30.50", "30000", "up", "slave")
+ redisSentinelsState := newMockRedisSentinelsCall()
+ redisSentinelsState.add("10.20.30.40", "26379", "sentinel")
+ redisSentinelsState.add("10.20.30.50", "30001", "sentinel")
+
+ expState := newExpDbState(3, nil)
+ expState.addPrimary("master", "10.20.30.30", "6379", "master", nil)
+ expState.addReplica("slave", "10.20.30.40", "6379", "up", "slave", nil)
+ expState.addReplica("slave", "10.20.30.50", "30000", "up", "slave", nil)
+ expState.addSentinel("10.20.30.40", "26379", "sentinel", nil)
+ expState.addSentinel("10.20.30.50", "30001", "sentinel", nil)
s[0].On("Master", "dbaasmaster").Return(redis.NewStringStringMapResult(redisPrimaryState, nil))
- s[0].On("Slaves", "dbaasmaster").Return(redis.NewSliceResult(redisReplicasState, nil))
- s[0].On("Sentinels", "dbaasmaster").Return(redis.NewSliceResult(redisSentinelsState, nil))
+ s[0].On("Slaves", "dbaasmaster").Return(redis.NewSliceResult(redisReplicasState.resp, nil))
+ s[0].On("Sentinels", "dbaasmaster").Return(redis.NewSliceResult(redisSentinelsState.resp, nil))
ret, err := db.State()
assert.Nil(t, err)
- assert.Equal(t, expState, ret)
+ assert.Equal(t, expState.s, *ret)
r.AssertExpectations(t)
}
-func TestStateWithPrimaryAndOneReplicaRedisFailureInPrimaryRedisCall(t *testing.T) {
- _, r, s, db := setupHaEnvWithSentinels(true)
- redisPrimaryState := map[string]string{}
- redisReplicasState := make([]interface{}, 1)
- redisReplicasState[0] = []interface{}{
- "role-reported", "slave",
- "ip", "10.20.30.40",
- "port", "6379",
- "flags", "slave",
- "master-link-status", "up",
- }
- redisSentinelsState := make([]interface{}, 1)
- redisSentinelsState[0] = []interface{}{
- "ip", "10.20.30.40",
- "port", "26379",
- "flags", "sentinel",
- }
+func TestStateWithPrimaryAndTwoReplicaRedisFailureInPrimaryRedisCall(t *testing.T) {
+ expErr := errors.New("Some error")
+ _, r, s, db := setupHaEnvWithSentinels(true, "3")
- expState := &sdlgoredis.DbState{
- PrimaryDbState: sdlgoredis.PrimaryDbState{
- Err: errors.New("Some error"),
- },
- ReplicasDbState: &sdlgoredis.ReplicasDbState{
- States: []*sdlgoredis.ReplicaDbState{
- &sdlgoredis.ReplicaDbState{
- Fields: sdlgoredis.ReplicaDbStateFields{
- Role: "slave",
- Ip: "10.20.30.40",
- Port: "6379",
- PrimaryLinkStatus: "up",
- Flags: "slave",
- },
- },
- },
- },
- SentinelsDbState: &sdlgoredis.SentinelsDbState{
- States: []*sdlgoredis.SentinelDbState{
- &sdlgoredis.SentinelDbState{
- Fields: sdlgoredis.SentinelDbStateFields{
- Ip: "10.20.30.40",
- Port: "26379",
- Flags: "sentinel",
- },
- },
- },
- },
- }
+ redisPrimaryState := newMockRedisMasterCallResp("master", "10.20.30.30", "6379", "master")
+ redisReplicasState := newMockRedisSlavesCall()
+ redisReplicasState.add("slave", "10.20.30.40", "6379", "up", "slave")
+ redisReplicasState.add("slave", "10.20.30.50", "30000", "up", "slave")
+ redisSentinelsState := newMockRedisSentinelsCall()
+ redisSentinelsState.add("10.20.30.40", "26379", "sentinel")
+ redisSentinelsState.add("10.20.30.50", "30001", "sentinel")
+
+ expState := newExpDbState(3, nil)
+ expState.addPrimary("", "", "", "", expErr)
+ expState.addReplica("slave", "10.20.30.40", "6379", "up", "slave", nil)
+ expState.addReplica("slave", "10.20.30.50", "30000", "up", "slave", nil)
+ expState.addSentinel("10.20.30.40", "26379", "sentinel", nil)
+ expState.addSentinel("10.20.30.50", "30001", "sentinel", nil)
- s[0].On("Master", "dbaasmaster").Return(redis.NewStringStringMapResult(redisPrimaryState, errors.New("Some error")))
- s[0].On("Slaves", "dbaasmaster").Return(redis.NewSliceResult(redisReplicasState, nil))
- s[0].On("Sentinels", "dbaasmaster").Return(redis.NewSliceResult(redisSentinelsState, nil))
+ s[0].On("Master", "dbaasmaster").Return(redis.NewStringStringMapResult(redisPrimaryState, expErr))
+ s[0].On("Slaves", "dbaasmaster").Return(redis.NewSliceResult(redisReplicasState.resp, nil))
+ s[0].On("Sentinels", "dbaasmaster").Return(redis.NewSliceResult(redisSentinelsState.resp, nil))
ret, err := db.State()
assert.NotNil(t, err)
- assert.Equal(t, expState, ret)
+ assert.Equal(t, expState.s, *ret)
r.AssertExpectations(t)
}
-func TestStateWithPrimaryAndOneReplicaRedisFailureInReplicasRedisCall(t *testing.T) {
- _, r, s, db := setupHaEnvWithSentinels(true)
- redisPrimaryState := map[string]string{
- "role-reported": "master",
- }
- redisReplicasState := make([]interface{}, 1)
- redisReplicasState[0] = []interface{}{}
- redisSentinelsState := make([]interface{}, 1)
- redisSentinelsState[0] = []interface{}{
- "ip", "10.20.30.40",
- "port", "26379",
- "flags", "sentinel",
- }
+func TestStateWithPrimaryAndTwoReplicaRedisFailureInReplicasRedisCall(t *testing.T) {
+ expErr := errors.New("Some error")
+ _, r, s, db := setupHaEnvWithSentinels(true, "3")
- expState := &sdlgoredis.DbState{
- PrimaryDbState: sdlgoredis.PrimaryDbState{
- Fields: sdlgoredis.PrimaryDbStateFields{
- Role: "master",
- },
- },
- ReplicasDbState: &sdlgoredis.ReplicasDbState{
- Err: errors.New("Some error"),
- States: []*sdlgoredis.ReplicaDbState{},
- },
- SentinelsDbState: &sdlgoredis.SentinelsDbState{
- States: []*sdlgoredis.SentinelDbState{
- &sdlgoredis.SentinelDbState{
- Fields: sdlgoredis.SentinelDbStateFields{
- Ip: "10.20.30.40",
- Port: "26379",
- Flags: "sentinel",
- },
- },
- },
- },
- }
+ redisPrimaryState := newMockRedisMasterCallResp("master", "10.20.30.30", "6379", "master")
+ redisReplicasState := newMockRedisSlavesCall()
+ redisReplicasState.add("slave", "10.20.30.40", "6379", "up", "slave")
+ redisReplicasState.add("slave", "10.20.30.50", "30000", "up", "slave")
+ redisSentinelsState := newMockRedisSentinelsCall()
+ redisSentinelsState.add("10.20.30.40", "26379", "sentinel")
+ redisSentinelsState.add("10.20.30.50", "30001", "sentinel")
+
+ expState := newExpDbState(3, nil)
+ expState.addPrimary("master", "10.20.30.30", "6379", "master", nil)
+ expState.addReplica("", "", "", "", "", expErr)
+ expState.addReplica("", "", "", "", "", expErr)
+ expState.addSentinel("10.20.30.40", "26379", "sentinel", nil)
+ expState.addSentinel("10.20.30.50", "30001", "sentinel", nil)
s[0].On("Master", "dbaasmaster").Return(redis.NewStringStringMapResult(redisPrimaryState, nil))
- s[0].On("Slaves", "dbaasmaster").Return(redis.NewSliceResult(redisReplicasState, errors.New("Some error")))
- s[0].On("Sentinels", "dbaasmaster").Return(redis.NewSliceResult(redisSentinelsState, nil))
+ s[0].On("Slaves", "dbaasmaster").Return(redis.NewSliceResult(redisReplicasState.resp, errors.New("Some error")))
+ s[0].On("Sentinels", "dbaasmaster").Return(redis.NewSliceResult(redisSentinelsState.resp, nil))
ret, err := db.State()
assert.NotNil(t, err)
- assert.Equal(t, expState, ret)
+ assert.Equal(t, expState.s, *ret)
r.AssertExpectations(t)
}
func TestStateWithPrimaryAndOneReplicaRedisFailureInSentinelsRedisCall(t *testing.T) {
- _, r, s, db := setupHaEnvWithSentinels(true)
- redisPrimaryState := map[string]string{
- "role-reported": "master",
- }
- redisReplicasState := make([]interface{}, 1)
- redisReplicasState[0] = []interface{}{
- "role-reported", "slave",
- "ip", "10.20.30.40",
- "port", "6379",
- "flags", "slave",
- "master-link-status", "up",
- }
- redisSentinelsState := make([]interface{}, 1)
- redisSentinelsState[0] = []interface{}{
- "ip", "10.20.30.40",
- "port", "26379",
- "flags", "sentinel",
- }
+ expErr := errors.New("Some error")
+ _, r, s, db := setupHaEnvWithSentinels(true, "2")
+
+ redisPrimaryState := newMockRedisMasterCallResp("master", "10.20.30.30", "6379", "master")
+ redisReplicasState := newMockRedisSlavesCall()
+ redisReplicasState.add("slave", "10.20.30.40", "6379", "up", "slave")
+ redisSentinelsState := newMockRedisSentinelsCall()
+ redisSentinelsState.add("10.20.30.40", "26379", "sentinel")
+
+ expState := newExpDbState(2, nil)
+ expState.addPrimary("master", "10.20.30.30", "6379", "master", nil)
+ expState.addReplica("slave", "10.20.30.40", "6379", "up", "slave", nil)
+ expState.addSentinel("", "", "", expErr)
+
+ s[0].On("Master", "dbaasmaster").Return(redis.NewStringStringMapResult(redisPrimaryState, nil))
+ s[0].On("Slaves", "dbaasmaster").Return(redis.NewSliceResult(redisReplicasState.resp, nil))
+ s[0].On("Sentinels", "dbaasmaster").Return(redis.NewSliceResult(redisSentinelsState.resp, expErr))
+ ret, err := db.State()
+ assert.NotNil(t, err)
+ assert.Equal(t, expState.s, *ret)
+ r.AssertExpectations(t)
+}
+
+func TestStateWithPrimaryAndTwoReplicaRedisFailureWhenIntConversionFails(t *testing.T) {
+ expErr := errors.New("Sentinel DBAAS_NODE_COUNT configuration value 'no-int' conversion to integer failed")
+ _, r, s, db := setupHaEnvWithSentinels(true, "no-int")
+
+ redisPrimaryState := newMockRedisMasterCallResp("master", "10.20.30.30", "6379", "master")
+ redisReplicasState := newMockRedisSlavesCall()
+ redisReplicasState.add("slave", "10.20.30.40", "6379", "up", "slave")
+ redisReplicasState.add("slave", "10.20.30.50", "30000", "up", "slave")
+ redisSentinelsState := newMockRedisSentinelsCall()
+ redisSentinelsState.add("10.20.30.40", "26379", "sentinel")
+ redisSentinelsState.add("10.20.30.50", "30001", "sentinel")
+
+ expState := newExpDbState(0, expErr)
+ expState.addPrimary("master", "10.20.30.30", "6379", "master", nil)
+ expState.addReplica("slave", "10.20.30.40", "6379", "up", "slave", nil)
+ expState.addReplica("slave", "10.20.30.50", "30000", "up", "slave", nil)
+ expState.addSentinel("10.20.30.40", "26379", "sentinel", nil)
+ expState.addSentinel("10.20.30.50", "30001", "sentinel", nil)
+
+ s[0].On("Master", "dbaasmaster").Return(redis.NewStringStringMapResult(redisPrimaryState, nil))
+ s[0].On("Slaves", "dbaasmaster").Return(redis.NewSliceResult(redisReplicasState.resp, nil))
+ s[0].On("Sentinels", "dbaasmaster").Return(redis.NewSliceResult(redisSentinelsState.resp, nil))
+ ret, err := db.State()
+ assert.Equal(t, expErr, err)
+ assert.Equal(t, expState.s, *ret)
+ r.AssertExpectations(t)
+}
+
+func TestStateWithSinglePrimaryRedisSuccessfully(t *testing.T) {
+ _, r, db := setupSingleEnv(true, "1")
+ redisInfo := "# Replication\r\n" +
+ "role:master\r\n" +
+ "connected_slaves:0\r\n" +
+ "min_slaves_good_slaves:0\r\n"
expState := &sdlgoredis.DbState{
+ ConfigNodeCnt: 1,
PrimaryDbState: sdlgoredis.PrimaryDbState{
Fields: sdlgoredis.PrimaryDbStateFields{
- Role: "master",
- },
- },
- ReplicasDbState: &sdlgoredis.ReplicasDbState{
- States: []*sdlgoredis.ReplicaDbState{
- &sdlgoredis.ReplicaDbState{
- Fields: sdlgoredis.ReplicaDbStateFields{
- Role: "slave",
- Ip: "10.20.30.40",
- Port: "6379",
- PrimaryLinkStatus: "up",
- Flags: "slave",
- },
- },
+ Role: "master",
+ Flags: "master",
},
},
- SentinelsDbState: &sdlgoredis.SentinelsDbState{
- Err: errors.New("Some error"),
- States: []*sdlgoredis.SentinelDbState{},
- },
}
- s[0].On("Master", "dbaasmaster").Return(redis.NewStringStringMapResult(redisPrimaryState, nil))
- s[0].On("Slaves", "dbaasmaster").Return(redis.NewSliceResult(redisReplicasState, nil))
- s[0].On("Sentinels", "dbaasmaster").Return(redis.NewSliceResult(redisSentinelsState, errors.New("Some error")))
+ r.On("Info", []string{"all"}).Return(redis.NewStringResult(redisInfo, nil))
ret, err := db.State()
- assert.NotNil(t, err)
+ assert.Nil(t, err)
assert.Equal(t, expState, ret)
r.AssertExpectations(t)
}
-func TestStateWithSinglePrimaryRedisSuccessfully(t *testing.T) {
- _, r, db := setupSingleEnv(true)
+func TestStateWithSinglePrimaryRedisFailureWhenIntConversionFails(t *testing.T) {
+ expErr := errors.New("DBAAS_NODE_COUNT configuration value 'no-int' conversion to integer failed")
+ _, r, db := setupSingleEnv(true, "no-int")
redisInfo := "# Replication\r\n" +
"role:master\r\n" +
"connected_slaves:0\r\n" +
"min_slaves_good_slaves:0\r\n"
expState := &sdlgoredis.DbState{
+ Err: expErr,
+ ConfigNodeCnt: 0,
PrimaryDbState: sdlgoredis.PrimaryDbState{
Fields: sdlgoredis.PrimaryDbStateFields{
Role: "master",
r.On("Info", []string{"all"}).Return(redis.NewStringResult(redisInfo, nil))
ret, err := db.State()
- assert.Nil(t, err)
+ assert.Equal(t, expErr, err)
assert.Equal(t, expState, ret)
r.AssertExpectations(t)
}
func TestStateWithSinglePrimaryRedisFailureInInfoCall(t *testing.T) {
- _, r, db := setupSingleEnv(true)
+ expErr := errors.New("Some error")
+ _, r, db := setupSingleEnv(true, "1")
redisInfo := ""
- expState := &sdlgoredis.DbState{}
+ expState := &sdlgoredis.DbState{
+ PrimaryDbState: sdlgoredis.PrimaryDbState{
+ Err: expErr,
+ },
+ }
r.On("Info", []string{"all"}).Return(redis.NewStringResult(redisInfo, errors.New("Some error")))
ret, err := db.State()