Improve O1 agent UT coverage
[ric-plt/o1.git] / agent / pkg / sbi / sbi_test.go
1 /*
2 ==================================================================================
3   Copyright (c) 2020 AT&T Intellectual Property.
4   Copyright (c) 2020 Nokia
5
6    Licensed under the Apache License, Version 2.0 (the "License");
7    you may not use this file except in compliance with the License.
8    You may obtain a copy of the License at
9
10        http://www.apache.org/licenses/LICENSE-2.0
11
12    Unless required by applicable law or agreed to in writing, software
13    distributed under the License is distributed on an "AS IS" BASIS,
14    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15    See the License for the specific language governing permissions and
16    limitations under the License.
17 ==================================================================================
18 */
19
20 package sbi_test
21
22 import (
23         "encoding/json"
24         "errors"
25         "fmt"
26         "github.com/go-openapi/strfmt"
27         "net"
28         "net/http"
29         "net/http/httptest"
30         "os"
31         "testing"
32         "time"
33
34         apimodel "gerrit.oran-osc.org/r/ric-plt/o1mediator/pkg/appmgrmodel"
35         "gerrit.oran-osc.org/r/ric-plt/o1mediator/pkg/sbi"
36         "github.com/prometheus/alertmanager/api/v2/models"
37         "github.com/stretchr/testify/assert"
38 )
39
40 var s *sbi.SBIClient
41
42 var xappName = "ueec"
43 var ns = "ricxapp"
44 var release = "ueec-xapp"
45 var helmVer = "0.0.1"
46 var cfgData = `{
47         "active":true,
48         "interfaceId": {
49                 "globalENBId":{
50                         "plmnId": "1234",
51                         "eNBId":"55"
52                 }
53         }
54 }`
55 var kpodOutput = `
56 NAME                               READY   STATUS    RESTARTS   AGE
57 ricxapp-ueec-7bfdd587db-2jl9j      1/1     Running   53         29d
58 ricxapp-anr-6748846478-8hmtz       1-1     Running   1          29d
59 ricxapp-dualco-7f76f65c99-5p6c6    0/1     Running   1          29d
60 `
61
62 // Test cases
63 func TestMain(M *testing.M) {
64         s = sbi.NewSBIClient("localhost:8080", "localhost:9093", 5)
65         os.Exit(M.Run())
66 }
67
68 func TestBuildXappDescriptor(t *testing.T) {
69         var expDesc apimodel.XappDescriptor = apimodel.XappDescriptor{
70                 XappName:    &xappName,
71                 HelmVersion: helmVer,
72                 ReleaseName: release,
73                 Namespace:   ns,
74         }
75         assert.Equal(t, expDesc, *getTestXappDescriptor())
76 }
77
78 func TestDeployXapp(t *testing.T) {
79         ts := createHTTPServer(t, "POST", "/ric/v1/xapps", 8080, http.StatusCreated, apimodel.Xapp{})
80         defer ts.Close()
81         err := s.DeployXapp(getTestXappDescriptor())
82         assert.Nil(t, err)
83 }
84
85 func TestDeployXappReturnsErrorIfHttpErrorResponse(t *testing.T) {
86         ts := createHTTPServer(t, "POST", "/ric/v1/xapps", 8080, http.StatusInternalServerError, nil)
87         defer ts.Close()
88         err := s.DeployXapp(getTestXappDescriptor())
89         assert.NotNil(t, err)
90 }
91
92 func TestUndeployXapp(t *testing.T) {
93         ts := createHTTPServer(t, "DELETE", "/ric/v1/xapps/ueec-xapp", 8080, http.StatusNoContent, nil)
94         defer ts.Close()
95         err := s.UndeployXapp(getTestXappDescriptor())
96         assert.Nil(t, err)
97 }
98
99 func TestUndeployXappReturnsErrorIfHttpErrorResponse(t *testing.T) {
100         ts := createHTTPServer(t, "DELETE", "/ric/v1/xapps/ueec-xapp", 8080, http.StatusInternalServerError, nil)
101         defer ts.Close()
102         err := s.UndeployXapp(getTestXappDescriptor())
103         assert.NotNil(t, err)
104 }
105
106 func TestGetDeployedXapps(t *testing.T) {
107         ts := createHTTPServer(t, "GET", "/ric/v1/xapps", 8080, http.StatusOK, apimodel.AllDeployedXapps{})
108         defer ts.Close()
109         err := s.GetDeployedXapps()
110         assert.Nil(t, err)
111 }
112
113 func TestGetDeployedXappsReturnsErrorIfHttpErrorResponse(t *testing.T) {
114         ts := createHTTPServer(t, "GET", "/ric/v1/xapps", 8080, http.StatusInternalServerError, apimodel.AllDeployedXapps{})
115         defer ts.Close()
116         err := s.GetDeployedXapps()
117         assert.NotNil(t, err)
118 }
119
120 func TestBuildXappConfig(t *testing.T) {
121         expResp := &apimodel.XAppConfig{
122                 Metadata: &apimodel.ConfigMetadata{
123                         XappName:  &xappName,
124                         Namespace: &ns,
125                 },
126                 Config: cfgData,
127         }
128         resp := s.BuildXappConfig(xappName, ns, cfgData)
129         assert.Equal(t, expResp, resp)
130 }
131
132 func TestModifyXappConfig(t *testing.T) {
133         ts := createHTTPServer(t, "PUT", "/ric/v1/config", 8080, http.StatusOK, apimodel.ConfigValidationErrors{})
134         defer ts.Close()
135         xappCfg := s.BuildXappConfig(xappName, ns, cfgData)
136         err := s.ModifyXappConfig(xappCfg)
137         assert.Nil(t, err)
138 }
139
140 func TestModifyXappConfigReturnsErrorIfHttpErrorResponse(t *testing.T) {
141         ts := createHTTPServer(t, "PUT", "/ric/v1/config", 8080, http.StatusInternalServerError, nil)
142         defer ts.Close()
143         xappCfg := s.BuildXappConfig(xappName, ns, cfgData)
144         err := s.ModifyXappConfig(xappCfg)
145         assert.NotNil(t, err)
146 }
147
148 func TestGetAllPodStatus(t *testing.T) {
149         oldCmdExec := sbi.CommandExec
150         defer func() { sbi.CommandExec = oldCmdExec }()
151         sbi.CommandExec = func(args string) (out string, err error) {
152                 assert.Equal(t, "/usr/local/bin/kubectl get pod -n ricxapp", args)
153                 return kpodOutput, nil
154         }
155
156         expPodList := []sbi.PodStatus{
157                 sbi.PodStatus{
158                         Name:   "ueec",
159                         Health: "healthy",
160                         Status: "Running",
161                 },
162                 sbi.PodStatus{
163                         Name:   "anr",
164                         Health: "unavailable",
165                         Status: "Running",
166                 },
167                 sbi.PodStatus{
168                         Name:   "dualco",
169                         Health: "unhealthy",
170                         Status: "Running",
171                 },
172         }
173
174         podList, err := s.GetAllPodStatus("ricxapp")
175         assert.Nil(t, err)
176         assert.Equal(t, podList, expPodList)
177 }
178
179 func TestGetAllPodStatusReturnsErrorIfKubectlCommandFails(t *testing.T) {
180         oldCmdExec := sbi.CommandExec
181         defer func() { sbi.CommandExec = oldCmdExec }()
182         sbi.CommandExec = func(args string) (out string, err error) {
183                 assert.Equal(t, "/usr/local/bin/kubectl get pod -n ricxapp", args)
184                 return "", errors.New("Some kubectl error")
185         }
186
187         expPodList := make([]sbi.PodStatus, 0)
188
189         podList, err := s.GetAllPodStatus("ricxapp")
190         assert.NotNil(t, err)
191         assert.Equal(t, podList, expPodList)
192 }
193
194 func TestGetHealthState(t *testing.T) {
195         assert.Equal(t, "healthy", s.GetHealthState("1/1"))
196 }
197
198 func TestGetHealthStateReturnsUnavailableIfReadyStatusUnkown(t *testing.T) {
199         assert.Equal(t, "unavailable", s.GetHealthState(""))
200 }
201
202 func TestGetHealthStateReturnsUnhealthyIfReadyStatusNotUp(t *testing.T) {
203         assert.Equal(t, "unhealthy", s.GetHealthState("0/1"))
204 }
205
206 func TestGetAlerts(t *testing.T) {
207         tim := strfmt.DateTime(time.Now())
208         fingerprint := "34c8f717936f063f"
209
210         alerts := []models.GettableAlert{
211                 models.GettableAlert{
212                         Alert: models.Alert{
213                                 Labels: models.LabelSet{
214                                         "status":      "active",
215                                         "alertname":   "E2 CONNECTIVITY LOST TO G-NODEB",
216                                         "severity":    "MAJOR",
217                                         "service":     "RIC:UEEC",
218                                         "system_name": "RIC",
219                                 },
220                         },
221                         Annotations: models.LabelSet{
222                                 "alarm_id":        "8006",
223                                 "additional_info": "ethernet",
224                                 "description":     "eth12",
225                                 "instructions":    "Not defined",
226                                 "summary":         "Communication error",
227                         },
228                         EndsAt:      &tim,
229                         StartsAt:    &tim,
230                         UpdatedAt:   &tim,
231                         Fingerprint: &fingerprint,
232                 },
233         }
234
235         url := "/api/v2/alerts?active=true&inhibited=true&silenced=true&unprocessed=true"
236         ts := createHTTPServer(t, "GET", url, 9093, http.StatusOK, alerts)
237         defer ts.Close()
238
239         resp, err := s.GetAlerts()
240
241         assert.Nil(t, err)
242         assert.Equal(t, true, resp != nil)
243         assert.NotNil(t, resp)
244
245         for _, alert := range resp.Payload {
246                 assert.Equal(t, alert.Annotations, alerts[0].Annotations)
247                 assert.Equal(t, alert.Alert, alerts[0].Alert)
248                 assert.Equal(t, alert.Fingerprint, alerts[0].Fingerprint)
249         }
250 }
251
252 func TestGetAlertsReturnErrorIfHttpErrorResponse(t *testing.T) {
253         url := "/api/v2/alerts?active=true&inhibited=true&silenced=true&unprocessed=true"
254         ts := createHTTPServer(t, "GET", url, 9093, http.StatusInternalServerError, nil)
255         defer ts.Close()
256
257         resp, err := s.GetAlerts()
258         assert.NotNil(t, err)
259         assert.Nil(t, resp)
260 }
261
262 func TestCommandExec(t *testing.T) {
263         resp, err := sbi.CommandExec("date")
264         assert.NotEqual(t, "", resp)
265         assert.Nil(t, err)
266 }
267
268 func TestCommandExecReturnErrorIfCmdExecutionFails(t *testing.T) {
269         resp, err := sbi.CommandExec("some-not-existing-command")
270         assert.Equal(t, "", resp)
271         assert.NotNil(t, err)
272 }
273
274 func getTestXappDescriptor() *apimodel.XappDescriptor {
275         return s.BuildXappDescriptor(xappName, ns, release, helmVer)
276 }
277
278 func createHTTPServer(t *testing.T, method, url string, port, status int, respData interface{}) *httptest.Server {
279         l, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", port))
280         if err != nil {
281                 t.Error("Failed to create listener: " + err.Error())
282         }
283         ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
284                 assert.Equal(t, r.Method, method)
285                 assert.Equal(t, r.URL.String(), url)
286                 w.Header().Add("Content-Type", "application/json")
287                 w.WriteHeader(status)
288                 b, _ := json.Marshal(respData)
289                 w.Write(b)
290         }))
291         ts.Listener.Close()
292         ts.Listener = l
293
294         ts.Start()
295
296         return ts
297 }