858385bbfc91b080354e429b6bf918eb12957b24
[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         expArgCntErr := errors.New("accepts 0 arg(s), received 1")
131         tests := []struct {
132                 args      string
133                 expErr    error
134                 expOutput string
135         }{
136                 {args: "-h", expErr: expOkErr, expOutput: expHelp},
137                 {args: "--help", expErr: expOkErr, expOutput: expHelp},
138                 {args: "--some-unknown-flag", expErr: expNokErr, expOutput: expHelp},
139                 {args: "some-extra-argument", expErr: expArgCntErr, expOutput: expHelp},
140         }
141
142         for _, test := range tests {
143                 buf := new(bytes.Buffer)
144                 cmd := cli.NewHealthCheckCmd(newMockDatabase)
145                 cmd.SetOut(buf)
146                 cmd.SetArgs([]string{test.args})
147
148                 err := cmd.Execute()
149
150                 stdout := buf.String()
151                 assert.Equal(t, test.expErr, err)
152                 assert.Contains(t, stdout, test.expOutput)
153         }
154 }
155
156 func TestCliHealthCheckCanShowHaDeploymentOkStatusCorrectly(t *testing.T) {
157         setupHcMockMasterDb("10.20.30.40", "6379")
158         addHcMockReplicaDbState("1.2.3.4", "6379", "ok")
159         addHcMockReplicaDbState("5.6.7.8", "6379", "ok")
160         addHcMockSentinelDbState("1.2.3.4", "26379", "sentinel")
161         addHcMockSentinelDbState("5.6.7.8", "26379", "sentinel")
162
163         stdout, err := runHcCli()
164
165         assert.Nil(t, err)
166         assert.Contains(t, stdout, "Overall status: OK")
167         assert.Contains(t, stdout, "Master (10.20.30.40:6379): OK")
168         assert.Contains(t, stdout, "Replica #1 (1.2.3.4:6379): OK")
169         assert.Contains(t, stdout, "Replica #2 (5.6.7.8:6379): OK")
170
171 }
172
173 func TestCliHealthCheckCanShowHaDeploymentStatusCorrectlyWhenOneReplicaStateNotUp(t *testing.T) {
174         setupHcMockMasterDb("10.20.30.40", "6379")
175         addHcMockReplicaDbState("1.2.3.4", "6379", "ok")
176         addHcMockReplicaDbState("5.6.7.8", "6379", "nok")
177         addHcMockSentinelDbState("1.2.3.4", "26379", "sentinel")
178         addHcMockSentinelDbState("5.6.7.8", "26379", "sentinel")
179
180         stdout, err := runHcCli()
181
182         assert.Nil(t, err)
183         assert.Contains(t, stdout, "Overall status: NOK")
184         assert.Contains(t, stdout, "Replica #2 (5.6.7.8:6379): NOK")
185         assert.Contains(t, stdout, "Replica link to the master is down")
186 }
187
188 func TestCliHealthCheckCanShowHaDeploymentStatusCorrectlyWhenOneSentinelStateNotUp(t *testing.T) {
189         setupHcMockMasterDb("10.20.30.40", "6379")
190         addHcMockReplicaDbState("1.2.3.4", "6379", "ok")
191         addHcMockReplicaDbState("5.6.7.8", "6379", "ok")
192         addHcMockSentinelDbState("1.2.3.4", "26379", "some-failure")
193         addHcMockSentinelDbState("5.6.7.8", "26379", "sentinel")
194
195         stdout, err := runHcCli()
196
197         assert.Nil(t, err)
198         assert.Contains(t, stdout, "Overall status: NOK")
199         assert.Contains(t, stdout, "Replica #1 (1.2.3.4:6379): OK")
200         assert.Contains(t, stdout, "Replica #2 (5.6.7.8:6379): OK")
201         assert.Contains(t, stdout, "Sentinel #1 (1.2.3.4:26379): NOK")
202         assert.Contains(t, stdout, "Sentinel flags are 'some-failure', expected 'sentinel'")
203 }
204
205 func TestCliHealthCheckCanShowHaDeploymentStatusCorrectlyWhenDbStateQueryFails(t *testing.T) {
206         setupHcMockMasterDb("10.20.30.40", "6379")
207         hcMocks.dbErr = errors.New("Some error")
208
209         buf := new(bytes.Buffer)
210         cmd := cli.NewHealthCheckCmd(newMockDatabase)
211         cmd.SetErr(buf)
212
213         err := cmd.Execute()
214         stderr := buf.String()
215
216         assert.Equal(t, hcMocks.dbErr, err)
217         assert.Contains(t, stderr, "Error: "+hcMocks.dbErr.Error())
218 }
219
220 func TestCliHealthCheckCanShowHaDeploymentOkStatusCorrectlyWhenDbStateIsFromReplicaOnly(t *testing.T) {
221         setupHcMockReplicaDb("1.2.3.4", "6379")
222
223         stdout, err := runHcCli()
224
225         assert.Nil(t, err)
226         assert.Contains(t, stdout, "Overall status: NOK")
227         assert.Contains(t, stdout, "Master (): NOK")
228 }
229
230 func TestCliHealthCheckCanShowHaDeploymentOkStatusCorrectlyWhenDbStateIsFromSentinelOnly(t *testing.T) {
231         setupHcMockSentinelDb("1.2.3.4", "26379")
232
233         stdout, err := runHcCli()
234
235         assert.Nil(t, err)
236         assert.Contains(t, stdout, "Overall status: NOK")
237         assert.Contains(t, stdout, "Master (): NOK")
238 }
239
240 func TestCliHealthCheckCanShowStandaloneDeploymentOkStatusCorrectly(t *testing.T) {
241         setupHcMockMasterDb("10.20.30.40", "6379")
242
243         stdout, err := runHcCli()
244
245         assert.Nil(t, err)
246         assert.Contains(t, stdout, "Overall status: OK")
247         assert.Contains(t, stdout, "Master (10.20.30.40:6379): OK")
248 }