2cc06190336e3a3bc31a097ee835318defd571a3
[ric-plt/sdlgo.git] / internal / cli / healthcheck_test.go
1 /*
2    Copyright (c) 2021 AT&T Intellectual Property.
3    Copyright (c) 2018-2021 Nokia.
4
5    Licensed under the Apache License, Version 2.0 (the "License");
6    you may not use this file except in compliance with the License.
7    You may obtain a copy of the License at
8
9        http://www.apache.org/licenses/LICENSE-2.0
10
11    Unless required by applicable law or agreed to in writing, software
12    distributed under the License is distributed on an "AS IS" BASIS,
13    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14    See the License for the specific language governing permissions and
15    limitations under the License.
16 */
17
18 /*
19  * This source code is part of the near-RT RIC (RAN Intelligent Controller)
20  * platform project (RICP).
21  */
22
23 package cli_test
24
25 import (
26         "bytes"
27         "errors"
28         "gerrit.o-ran-sc.org/r/ric-plt/sdlgo/internal/cli"
29         "gerrit.o-ran-sc.org/r/ric-plt/sdlgo/internal/mocks"
30         "gerrit.o-ran-sc.org/r/ric-plt/sdlgo/internal/sdlgoredis"
31         "github.com/stretchr/testify/assert"
32         "testing"
33 )
34
35 var hcMocks *healthCheckMocks
36
37 type healthCheckMocks struct {
38         dbIface *mocks.MockDB
39         dbErr   error
40         dbState sdlgoredis.DbState
41 }
42
43 func setupHcMockMasterDb(ip, port string) {
44         hcMocks = new(healthCheckMocks)
45         hcMocks.dbState.MasterDbState.Fields.Role = "master"
46         hcMocks.dbState.MasterDbState.Fields.Ip = ip
47         hcMocks.dbState.MasterDbState.Fields.Port = port
48         hcMocks.dbState.MasterDbState.Fields.Flags = "master"
49 }
50
51 func setupHcMockReplicaDb(ip, port string) {
52         hcMocks = new(healthCheckMocks)
53         hcMocks.dbState.ReplicasDbState = new(sdlgoredis.ReplicasDbState)
54         hcMocks.dbState.ReplicasDbState.States = []*sdlgoredis.ReplicaDbState{
55                 &sdlgoredis.ReplicaDbState{
56                         Fields: sdlgoredis.ReplicaDbStateFields{
57                                 Role: "slave",
58                         },
59                 },
60         }
61 }
62
63 func setupHcMockSentinelDb(ip, port string) {
64         hcMocks = new(healthCheckMocks)
65         hcMocks.dbState.SentinelsDbState = new(sdlgoredis.SentinelsDbState)
66         hcMocks.dbState.SentinelsDbState.States = []*sdlgoredis.SentinelDbState{
67                 &sdlgoredis.SentinelDbState{
68                         Fields: sdlgoredis.SentinelDbStateFields{
69                                 Ip:   ip,
70                                 Port: port,
71                         },
72                 },
73         }
74 }
75
76 func addHcMockReplicaDbState(ip, port, masterLinkOk string) {
77         if hcMocks.dbState.ReplicasDbState == nil {
78                 hcMocks.dbState.ReplicasDbState = new(sdlgoredis.ReplicasDbState)
79         }
80         hcMocks.dbState.ReplicasDbState.States = append(hcMocks.dbState.ReplicasDbState.States,
81                 &sdlgoredis.ReplicaDbState{
82                         Fields: sdlgoredis.ReplicaDbStateFields{
83                                 Role:             "slave",
84                                 Ip:               ip,
85                                 Port:             port,
86                                 MasterLinkStatus: masterLinkOk,
87                                 Flags:            "slave",
88                         },
89                 },
90         )
91 }
92
93 func addHcMockSentinelDbState(ip, port, flags string) {
94         if hcMocks.dbState.SentinelsDbState == nil {
95                 hcMocks.dbState.SentinelsDbState = new(sdlgoredis.SentinelsDbState)
96         }
97         hcMocks.dbState.SentinelsDbState.States = append(hcMocks.dbState.SentinelsDbState.States,
98                 &sdlgoredis.SentinelDbState{
99                         Fields: sdlgoredis.SentinelDbStateFields{
100                                 Ip:    ip,
101                                 Port:  port,
102                                 Flags: flags,
103                         },
104                 },
105         )
106 }
107
108 func newMockDatabase() *cli.Database {
109         db := &cli.Database{}
110         hcMocks.dbIface = new(mocks.MockDB)
111         hcMocks.dbIface.On("State").Return(&hcMocks.dbState, hcMocks.dbErr)
112         db.Instances = append(db.Instances, hcMocks.dbIface)
113         return db
114 }
115
116 func runHcCli() (string, error) {
117         buf := new(bytes.Buffer)
118         cmd := cli.NewHealthCheckCmd(newMockDatabase)
119         cmd.SetOut(buf)
120
121         err := cmd.Execute()
122
123         return buf.String(), err
124 }
125
126 func TestCliHealthCheckCanShowHelp(t *testing.T) {
127         var expOkErr error
128         expHelp := "Usage:\n  " + "healthcheck [flags]"
129         expNokErr := errors.New("unknown flag: --some-unknown-flag")
130         tests := []struct {
131                 args      string
132                 expErr    error
133                 expOutput string
134         }{
135                 {args: "-h", expErr: expOkErr, expOutput: expHelp},
136                 {args: "--help", expErr: expOkErr, expOutput: expHelp},
137                 {args: "--some-unknown-flag", expErr: expNokErr, expOutput: expHelp},
138         }
139
140         for _, test := range tests {
141                 buf := new(bytes.Buffer)
142                 cmd := cli.NewHealthCheckCmd(newMockDatabase)
143                 cmd.SetOut(buf)
144                 cmd.SetArgs([]string{test.args})
145
146                 err := cmd.Execute()
147
148                 stdout := buf.String()
149                 assert.Equal(t, test.expErr, err)
150                 assert.Contains(t, stdout, test.expOutput)
151         }
152 }
153
154 func TestCliHealthCheckCanShowHaDeploymentOkStatusCorrectly(t *testing.T) {
155         setupHcMockMasterDb("10.20.30.40", "6379")
156         addHcMockReplicaDbState("1.2.3.4", "6379", "ok")
157         addHcMockReplicaDbState("5.6.7.8", "6379", "ok")
158         addHcMockSentinelDbState("1.2.3.4", "26379", "sentinel")
159         addHcMockSentinelDbState("5.6.7.8", "26379", "sentinel")
160
161         stdout, err := runHcCli()
162
163         assert.Nil(t, err)
164         assert.Contains(t, stdout, "Overall status: OK")
165         assert.Contains(t, stdout, "Master (10.20.30.40:6379): OK")
166         assert.Contains(t, stdout, "Replica #1 (1.2.3.4:6379): OK")
167         assert.Contains(t, stdout, "Replica #2 (5.6.7.8:6379): OK")
168
169 }
170
171 func TestCliHealthCheckCanShowHaDeploymentStatusCorrectlyWhenOneReplicaStateNotUp(t *testing.T) {
172         setupHcMockMasterDb("10.20.30.40", "6379")
173         addHcMockReplicaDbState("1.2.3.4", "6379", "ok")
174         addHcMockReplicaDbState("5.6.7.8", "6379", "nok")
175         addHcMockSentinelDbState("1.2.3.4", "26379", "sentinel")
176         addHcMockSentinelDbState("5.6.7.8", "26379", "sentinel")
177
178         stdout, err := runHcCli()
179
180         assert.Nil(t, err)
181         assert.Contains(t, stdout, "Overall status: NOK")
182         assert.Contains(t, stdout, "Replica #2 (5.6.7.8:6379): NOK")
183         assert.Contains(t, stdout, "Replica link to the master is down")
184 }
185
186 func TestCliHealthCheckCanShowHaDeploymentStatusCorrectlyWhenOneSentinelStateNotUp(t *testing.T) {
187         setupHcMockMasterDb("10.20.30.40", "6379")
188         addHcMockReplicaDbState("1.2.3.4", "6379", "ok")
189         addHcMockReplicaDbState("5.6.7.8", "6379", "ok")
190         addHcMockSentinelDbState("1.2.3.4", "26379", "some-failure")
191         addHcMockSentinelDbState("5.6.7.8", "26379", "sentinel")
192
193         stdout, err := runHcCli()
194
195         assert.Nil(t, err)
196         assert.Contains(t, stdout, "Overall status: NOK")
197         assert.Contains(t, stdout, "Replica #1 (1.2.3.4:6379): OK")
198         assert.Contains(t, stdout, "Replica #2 (5.6.7.8:6379): OK")
199         assert.Contains(t, stdout, "Sentinel #1 (1.2.3.4:26379): NOK")
200         assert.Contains(t, stdout, "Sentinel flags are 'some-failure', expected 'sentinel'")
201 }
202
203 func TestCliHealthCheckCanShowHaDeploymentStatusCorrectlyWhenDbStateQueryFails(t *testing.T) {
204         setupHcMockMasterDb("10.20.30.40", "6379")
205         hcMocks.dbErr = errors.New("Some error")
206         expCliErr := errors.New("SDL CLI error: Some error")
207
208         buf := new(bytes.Buffer)
209         cmd := cli.NewHealthCheckCmd(newMockDatabase)
210         cmd.SetErr(buf)
211
212         err := cmd.Execute()
213         stderr := buf.String()
214
215         assert.Equal(t, expCliErr, err)
216         assert.Contains(t, stderr, "Error: "+expCliErr.Error())
217 }
218
219 func TestCliHealthCheckCanShowHaDeploymentOkStatusCorrectlyWhenDbStateIsFromReplicaOnly(t *testing.T) {
220         setupHcMockReplicaDb("1.2.3.4", "6379")
221
222         stdout, err := runHcCli()
223
224         assert.Nil(t, err)
225         assert.Contains(t, stdout, "Overall status: NOK")
226         assert.Contains(t, stdout, "Master (): NOK")
227 }
228
229 func TestCliHealthCheckCanShowHaDeploymentOkStatusCorrectlyWhenDbStateIsFromSentinelOnly(t *testing.T) {
230         setupHcMockSentinelDb("1.2.3.4", "26379")
231
232         stdout, err := runHcCli()
233
234         assert.Nil(t, err)
235         assert.Contains(t, stdout, "Overall status: NOK")
236         assert.Contains(t, stdout, "Master (): NOK")
237 }
238
239 func TestCliHealthCheckCanShowStandaloneDeploymentOkStatusCorrectly(t *testing.T) {
240         setupHcMockMasterDb("10.20.30.40", "6379")
241
242         stdout, err := runHcCli()
243
244         assert.Nil(t, err)
245         assert.Contains(t, stdout, "Overall status: OK")
246         assert.Contains(t, stdout, "Master (10.20.30.40:6379): OK")
247 }