Fix sdlcli healthcheck DBAAS status in SEP install
[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 setupHcMockPrimaryDb(ip, port string, nodes int) {
44         hcMocks = new(healthCheckMocks)
45         hcMocks.dbState.ConfigNodeCnt = nodes
46         hcMocks.dbState.PrimaryDbState.Fields.Role = "master"
47         hcMocks.dbState.PrimaryDbState.Fields.Ip = ip
48         hcMocks.dbState.PrimaryDbState.Fields.Port = port
49         hcMocks.dbState.PrimaryDbState.Fields.Flags = "master"
50         hcMocks.dbState.ReplicasDbState = new(sdlgoredis.ReplicasDbState)
51         hcMocks.dbState.ReplicasDbState.States = []*sdlgoredis.ReplicaDbState{}
52         hcMocks.dbState.SentinelsDbState = new(sdlgoredis.SentinelsDbState)
53         hcMocks.dbState.SentinelsDbState.States = []*sdlgoredis.SentinelDbState{}
54 }
55
56 func setupHcMockReplicaDb(nodes int) {
57         hcMocks = new(healthCheckMocks)
58         hcMocks.dbState.ConfigNodeCnt = nodes
59         hcMocks.dbState.ReplicasDbState = new(sdlgoredis.ReplicasDbState)
60         hcMocks.dbState.ReplicasDbState.States = []*sdlgoredis.ReplicaDbState{}
61         hcMocks.dbState.SentinelsDbState = new(sdlgoredis.SentinelsDbState)
62         hcMocks.dbState.SentinelsDbState.States = []*sdlgoredis.SentinelDbState{}
63 }
64
65 func setupHcMockSentinelDb(ip, port string, nodes int) {
66         hcMocks = new(healthCheckMocks)
67         hcMocks.dbState.ConfigNodeCnt = nodes
68         hcMocks.dbState.SentinelsDbState = new(sdlgoredis.SentinelsDbState)
69         hcMocks.dbState.SentinelsDbState.States = []*sdlgoredis.SentinelDbState{}
70 }
71
72 func addHcMockReplicaDbState(ip, port, primaryLinkOk string) {
73         if hcMocks.dbState.ReplicasDbState == nil {
74                 hcMocks.dbState.ReplicasDbState = new(sdlgoredis.ReplicasDbState)
75         }
76         hcMocks.dbState.ReplicasDbState.States = append(hcMocks.dbState.ReplicasDbState.States,
77                 &sdlgoredis.ReplicaDbState{
78                         Fields: sdlgoredis.ReplicaDbStateFields{
79                                 Role:              "slave",
80                                 Ip:                ip,
81                                 Port:              port,
82                                 PrimaryLinkStatus: primaryLinkOk,
83                                 Flags:             "slave",
84                         },
85                 },
86         )
87 }
88
89 func addHcMockSentinelDbState(ip, port, flags string) {
90         if hcMocks.dbState.SentinelsDbState == nil {
91                 hcMocks.dbState.SentinelsDbState = new(sdlgoredis.SentinelsDbState)
92         }
93         hcMocks.dbState.SentinelsDbState.States = append(hcMocks.dbState.SentinelsDbState.States,
94                 &sdlgoredis.SentinelDbState{
95                         Fields: sdlgoredis.SentinelDbStateFields{
96                                 Ip:    ip,
97                                 Port:  port,
98                                 Flags: flags,
99                         },
100                 },
101         )
102 }
103
104 func newMockDatabase() *cli.Database {
105         db := &cli.Database{}
106         hcMocks.dbIface = new(mocks.MockDB)
107         hcMocks.dbIface.On("State").Return(&hcMocks.dbState, hcMocks.dbErr)
108         db.Instances = append(db.Instances, hcMocks.dbIface)
109         return db
110 }
111
112 func runHcCli() (string, error) {
113         buf := new(bytes.Buffer)
114         cmd := cli.NewHealthCheckCmd(newMockDatabase)
115         cmd.SetOut(buf)
116
117         err := cmd.Execute()
118
119         return buf.String(), err
120 }
121
122 func TestCliHealthCheckCanShowHelp(t *testing.T) {
123         var expOkErr error
124         expHelp := "Usage:\n  " + "healthcheck [flags]"
125         expNokErr := errors.New("unknown flag: --some-unknown-flag")
126         expArgCntErr := errors.New("accepts 0 arg(s), received 1")
127         tests := []struct {
128                 args      string
129                 expErr    error
130                 expOutput string
131         }{
132                 {args: "-h", expErr: expOkErr, expOutput: expHelp},
133                 {args: "--help", expErr: expOkErr, expOutput: expHelp},
134                 {args: "--some-unknown-flag", expErr: expNokErr, expOutput: expHelp},
135                 {args: "some-extra-argument", expErr: expArgCntErr, expOutput: expHelp},
136         }
137
138         for _, test := range tests {
139                 buf := new(bytes.Buffer)
140                 cmd := cli.NewHealthCheckCmd(newMockDatabase)
141                 cmd.SetOut(buf)
142                 cmd.SetArgs([]string{test.args})
143
144                 err := cmd.Execute()
145
146                 stdout := buf.String()
147                 assert.Equal(t, test.expErr, err)
148                 assert.Contains(t, stdout, test.expOutput)
149         }
150 }
151
152 func TestCliHealthCheckCanShowHaDeploymentOkStatusCorrectly(t *testing.T) {
153         expOut :=
154                 "Overall status: OK\n\n" +
155                         "CLUSTER   ROLE      ADDRESS            STATUS   ERROR    \n" +
156                         "0         primary   10.20.30.40:6379   OK       <none>   \n" +
157                         "0         replica   1.2.3.4:6379       OK       <none>   \n" +
158                         "0         replica   5.6.7.8:6379       OK       <none>   \n"
159         setupHcMockPrimaryDb("10.20.30.40", "6379", 3)
160         addHcMockReplicaDbState("1.2.3.4", "6379", "ok")
161         addHcMockReplicaDbState("5.6.7.8", "6379", "ok")
162         addHcMockSentinelDbState("1.2.3.4", "26379", "sentinel")
163         addHcMockSentinelDbState("5.6.7.8", "26379", "sentinel")
164
165         stdout, err := runHcCli()
166
167         assert.Nil(t, err)
168         assert.Equal(t, expOut, stdout)
169 }
170
171 func TestCliHealthCheckCanShowHaDeploymentStatusCorrectlyWhenOneReplicaStateNotUp(t *testing.T) {
172         expOut :=
173                 "Overall status: NOK\n\n" +
174                         "CLUSTER   ROLE      ADDRESS            STATUS   ERROR                                 \n" +
175                         "0         primary   10.20.30.40:6379   OK       <none>                                \n" +
176                         "0         replica   1.2.3.4:6379       OK       <none>                                \n" +
177                         "0         replica   5.6.7.8:6379       NOK      Replica link to the primary is down   \n"
178         setupHcMockPrimaryDb("10.20.30.40", "6379", 3)
179         addHcMockReplicaDbState("1.2.3.4", "6379", "ok")
180         addHcMockReplicaDbState("5.6.7.8", "6379", "nok")
181         addHcMockSentinelDbState("1.2.3.4", "26379", "sentinel")
182         addHcMockSentinelDbState("5.6.7.8", "26379", "sentinel")
183
184         stdout, err := runHcCli()
185
186         assert.Nil(t, err)
187         assert.Equal(t, expOut, stdout)
188 }
189
190 func TestCliHealthCheckCanShowHaDeploymentStatusCorrectlyWhenOneSentinelStateNotUp(t *testing.T) {
191         expOut :=
192                 "Overall status: NOK\n\n" +
193                         "CLUSTER   ROLE       ADDRESS            STATUS   ERROR                                                    \n" +
194                         "0         primary    10.20.30.40:6379   OK       <none>                                                   \n" +
195                         "0         replica    1.2.3.4:6379       OK       <none>                                                   \n" +
196                         "0         replica    5.6.7.8:6379       OK       <none>                                                   \n" +
197                         "0         sentinel   1.2.3.4:26379      NOK      Sentinel flags are 'some-failure', expected 'sentinel'   \n"
198         setupHcMockPrimaryDb("10.20.30.40", "6379", 3)
199         addHcMockReplicaDbState("1.2.3.4", "6379", "ok")
200         addHcMockReplicaDbState("5.6.7.8", "6379", "ok")
201         addHcMockSentinelDbState("1.2.3.4", "26379", "some-failure")
202         addHcMockSentinelDbState("5.6.7.8", "26379", "sentinel")
203
204         stdout, err := runHcCli()
205
206         assert.Nil(t, err)
207         assert.Equal(t, expOut, stdout)
208 }
209
210 func TestCliHealthCheckCanShowHaDeploymentStatusCorrectlyWhenNoReplicas(t *testing.T) {
211         expOut :=
212                 "Overall status: NOK\n\n" +
213                         "CLUSTER   ROLE      ADDRESS            STATUS   ERROR                                                        \n" +
214                         "0         primary   10.20.30.40:6379   OK       <none>                                                       \n" +
215                         "0         replica   <none>             NOK      Configured DBAAS nodes 3 but only 1 primary and 0 replicas   \n"
216         setupHcMockPrimaryDb("10.20.30.40", "6379", 3)
217         addHcMockSentinelDbState("1.2.3.4", "26379", "sentinel")
218         addHcMockSentinelDbState("5.6.7.8", "26379", "sentinel")
219
220         stdout, err := runHcCli()
221
222         assert.Nil(t, err)
223         assert.Equal(t, expOut, stdout)
224 }
225
226 func TestCliHealthCheckCanShowHaDeploymentStatusCorrectlyWhenDbStateQueryFails(t *testing.T) {
227         setupHcMockPrimaryDb("10.20.30.40", "6379", 3)
228         hcMocks.dbErr = errors.New("Some error")
229
230         buf := new(bytes.Buffer)
231         cmd := cli.NewHealthCheckCmd(newMockDatabase)
232         cmd.SetErr(buf)
233
234         err := cmd.Execute()
235         stderr := buf.String()
236
237         assert.Equal(t, hcMocks.dbErr, err)
238         assert.Contains(t, stderr, "Error: Some error")
239 }
240
241 func TestCliHealthCheckCanShowHaDeploymentOkStatusCorrectlyWhenDbStateIsFromReplicaOnly(t *testing.T) {
242         expOut :=
243                 "Overall status: NOK\n\n" +
244                         "CLUSTER   ROLE      ADDRESS        STATUS   ERROR                                 \n" +
245                         "0         primary   <none>         NOK      No primary DB, current role ''        \n" +
246                         "0         replica   1.2.3.4:6379   NOK      Replica link to the primary is down   \n" +
247                         "0         replica   5.6.7.8:6379   NOK      Replica link to the primary is down   \n"
248         setupHcMockReplicaDb(3)
249         addHcMockReplicaDbState("1.2.3.4", "6379", "nok")
250         addHcMockReplicaDbState("5.6.7.8", "6379", "nok")
251
252         stdout, err := runHcCli()
253
254         assert.Nil(t, err)
255         assert.Equal(t, expOut, stdout)
256 }
257
258 func TestCliHealthCheckCanShowHaDeploymentOkStatusCorrectlyWhenDbStateIsFromSentinelOnly(t *testing.T) {
259         expOut :=
260                 "Overall status: NOK\n\n" +
261                         "CLUSTER   ROLE      ADDRESS   STATUS   ERROR                            \n" +
262                         "0         primary   <none>    NOK      No primary DB, current role ''   \n"
263         setupHcMockSentinelDb("1.2.3.4", "26379", 3)
264
265         stdout, err := runHcCli()
266
267         assert.Nil(t, err)
268         assert.Equal(t, expOut, stdout)
269 }
270
271 func TestCliHealthCheckCanShowStandaloneDeploymentOkStatusCorrectly(t *testing.T) {
272         expOut :=
273                 "Overall status: OK\n\n" +
274                         "CLUSTER   ROLE      ADDRESS            STATUS   ERROR    \n" +
275                         "0         primary   10.20.30.40:6379   OK       <none>   \n"
276         setupHcMockPrimaryDb("10.20.30.40", "6379", 1)
277
278         stdout, err := runHcCli()
279
280         assert.Nil(t, err)
281         assert.Equal(t, expOut, stdout)
282 }