From a32f10007e6783f31b6b7af8b00bcc31ffae4660 Mon Sep 17 00:00:00 2001 From: Timo Tietavainen Date: Tue, 3 Nov 2020 23:21:00 +0200 Subject: [PATCH] Improve O1 agent UT coverage Improve existing unit tests coverage for O1 Agent's NBI package and implement new unit tests for SBI and main packages. Fix also few missing nil value checks found from the source code. Signed-off-by: Timo Tietavainen Change-Id: I3bd0cc1193730960e0bbfe8a7563a167edf4df8f --- agent/build_o1agent.sh | 2 +- agent/cmd/o1agent.go | 3 +- agent/cmd/o1agent_test.go | 69 +++++++++++ agent/pkg/nbi/nbi.go | 81 ++++++++++--- agent/pkg/nbi/nbi_test.go | 174 ++++++++++++++------------- agent/pkg/sbi/sbi.go | 7 +- agent/pkg/sbi/sbi_test.go | 297 ++++++++++++++++++++++++++++++++++++++++++++++ agent/pkg/sbi/types.go | 2 +- 8 files changed, 527 insertions(+), 108 deletions(-) create mode 100644 agent/cmd/o1agent_test.go create mode 100644 agent/pkg/sbi/sbi_test.go diff --git a/agent/build_o1agent.sh b/agent/build_o1agent.sh index 5b20e41..a708261 100755 --- a/agent/build_o1agent.sh +++ b/agent/build_o1agent.sh @@ -35,4 +35,4 @@ GO111MODULE=on GO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -ldflags "-X main.Version=$tag -X main.Hash=$hash" -o o1agent ./cmd/o1agent.go # Run o1agent UT -go test -v -p 1 -cover -coverprofile cover.out ./pkg/nbi/ -c -o ./nbi_test && ./nbi_test +go test -v -p 1 -cover -coverprofile=/go/src/ws/agent/coverage.out ./... diff --git a/agent/cmd/o1agent.go b/agent/cmd/o1agent.go index 387f333..38b7341 100755 --- a/agent/cmd/o1agent.go +++ b/agent/cmd/o1agent.go @@ -33,6 +33,7 @@ import ( var Version string var Hash string +var osExit = os.Exit type O1Agent struct { rmrReady bool @@ -73,7 +74,7 @@ func (o *O1Agent) Sighandler() { <-o.sigChan o.nbiClient.Stop() - os.Exit(1) + osExit(1) } func NewO1Agent() *O1Agent { diff --git a/agent/cmd/o1agent_test.go b/agent/cmd/o1agent_test.go new file mode 100644 index 0000000..808ab46 --- /dev/null +++ b/agent/cmd/o1agent_test.go @@ -0,0 +1,69 @@ +/* +================================================================================== + Copyright (c) 2020 AT&T Intellectual Property. + Copyright (c) 2020 Nokia + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +================================================================================== +*/ + +package main + +import ( + "github.com/stretchr/testify/assert" + "os" + "syscall" + "testing" + "time" +) + +var o1Agent *O1Agent + +// Test cases +func TestMain(M *testing.M) { + o1Agent = NewO1Agent() + go func() { + o1Agent.nbiClient.Start() + o1Agent.Run() + }() + time.Sleep(time.Duration(1) * time.Second) + os.Exit(M.Run()) +} + +func TestConsume(t *testing.T) { + ret := o1Agent.Consume(nil) + assert.Nil(t, ret) +} + +func TestConfigChangeHandler(t *testing.T) { + o1Agent.ConfigChangeHandler("") +} + +func TestStatusCB(t *testing.T) { + assert.True(t, o1Agent.StatusCB()) +} + +func TestSighandler(t *testing.T) { + oldOsExit := osExit + defer func() { osExit = oldOsExit }() + + var exitCode int + osExit = func(code int) { + exitCode = code + } + + go o1Agent.Sighandler() + o1Agent.sigChan <- syscall.SIGTERM + time.Sleep(time.Duration(1) * time.Second) + assert.Equal(t, 1, exitCode) +} diff --git a/agent/pkg/nbi/nbi.go b/agent/pkg/nbi/nbi.go index 8d5bb5f..b191db5 100755 --- a/agent/pkg/nbi/nbi.go +++ b/agent/pkg/nbi/nbi.go @@ -25,10 +25,10 @@ import ( "fmt" "github.com/spf13/viper" "github.com/valyala/fastjson" + "os" "strings" "time" "unsafe" - "os" "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/xapp" "gerrit.oran-osc.org/r/ric-plt/o1mediator/pkg/sbi" @@ -48,6 +48,7 @@ import "C" var sbiClient sbi.SBIClientInterface var nbiClient *Nbi var log = xapp.Logger +var rnib iRnib = xapp.Rnib func NewNbi(s sbi.SBIClientInterface) *Nbi { sbiClient = s @@ -234,7 +235,11 @@ func (n *Nbi) ManageConfigmaps(module, configJson string, oper int) error { root := fmt.Sprintf("%s:ric", module) appName := string(value.GetStringBytes(root, "config", "name")) namespace := string(value.GetStringBytes(root, "config", "namespace")) - control := value.Get(root, "config", "control").String() + controlVal := value.Get(root, "config", "control") + if controlVal == nil { + return nil + } + control := controlVal.String() var f interface{} err = json.Unmarshal([]byte(strings.ReplaceAll(control, "\\", "")), &f) @@ -270,10 +275,10 @@ func nbiGnbStateCB(session *C.sr_session_ctx_t, module *C.char, xpath *C.char, r log.Info("nbiGnbStateCB: module='%s' xpath='%s' rpath='%s' [id=%d]", mod, C.GoString(xpath), C.GoString(rpath), reqid) if mod == "o-ran-sc-ric-xapp-desc-v1" { - xappnamespace := os.Getenv("XAPP_NAMESPACE") - if xappnamespace == "" { - xappnamespace = "ricxapp" - } + xappnamespace := os.Getenv("XAPP_NAMESPACE") + if xappnamespace == "" { + xappnamespace = "ricxapp" + } podList, _ := sbiClient.GetAllPodStatus(xappnamespace) for _, pod := range podList { @@ -286,20 +291,21 @@ func nbiGnbStateCB(session *C.sr_session_ctx_t, module *C.char, xpath *C.char, r } if mod == "o-ran-sc-ric-alarm-v1" { - alerts, _ := sbiClient.GetAlerts() - for _, alert := range alerts.Payload { - id := alert.Annotations["alarm_id"] - path := fmt.Sprintf("/o-ran-sc-ric-alarm-v1:ric/alarms/alarm[alarm-id='%s']", id) - nbiClient.CreateNewElement(session, parent, path, "alarm-id", id) - nbiClient.CreateNewElement(session, parent, path, "fault-text", alert.Alert.Labels["alertname"]) - nbiClient.CreateNewElement(session, parent, path, "severity", alert.Alert.Labels["severity"]) - nbiClient.CreateNewElement(session, parent, path, "status", alert.Alert.Labels["status"]) - nbiClient.CreateNewElement(session, parent, path, "additional-info", alert.Annotations["additional_info"]) + if alerts, _ := sbiClient.GetAlerts(); alerts != nil { + for _, alert := range alerts.Payload { + id := alert.Annotations["alarm_id"] + path := fmt.Sprintf("/o-ran-sc-ric-alarm-v1:ric/alarms/alarm[alarm-id='%s']", id) + nbiClient.CreateNewElement(session, parent, path, "alarm-id", id) + nbiClient.CreateNewElement(session, parent, path, "fault-text", alert.Alert.Labels["alertname"]) + nbiClient.CreateNewElement(session, parent, path, "severity", alert.Alert.Labels["severity"]) + nbiClient.CreateNewElement(session, parent, path, "status", alert.Alert.Labels["status"]) + nbiClient.CreateNewElement(session, parent, path, "additional-info", alert.Annotations["additional_info"]) + } } return C.SR_ERR_OK } - gnbs, err := xapp.Rnib.GetListGnbIds() + gnbs, err := rnib.GetListGnbIds() if err != nil || len(gnbs) == 0 { log.Info("Rnib.GetListGnbIds() returned elementCount=%d err:%v", len(gnbs), err) return C.SR_ERR_OK @@ -307,7 +313,7 @@ func nbiGnbStateCB(session *C.sr_session_ctx_t, module *C.char, xpath *C.char, r for _, gnb := range gnbs { ranName := gnb.GetInventoryName() - info, err := xapp.Rnib.GetNodeb(ranName) + info, err := rnib.GetNodeb(ranName) if err != nil { log.Error("GetNodeb() failed for ranName=%s: %v", ranName, err) continue @@ -387,3 +393,44 @@ func (n *Nbi) NodeType2Str(ntype int) string { } return "not-specified" } + +func (n *Nbi) testModuleChangeCB(module string) bool { + var event C.sr_event_t = C.SR_EV_CHANGE + reqID := C.int(100) + modName := C.CString(module) + defer C.free(unsafe.Pointer(modName)) + + if ret := nbiModuleChangeCB(n.session, modName, nil, event, reqID); ret != C.SR_ERR_OK { + return false + } + return true +} + +func (n *Nbi) testModuleChangeCBDone(module string) bool { + var event C.sr_event_t = C.SR_EV_DONE + reqID := C.int(100) + modName := C.CString(module) + defer C.free(unsafe.Pointer(modName)) + + if ret := nbiModuleChangeCB(n.session, modName, nil, event, reqID); ret != C.SR_ERR_OK { + return false + } + return true +} + +func (n *Nbi) testGnbStateCB(module string) bool { + modName := C.CString(module) + defer C.free(unsafe.Pointer(modName)) + reqID := C.uint32_t(100) + parent := make([]*C.char, 1) + + if ret := nbiGnbStateCB(n.session, modName, nil, nil, reqID, &parent[0]); ret != C.SR_ERR_OK { + return false + } + return true +} + +type iRnib interface { + GetListGnbIds() ([]*xapp.RNIBNbIdentity, xapp.RNIBIRNibError) + GetNodeb(invName string) (*xapp.RNIBNodebInfo, xapp.RNIBIRNibError) +} diff --git a/agent/pkg/nbi/nbi_test.go b/agent/pkg/nbi/nbi_test.go index 953daa6..92835ba 100755 --- a/agent/pkg/nbi/nbi_test.go +++ b/agent/pkg/nbi/nbi_test.go @@ -21,6 +21,7 @@ package nbi import ( "encoding/json" + "fmt" "github.com/stretchr/testify/assert" "net" "net/http" @@ -28,12 +29,12 @@ import ( "os" "testing" "time" - "github.com/go-openapi/strfmt" - "fmt" - "github.com/prometheus/alertmanager/api/v2/models" + "errors" + "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/xapp" apimodel "gerrit.oran-osc.org/r/ric-plt/o1mediator/pkg/appmgrmodel" "gerrit.oran-osc.org/r/ric-plt/o1mediator/pkg/sbi" + "github.com/stretchr/testify/mock" ) var XappConfig = `{ @@ -69,17 +70,13 @@ var XappDescriptor = `{ } }` -var kpodOutput = ` -NAME READY STATUS RESTARTS AGE -ricxapp-ueec-7bfdd587db-2jl9j 1/1 Running 53 29d -ricxapp-anr-6748846478-8hmtz 1-1 Running 1 29d -ricxapp-dualco-7f76f65c99-5p6c6 0/1 Running 1 29d -` - var n *Nbi +var rnibM *rnibMock // Test cases func TestMain(M *testing.M) { + rnibM = new(rnibMock) + rnib = rnibM n = NewNbi(sbi.NewSBIClient("localhost:8080", "localhost:9093", 5)) go n.Start() time.Sleep(time.Duration(1) * time.Second) @@ -99,6 +96,69 @@ func TestModifyConfigmap(t *testing.T) { assert.Equal(t, true, err == nil) } +func TestXappDescModuleChangeCB(t *testing.T) { + ok := n.testModuleChangeCB("o-ran-sc-ric-xapp-desc-v1") + assert.True(t, ok) +} + +func TestUeecConfigModuleChangeCB(t *testing.T) { + ok := n.testModuleChangeCB("o-ran-sc-ric-ueec-config-v1") + assert.True(t, ok) +} + +func TestUeecConfigDoneModuleChangeCB(t *testing.T) { + ok := n.testModuleChangeCBDone("o-ran-sc-ric-ueec-config-v1") + assert.True(t, ok) +} + +func TestXappDescGnbStateCB(t *testing.T) { + ok := n.testGnbStateCB("o-ran-sc-ric-xapp-desc-v1") + assert.True(t, ok) +} + +func TestAlarmGnbStateCB(t *testing.T) { + ok := n.testGnbStateCB("o-ran-sc-ric-alarm-v1") + assert.True(t, ok) +} + +func TestGnbStateCB(t *testing.T) { + var rnibOk xapp.RNIBIRNibError + var gNbIDs []*xapp.RNIBNbIdentity + gNbID := xapp.RNIBNbIdentity{ + InventoryName: "test-gnb", + } + gNbIDs = append(gNbIDs, &gNbID) + nodeInfo := xapp.RNIBNodebInfo{} + + rnibM.On("GetListGnbIds").Return(gNbIDs, rnibOk).Once() + rnibM.On("GetNodeb", mock.Anything).Return(&nodeInfo, rnibOk).Once() + ok := n.testGnbStateCB("") + assert.True(t, ok) +} + +func TestGnbStateCBWhenRnibGetListGnbIdsFails(t *testing.T) { + var rnibErr xapp.RNIBIRNibError = errors.New("Some RNIB Error") + + rnibM.On("GetListGnbIds").Return(nil, rnibErr).Once() + ok := n.testGnbStateCB("") + assert.True(t, ok) +} + +func TestGnbStateCBWhenRnibGetNodebFails(t *testing.T) { + var rnibOk xapp.RNIBIRNibError + var rnibErr xapp.RNIBIRNibError = errors.New("Some RNIB Error") + var gNbIDs []*xapp.RNIBNbIdentity + gNbID := xapp.RNIBNbIdentity{ + InventoryName: "test-gnb", + } + gNbIDs = append(gNbIDs, &gNbID) + + rnibM.On("GetListGnbIds").Return(gNbIDs, rnibOk).Once() + rnibM.On("GetNodeb", mock.Anything).Return(nil, rnibErr).Once() + ok := n.testGnbStateCB("") + assert.True(t, ok) +} + func TestDeployXApp(t *testing.T) { ts := CreateHTTPServer(t, "POST", "/ric/v1/xapps", 8080, http.StatusCreated, apimodel.Xapp{}) defer ts.Close() @@ -131,80 +191,6 @@ func TestGetDeployedXapps(t *testing.T) { assert.Equal(t, true, err == nil) } -func TestGetAlerts(t *testing.T) { - tim := strfmt.DateTime(time.Now()) - fingerprint := "34c8f717936f063f" - - alerts := []models.GettableAlert{ - models.GettableAlert{ - Alert: models.Alert{ - Labels: models.LabelSet{ - "status": "active", - "alertname": "E2 CONNECTIVITY LOST TO G-NODEB", - "severity": "MAJOR", - "service": "RIC:UEEC", - "system_name": "RIC", - }, - }, - Annotations: models.LabelSet{ - "alarm_id": "8006", - "additional_info": "ethernet", - "description": "eth12", - "instructions": "Not defined", - "summary": "Communication error", - }, - EndsAt: &tim, - StartsAt: &tim, - UpdatedAt: &tim, - Fingerprint: &fingerprint, - }, - } - - url := "/api/v2/alerts?active=true&inhibited=true&silenced=true&unprocessed=true" - ts := CreateHTTPServer(t, "GET", url, 9093, http.StatusOK, alerts) - defer ts.Close() - - resp, err := sbiClient.GetAlerts() - - assert.Equal(t, true, err == nil) - assert.Equal(t, true, resp != nil) - - for _, alert := range resp.Payload { - assert.Equal(t, alert.Annotations, alerts[0].Annotations) - assert.Equal(t, alert.Alert, alerts[0].Alert) - assert.Equal(t, alert.Fingerprint, alerts[0].Fingerprint) - } -} - -func TestGetAllPodStatus(t *testing.T) { - sbi.CommandExec = func(args string) (out string, err error) { - assert.Equal(t, "/usr/local/bin/kubectl get pod -n ricxapp", args) - return kpodOutput, nil - } - - expectedPodList := []sbi.PodStatus{ - sbi.PodStatus{ - Name: "ueec", - Health: "healthy", - Status: "Running", - }, - sbi.PodStatus{ - Name: "anr", - Health: "unavailable", - Status: "Running", - }, - sbi.PodStatus{ - Name: "dualco", - Health: "unhealthy", - Status: "Running", - }, - } - - podList, err := sbiClient.GetAllPodStatus("ricxapp") - assert.Equal(t, true, err == nil) - assert.Equal(t, podList, expectedPodList) -} - func TestErrorCases(t *testing.T) { // Invalid config err := n.ManageXapps("o-ran-sc-ric-xapp-desc-v1", "", 2) @@ -296,3 +282,23 @@ func ConfigMatcher(result, expected *apimodel.XAppConfig) bool { } return false } + +type rnibMock struct { + mock.Mock +} + +func (m *rnibMock) GetListGnbIds() ([]*xapp.RNIBNbIdentity, xapp.RNIBIRNibError) { + a := m.Called() + if a.Get(0) == nil { + return nil, a.Error(1) + } + return a.Get(0).([]*xapp.RNIBNbIdentity), a.Error(1) +} + +func (m *rnibMock) GetNodeb(invName string) (*xapp.RNIBNodebInfo, xapp.RNIBIRNibError) { + a := m.Called(invName) + if a.Get(0) == nil { + return nil, a.Error(1) + } + return a.Get(0).(*xapp.RNIBNodebInfo), a.Error(1) +} diff --git a/agent/pkg/sbi/sbi.go b/agent/pkg/sbi/sbi.go index 5120f5e..a201f7f 100755 --- a/agent/pkg/sbi/sbi.go +++ b/agent/pkg/sbi/sbi.go @@ -38,7 +38,6 @@ import ( apimodel "gerrit.oran-osc.org/r/ric-plt/o1mediator/pkg/appmgrmodel" "gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/xapp" - ) type PodStatus struct { @@ -179,9 +178,9 @@ var CommandExec = func(args string) (string, error) { cmd.Stdout = &stdout cmd.Stderr = &stderr - xapp.Logger.Debug("Running command: '%s'", cmd) + xapp.Logger.Debug("Running command: '%s'", strings.Join(cmd.Args, " ")) if err := cmd.Run(); err != nil { - xapp.Logger.Error("Command failed (%s): %v - %s", cmd, err.Error(), stderr.String()) + xapp.Logger.Error("Command failed (%s): %v - %s", strings.Join(cmd.Args, " "), err.Error(), stderr.String()) return "", err } xapp.Logger.Debug("Command executed successfully!") @@ -199,4 +198,4 @@ func (s *SBIClient) GetAlerts() (*alert.GetAlertsOK, error) { } return resp, nil -} \ No newline at end of file +} diff --git a/agent/pkg/sbi/sbi_test.go b/agent/pkg/sbi/sbi_test.go new file mode 100644 index 0000000..4d91022 --- /dev/null +++ b/agent/pkg/sbi/sbi_test.go @@ -0,0 +1,297 @@ +/* +================================================================================== + Copyright (c) 2020 AT&T Intellectual Property. + Copyright (c) 2020 Nokia + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +================================================================================== +*/ + +package sbi_test + +import ( + "encoding/json" + "errors" + "fmt" + "github.com/go-openapi/strfmt" + "net" + "net/http" + "net/http/httptest" + "os" + "testing" + "time" + + apimodel "gerrit.oran-osc.org/r/ric-plt/o1mediator/pkg/appmgrmodel" + "gerrit.oran-osc.org/r/ric-plt/o1mediator/pkg/sbi" + "github.com/prometheus/alertmanager/api/v2/models" + "github.com/stretchr/testify/assert" +) + +var s *sbi.SBIClient + +var xappName = "ueec" +var ns = "ricxapp" +var release = "ueec-xapp" +var helmVer = "0.0.1" +var cfgData = `{ + "active":true, + "interfaceId": { + "globalENBId":{ + "plmnId": "1234", + "eNBId":"55" + } + } +}` +var kpodOutput = ` +NAME READY STATUS RESTARTS AGE +ricxapp-ueec-7bfdd587db-2jl9j 1/1 Running 53 29d +ricxapp-anr-6748846478-8hmtz 1-1 Running 1 29d +ricxapp-dualco-7f76f65c99-5p6c6 0/1 Running 1 29d +` + +// Test cases +func TestMain(M *testing.M) { + s = sbi.NewSBIClient("localhost:8080", "localhost:9093", 5) + os.Exit(M.Run()) +} + +func TestBuildXappDescriptor(t *testing.T) { + var expDesc apimodel.XappDescriptor = apimodel.XappDescriptor{ + XappName: &xappName, + HelmVersion: helmVer, + ReleaseName: release, + Namespace: ns, + } + assert.Equal(t, expDesc, *getTestXappDescriptor()) +} + +func TestDeployXapp(t *testing.T) { + ts := createHTTPServer(t, "POST", "/ric/v1/xapps", 8080, http.StatusCreated, apimodel.Xapp{}) + defer ts.Close() + err := s.DeployXapp(getTestXappDescriptor()) + assert.Nil(t, err) +} + +func TestDeployXappReturnsErrorIfHttpErrorResponse(t *testing.T) { + ts := createHTTPServer(t, "POST", "/ric/v1/xapps", 8080, http.StatusInternalServerError, nil) + defer ts.Close() + err := s.DeployXapp(getTestXappDescriptor()) + assert.NotNil(t, err) +} + +func TestUndeployXapp(t *testing.T) { + ts := createHTTPServer(t, "DELETE", "/ric/v1/xapps/ueec-xapp", 8080, http.StatusNoContent, nil) + defer ts.Close() + err := s.UndeployXapp(getTestXappDescriptor()) + assert.Nil(t, err) +} + +func TestUndeployXappReturnsErrorIfHttpErrorResponse(t *testing.T) { + ts := createHTTPServer(t, "DELETE", "/ric/v1/xapps/ueec-xapp", 8080, http.StatusInternalServerError, nil) + defer ts.Close() + err := s.UndeployXapp(getTestXappDescriptor()) + assert.NotNil(t, err) +} + +func TestGetDeployedXapps(t *testing.T) { + ts := createHTTPServer(t, "GET", "/ric/v1/xapps", 8080, http.StatusOK, apimodel.AllDeployedXapps{}) + defer ts.Close() + err := s.GetDeployedXapps() + assert.Nil(t, err) +} + +func TestGetDeployedXappsReturnsErrorIfHttpErrorResponse(t *testing.T) { + ts := createHTTPServer(t, "GET", "/ric/v1/xapps", 8080, http.StatusInternalServerError, apimodel.AllDeployedXapps{}) + defer ts.Close() + err := s.GetDeployedXapps() + assert.NotNil(t, err) +} + +func TestBuildXappConfig(t *testing.T) { + expResp := &apimodel.XAppConfig{ + Metadata: &apimodel.ConfigMetadata{ + XappName: &xappName, + Namespace: &ns, + }, + Config: cfgData, + } + resp := s.BuildXappConfig(xappName, ns, cfgData) + assert.Equal(t, expResp, resp) +} + +func TestModifyXappConfig(t *testing.T) { + ts := createHTTPServer(t, "PUT", "/ric/v1/config", 8080, http.StatusOK, apimodel.ConfigValidationErrors{}) + defer ts.Close() + xappCfg := s.BuildXappConfig(xappName, ns, cfgData) + err := s.ModifyXappConfig(xappCfg) + assert.Nil(t, err) +} + +func TestModifyXappConfigReturnsErrorIfHttpErrorResponse(t *testing.T) { + ts := createHTTPServer(t, "PUT", "/ric/v1/config", 8080, http.StatusInternalServerError, nil) + defer ts.Close() + xappCfg := s.BuildXappConfig(xappName, ns, cfgData) + err := s.ModifyXappConfig(xappCfg) + assert.NotNil(t, err) +} + +func TestGetAllPodStatus(t *testing.T) { + oldCmdExec := sbi.CommandExec + defer func() { sbi.CommandExec = oldCmdExec }() + sbi.CommandExec = func(args string) (out string, err error) { + assert.Equal(t, "/usr/local/bin/kubectl get pod -n ricxapp", args) + return kpodOutput, nil + } + + expPodList := []sbi.PodStatus{ + sbi.PodStatus{ + Name: "ueec", + Health: "healthy", + Status: "Running", + }, + sbi.PodStatus{ + Name: "anr", + Health: "unavailable", + Status: "Running", + }, + sbi.PodStatus{ + Name: "dualco", + Health: "unhealthy", + Status: "Running", + }, + } + + podList, err := s.GetAllPodStatus("ricxapp") + assert.Nil(t, err) + assert.Equal(t, podList, expPodList) +} + +func TestGetAllPodStatusReturnsErrorIfKubectlCommandFails(t *testing.T) { + oldCmdExec := sbi.CommandExec + defer func() { sbi.CommandExec = oldCmdExec }() + sbi.CommandExec = func(args string) (out string, err error) { + assert.Equal(t, "/usr/local/bin/kubectl get pod -n ricxapp", args) + return "", errors.New("Some kubectl error") + } + + expPodList := make([]sbi.PodStatus, 0) + + podList, err := s.GetAllPodStatus("ricxapp") + assert.NotNil(t, err) + assert.Equal(t, podList, expPodList) +} + +func TestGetHealthState(t *testing.T) { + assert.Equal(t, "healthy", s.GetHealthState("1/1")) +} + +func TestGetHealthStateReturnsUnavailableIfReadyStatusUnkown(t *testing.T) { + assert.Equal(t, "unavailable", s.GetHealthState("")) +} + +func TestGetHealthStateReturnsUnhealthyIfReadyStatusNotUp(t *testing.T) { + assert.Equal(t, "unhealthy", s.GetHealthState("0/1")) +} + +func TestGetAlerts(t *testing.T) { + tim := strfmt.DateTime(time.Now()) + fingerprint := "34c8f717936f063f" + + alerts := []models.GettableAlert{ + models.GettableAlert{ + Alert: models.Alert{ + Labels: models.LabelSet{ + "status": "active", + "alertname": "E2 CONNECTIVITY LOST TO G-NODEB", + "severity": "MAJOR", + "service": "RIC:UEEC", + "system_name": "RIC", + }, + }, + Annotations: models.LabelSet{ + "alarm_id": "8006", + "additional_info": "ethernet", + "description": "eth12", + "instructions": "Not defined", + "summary": "Communication error", + }, + EndsAt: &tim, + StartsAt: &tim, + UpdatedAt: &tim, + Fingerprint: &fingerprint, + }, + } + + url := "/api/v2/alerts?active=true&inhibited=true&silenced=true&unprocessed=true" + ts := createHTTPServer(t, "GET", url, 9093, http.StatusOK, alerts) + defer ts.Close() + + resp, err := s.GetAlerts() + + assert.Nil(t, err) + assert.Equal(t, true, resp != nil) + assert.NotNil(t, resp) + + for _, alert := range resp.Payload { + assert.Equal(t, alert.Annotations, alerts[0].Annotations) + assert.Equal(t, alert.Alert, alerts[0].Alert) + assert.Equal(t, alert.Fingerprint, alerts[0].Fingerprint) + } +} + +func TestGetAlertsReturnErrorIfHttpErrorResponse(t *testing.T) { + url := "/api/v2/alerts?active=true&inhibited=true&silenced=true&unprocessed=true" + ts := createHTTPServer(t, "GET", url, 9093, http.StatusInternalServerError, nil) + defer ts.Close() + + resp, err := s.GetAlerts() + assert.NotNil(t, err) + assert.Nil(t, resp) +} + +func TestCommandExec(t *testing.T) { + resp, err := sbi.CommandExec("date") + assert.NotEqual(t, "", resp) + assert.Nil(t, err) +} + +func TestCommandExecReturnErrorIfCmdExecutionFails(t *testing.T) { + resp, err := sbi.CommandExec("some-not-existing-command") + assert.Equal(t, "", resp) + assert.NotNil(t, err) +} + +func getTestXappDescriptor() *apimodel.XappDescriptor { + return s.BuildXappDescriptor(xappName, ns, release, helmVer) +} + +func createHTTPServer(t *testing.T, method, url string, port, status int, respData interface{}) *httptest.Server { + l, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", port)) + if err != nil { + t.Error("Failed to create listener: " + err.Error()) + } + ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, r.Method, method) + assert.Equal(t, r.URL.String(), url) + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(status) + b, _ := json.Marshal(respData) + w.Write(b) + })) + ts.Listener.Close() + ts.Listener = l + + ts.Start() + + return ts +} diff --git a/agent/pkg/sbi/types.go b/agent/pkg/sbi/types.go index ae522bb..f5cd190 100755 --- a/agent/pkg/sbi/types.go +++ b/agent/pkg/sbi/types.go @@ -29,7 +29,7 @@ import ( type SBIClient struct { appmgrAddr string alertmgrAddr string - timeout time.Duration + timeout time.Duration } type SBIClientInterface interface { -- 2.16.6