Merge "Release image v0.5.0"
authorAbukar Mohamed <abukar.mohamed@nokia.com>
Mon, 14 Dec 2020 06:56:53 +0000 (06:56 +0000)
committerGerrit Code Review <gerrit@o-ran-sc.org>
Mon, 14 Dec 2020 06:56:53 +0000 (06:56 +0000)
Dockerfile
agent/build_o1agent.sh
agent/cmd/o1agent.go
agent/cmd/o1agent_test.go [new file with mode: 0644]
agent/go.mod
agent/pkg/nbi/nbi.go
agent/pkg/nbi/nbi_test.go
agent/pkg/sbi/sbi.go
agent/pkg/sbi/sbi_test.go [new file with mode: 0644]
agent/pkg/sbi/types.go

index 97b4933..ad608e4 100755 (executable)
@@ -107,7 +107,7 @@ RUN \
 # ======================================================================
 
 # RMR
-ARG RMRVERSION=4.0.2
+ARG RMRVERSION=4.4.6
 ARG RMRLIBURL=https://packagecloud.io/o-ran-sc/release/packages/debian/stretch/rmr_${RMRVERSION}_amd64.deb/download.deb
 ARG RMRDEVURL=https://packagecloud.io/o-ran-sc/release/packages/debian/stretch/rmr-dev_${RMRVERSION}_amd64.deb/download.deb
 
index 5b20e41..a708261 100755 (executable)
@@ -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 ./...
index 387f333..38b7341 100755 (executable)
@@ -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 (file)
index 0000000..808ab46
--- /dev/null
@@ -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)
+}
index 69848c6..5dc36f8 100644 (file)
@@ -2,7 +2,7 @@ module gerrit.oran-osc.org/r/ric-plt/o1mediator
 
 go 1.12
 
-replace gerrit.o-ran-sc.org/r/ric-plt/xapp-frame => gerrit.o-ran-sc.org/r/ric-plt/xapp-frame.git v0.4.7
+replace gerrit.o-ran-sc.org/r/ric-plt/xapp-frame => gerrit.o-ran-sc.org/r/ric-plt/xapp-frame.git v0.5.12
 
 replace gerrit.o-ran-sc.org/r/ric-plt/sdlgo => gerrit.o-ran-sc.org/r/ric-plt/sdlgo.git v0.5.0
 
index 7865f43..b191db5 100755 (executable)
@@ -25,6 +25,7 @@ import (
        "fmt"
        "github.com/spf13/viper"
        "github.com/valyala/fastjson"
+       "os"
        "strings"
        "time"
        "unsafe"
@@ -47,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
@@ -233,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)
@@ -269,7 +275,12 @@ 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" {
-               podList, _ := sbiClient.GetAllPodStatus("ricxapp")
+               xappnamespace := os.Getenv("XAPP_NAMESPACE")
+               if xappnamespace == "" {
+                       xappnamespace = "ricxapp"
+               }
+               podList, _ := sbiClient.GetAllPodStatus(xappnamespace)
+
                for _, pod := range podList {
                        path := fmt.Sprintf("/o-ran-sc-ric-xapp-desc-v1:ric/health/status[name='%s']", pod.Name)
                        nbiClient.CreateNewElement(session, parent, path, "name", path)
@@ -280,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
@@ -301,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
@@ -381,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)
+}
index 953daa6..92835ba 100755 (executable)
@@ -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)
+}
index 5120f5e..a201f7f 100755 (executable)
@@ -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 (file)
index 0000000..4d91022
--- /dev/null
@@ -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
+}
index ae522bb..f5cd190 100755 (executable)
@@ -29,7 +29,7 @@ import (
 type SBIClient struct {
        appmgrAddr   string
        alertmgrAddr string
-       timeout          time.Duration
+       timeout      time.Duration
 }
 
 type SBIClientInterface interface {