First commit

This commit is contained in:
Leonardo Bonati
2021-12-08 20:17:46 +00:00
commit 60dffad583
2923 changed files with 463894 additions and 0 deletions

View File

@@ -0,0 +1,134 @@
//
// Copyright 2019 AT&T Intellectual Property
// Copyright 2019 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.
// This source code is part of the near-RT RIC (RAN Intelligent Controller)
// platform project (RICP).
package managers
import (
"e2mgr/clients"
"e2mgr/e2managererrors"
"e2mgr/logger"
"e2mgr/services"
"gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
)
type E2TAssociationManager struct {
logger *logger.Logger
rnibDataService services.RNibDataService
e2tInstanceManager IE2TInstancesManager
rmClient clients.IRoutingManagerClient
}
func NewE2TAssociationManager(logger *logger.Logger, rnibDataService services.RNibDataService, e2tInstanceManager IE2TInstancesManager, rmClient clients.IRoutingManagerClient) *E2TAssociationManager {
return &E2TAssociationManager{
logger: logger,
rnibDataService: rnibDataService,
e2tInstanceManager: e2tInstanceManager,
rmClient: rmClient,
}
}
func (m *E2TAssociationManager) AssociateRan(e2tAddress string, nodebInfo *entities.NodebInfo) error {
ranName := nodebInfo.RanName
m.logger.Infof("#E2TAssociationManager.AssociateRan - Associating RAN %s to E2T Instance address: %s", ranName, e2tAddress)
err := m.associateRanAndUpdateNodeb(e2tAddress, nodebInfo)
if err != nil {
m.logger.Errorf("#E2TAssociationManager.AssociateRan - RoutingManager failure: Failed to associate RAN %s to E2T %s. Error: %s", nodebInfo, e2tAddress, err)
return err
}
err = m.e2tInstanceManager.AddRansToInstance(e2tAddress, []string{ranName})
if err != nil {
m.logger.Errorf("#E2TAssociationManager.AssociateRan - RAN name: %s - Failed to add RAN to E2T instance %s. Error: %s", ranName, e2tAddress, err)
return e2managererrors.NewRnibDbError()
}
m.logger.Infof("#E2TAssociationManager.AssociateRan - successfully associated RAN %s with E2T %s", ranName, e2tAddress)
return nil
}
func (m *E2TAssociationManager) associateRanAndUpdateNodeb(e2tAddress string, nodebInfo *entities.NodebInfo) error {
rmErr := m.rmClient.AssociateRanToE2TInstance(e2tAddress, nodebInfo.RanName)
if rmErr != nil {
nodebInfo.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED
} else {
nodebInfo.ConnectionStatus = entities.ConnectionStatus_CONNECTED
nodebInfo.AssociatedE2TInstanceAddress = e2tAddress
}
rNibErr := m.rnibDataService.UpdateNodebInfo(nodebInfo)
if rNibErr != nil {
m.logger.Errorf("#E2TAssociationManager.associateRanAndUpdateNodeb - RAN name: %s - Failed to update nodeb entity in rNib. Error: %s", nodebInfo.RanName, rNibErr)
}
var err error
if rmErr != nil {
err = e2managererrors.NewRoutingManagerError()
} else if rNibErr != nil{
err = e2managererrors.NewRnibDbError()
}
return err
}
func (m *E2TAssociationManager) DissociateRan(e2tAddress string, ranName string) error {
m.logger.Infof("#E2TAssociationManager.DissociateRan - Dissociating RAN %s from E2T Instance address: %s", ranName, e2tAddress)
nodebInfo, rnibErr := m.rnibDataService.GetNodeb(ranName)
if rnibErr != nil {
m.logger.Errorf("#E2TAssociationManager.DissociateRan - RAN name: %s - Failed fetching RAN from rNib. Error: %s", ranName, rnibErr)
return rnibErr
}
nodebInfo.AssociatedE2TInstanceAddress = ""
rnibErr = m.rnibDataService.UpdateNodebInfo(nodebInfo)
if rnibErr != nil {
m.logger.Errorf("#E2TAssociationManager.DissociateRan - RAN name: %s - Failed to update RAN.AssociatedE2TInstanceAddress in rNib. Error: %s", ranName, rnibErr)
return rnibErr
}
err := m.e2tInstanceManager.RemoveRanFromInstance(ranName, e2tAddress)
if err != nil {
m.logger.Errorf("#E2TAssociationManager.DissociateRan - RAN name: %s - Failed to remove RAN from E2T instance %s. Error: %s", ranName, e2tAddress, err)
return err
}
err = m.rmClient.DissociateRanE2TInstance(e2tAddress, ranName)
if err != nil {
m.logger.Errorf("#E2TAssociationManager.DissociateRan - RoutingManager failure: Failed to dissociate RAN %s from E2T %s. Error: %s", ranName, e2tAddress, err)
} else {
m.logger.Infof("#E2TAssociationManager.DissociateRan - successfully dissociated RAN %s from E2T %s", ranName, e2tAddress)
}
return nil
}
func (m *E2TAssociationManager) RemoveE2tInstance(e2tInstance *entities.E2TInstance) error {
m.logger.Infof("#E2TAssociationManager.RemoveE2tInstance - Removing E2T %s and dessociating its associated RANs.", e2tInstance.Address)
err := m.rmClient.DeleteE2TInstance(e2tInstance.Address, e2tInstance.AssociatedRanList)
if err != nil {
m.logger.Warnf("#E2TAssociationManager.RemoveE2tInstance - RoutingManager failure: Failed to delete E2T %s. Error: %s", e2tInstance.Address, err)
// log and continue
}
err = m.e2tInstanceManager.RemoveE2TInstance(e2tInstance.Address)
if err != nil {
m.logger.Errorf("#E2TAssociationManager.RemoveE2tInstance - Failed to remove E2T %s. Error: %s", e2tInstance.Address, err)
return err
}
m.logger.Infof("#E2TAssociationManager.RemoveE2tInstance - E2T %s successfully removed.", e2tInstance.Address)
return nil
}

View File

@@ -0,0 +1,383 @@
//
// Copyright 2019 AT&T Intellectual Property
// Copyright 2019 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.
// This source code is part of the near-RT RIC (RAN Intelligent Controller)
// platform project (RICP).
package managers
import (
"bytes"
"e2mgr/clients"
"e2mgr/configuration"
"e2mgr/e2managererrors"
"e2mgr/mocks"
"e2mgr/models"
"e2mgr/services"
"encoding/json"
"gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"io/ioutil"
"net/http"
"testing"
)
const RanName = "test"
func initE2TAssociationManagerTest(t *testing.T) (*E2TAssociationManager, *mocks.RnibReaderMock, *mocks.RnibWriterMock, *mocks.HttpClientMock) {
log := initLog(t)
config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: 3}
readerMock := &mocks.RnibReaderMock{}
writerMock := &mocks.RnibWriterMock{}
rnibDataService := services.NewRnibDataService(log, config, readerMock, writerMock)
e2tInstancesManager := NewE2TInstancesManager(rnibDataService, log)
httpClientMock := &mocks.HttpClientMock{}
rmClient := clients.NewRoutingManagerClient(log, config, httpClientMock)
manager := NewE2TAssociationManager(log, rnibDataService, e2tInstancesManager, rmClient)
return manager, readerMock, writerMock, httpClientMock
}
func mockHttpClient(httpClientMock *mocks.HttpClientMock, apiSuffix string, isSuccessful bool) {
data := models.RoutingManagerE2TDataList{models.NewRoutingManagerE2TData(E2TAddress, RanName)}
marshaled, _ := json.Marshal(data)
body := bytes.NewBuffer(marshaled)
respBody := ioutil.NopCloser(bytes.NewBufferString(""))
var respStatusCode int
if isSuccessful {
respStatusCode = http.StatusCreated
} else {
respStatusCode = http.StatusBadRequest
}
httpClientMock.On("Post", apiSuffix, "application/json", body).Return(&http.Response{StatusCode: respStatusCode, Body: respBody}, nil)
}
func TestAssociateRanSuccess(t *testing.T) {
manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
mockHttpClient(httpClientMock, clients.AssociateRanToE2TInstanceApiSuffix, true)
nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: ""}
updatedNb := *nb
updatedNb.AssociatedE2TInstanceAddress = E2TAddress
updatedNb.ConnectionStatus = entities.ConnectionStatus_CONNECTED
writerMock.On("UpdateNodebInfo", &updatedNb).Return(nil)
e2tInstance := &entities.E2TInstance{Address: E2TAddress}
readerMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance, nil)
updatedE2tInstance := *e2tInstance
updatedE2tInstance.AssociatedRanList = append(updatedE2tInstance.AssociatedRanList, RanName)
writerMock.On("SaveE2TInstance", &updatedE2tInstance).Return(nil)
err := manager.AssociateRan(E2TAddress, nb)
assert.Nil(t, err)
readerMock.AssertExpectations(t)
writerMock.AssertExpectations(t)
httpClientMock.AssertExpectations(t)
}
func TestAssociateRanRoutingManagerError(t *testing.T) {
manager, _, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
mockHttpClient(httpClientMock, clients.AssociateRanToE2TInstanceApiSuffix, false)
nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: ""}
writerMock.On("UpdateNodebInfo", nb).Return(nil)
err := manager.AssociateRan(E2TAddress, nb)
assert.NotNil(t, err)
assert.IsType(t, &e2managererrors.RoutingManagerError{}, err)
writerMock.AssertExpectations(t)
httpClientMock.AssertExpectations(t)
}
func TestAssociateRanUpdateNodebError(t *testing.T) {
manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
mockHttpClient(httpClientMock, clients.AssociateRanToE2TInstanceApiSuffix, true)
nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: ""}
updatedNb := *nb
updatedNb.AssociatedE2TInstanceAddress = E2TAddress
updatedNb.ConnectionStatus = entities.ConnectionStatus_CONNECTED
writerMock.On("UpdateNodebInfo", &updatedNb).Return(e2managererrors.NewRnibDbError())
err := manager.AssociateRan(E2TAddress, nb)
assert.NotNil(t, err)
assert.IsType(t, &e2managererrors.RnibDbError{}, err)
readerMock.AssertExpectations(t)
writerMock.AssertExpectations(t)
httpClientMock.AssertExpectations(t)
}
func TestAssociateRanGetE2tInstanceError(t *testing.T) {
manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
mockHttpClient(httpClientMock, clients.AssociateRanToE2TInstanceApiSuffix, true)
nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: ""}
updatedNb := *nb
updatedNb.AssociatedE2TInstanceAddress = E2TAddress
updatedNb.ConnectionStatus = entities.ConnectionStatus_CONNECTED
writerMock.On("UpdateNodebInfo", &updatedNb).Return(nil)
var e2tInstance *entities.E2TInstance
readerMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance, errors.New("test"))
err := manager.AssociateRan(E2TAddress, nb)
assert.NotNil(t, err)
assert.IsType(t, &e2managererrors.RnibDbError{}, err)
readerMock.AssertExpectations(t)
writerMock.AssertExpectations(t)
httpClientMock.AssertExpectations(t)
}
func TestAssociateRanSaveE2tInstanceError(t *testing.T) {
manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
mockHttpClient(httpClientMock, clients.AssociateRanToE2TInstanceApiSuffix, true)
nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: ""}
updatedNb := *nb
updatedNb.AssociatedE2TInstanceAddress = E2TAddress
updatedNb.ConnectionStatus = entities.ConnectionStatus_CONNECTED
writerMock.On("UpdateNodebInfo", &updatedNb).Return(nil)
e2tInstance := &entities.E2TInstance{Address: E2TAddress}
readerMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance, nil)
updatedE2tInstance := *e2tInstance
updatedE2tInstance.AssociatedRanList = append(updatedE2tInstance.AssociatedRanList, RanName)
writerMock.On("SaveE2TInstance", &updatedE2tInstance).Return(errors.New("test"))
err := manager.AssociateRan(E2TAddress, nb)
assert.NotNil(t, err)
assert.IsType(t, &e2managererrors.RnibDbError{}, err)
readerMock.AssertExpectations(t)
writerMock.AssertExpectations(t)
httpClientMock.AssertExpectations(t)
}
func TestDissociateRanSuccess(t *testing.T) {
manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
mockHttpClient(httpClientMock, clients.DissociateRanE2TInstanceApiSuffix, true)
nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: E2TAddress}
readerMock.On("GetNodeb", RanName).Return(nb, nil)
updatedNb := *nb
updatedNb.AssociatedE2TInstanceAddress = ""
writerMock.On("UpdateNodebInfo", &updatedNb).Return(nil)
e2tInstance := &entities.E2TInstance{Address: E2TAddress}
e2tInstance.AssociatedRanList = append(e2tInstance.AssociatedRanList, RanName)
readerMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance, nil)
updatedE2tInstance := *e2tInstance
updatedE2tInstance.AssociatedRanList = []string{}
writerMock.On("SaveE2TInstance", &updatedE2tInstance).Return(nil)
err := manager.DissociateRan(E2TAddress, RanName)
assert.Nil(t, err)
readerMock.AssertExpectations(t)
writerMock.AssertExpectations(t)
httpClientMock.AssertExpectations(t)
}
func TestDissociateRanGetNodebError(t *testing.T) {
manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
var nb *entities.NodebInfo
readerMock.On("GetNodeb", RanName).Return(nb, e2managererrors.NewRnibDbError())
err := manager.DissociateRan(E2TAddress, RanName)
assert.NotNil(t, err)
assert.IsType(t, &e2managererrors.RnibDbError{}, err)
readerMock.AssertExpectations(t)
writerMock.AssertExpectations(t)
httpClientMock.AssertExpectations(t)
}
func TestDissociateRanUpdateNodebError(t *testing.T) {
manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: E2TAddress}
readerMock.On("GetNodeb", RanName).Return(nb, nil)
updatedNb := *nb
updatedNb.AssociatedE2TInstanceAddress = ""
writerMock.On("UpdateNodebInfo", &updatedNb).Return(e2managererrors.NewRnibDbError())
err := manager.DissociateRan(E2TAddress, RanName)
assert.NotNil(t, err)
assert.IsType(t, &e2managererrors.RnibDbError{}, err)
readerMock.AssertExpectations(t)
writerMock.AssertExpectations(t)
httpClientMock.AssertExpectations(t)
}
func TestDissociateRanGetE2tInstanceError(t *testing.T) {
manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: E2TAddress}
readerMock.On("GetNodeb", RanName).Return(nb, nil)
updatedNb := *nb
updatedNb.AssociatedE2TInstanceAddress = ""
writerMock.On("UpdateNodebInfo", &updatedNb).Return(nil)
var e2tInstance *entities.E2TInstance
readerMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance, errors.New("test"))
err := manager.DissociateRan(E2TAddress, RanName)
assert.NotNil(t, err)
assert.IsType(t, &e2managererrors.RnibDbError{}, err)
readerMock.AssertExpectations(t)
writerMock.AssertExpectations(t)
httpClientMock.AssertExpectations(t)
}
func TestDissociateRanSaveE2tInstanceError(t *testing.T) {
manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: E2TAddress}
readerMock.On("GetNodeb", RanName).Return(nb, nil)
updatedNb := *nb
updatedNb.AssociatedE2TInstanceAddress = ""
writerMock.On("UpdateNodebInfo", &updatedNb).Return(nil)
e2tInstance := &entities.E2TInstance{Address: E2TAddress}
e2tInstance.AssociatedRanList = append(e2tInstance.AssociatedRanList, RanName)
readerMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance, nil)
updatedE2tInstance := *e2tInstance
updatedE2tInstance.AssociatedRanList = []string{}
writerMock.On("SaveE2TInstance", &updatedE2tInstance).Return(errors.New("test"))
err := manager.DissociateRan(E2TAddress, RanName)
assert.NotNil(t, err)
assert.IsType(t, &e2managererrors.RnibDbError{}, err)
readerMock.AssertExpectations(t)
writerMock.AssertExpectations(t)
httpClientMock.AssertExpectations(t)
}
func TestDissociateRanRoutingManagerError(t *testing.T) {
manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
mockHttpClient(httpClientMock, clients.DissociateRanE2TInstanceApiSuffix, false)
nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: E2TAddress}
readerMock.On("GetNodeb", RanName).Return(nb, nil)
updatedNb := *nb
updatedNb.AssociatedE2TInstanceAddress = ""
writerMock.On("UpdateNodebInfo", &updatedNb).Return(nil)
e2tInstance := &entities.E2TInstance{Address: E2TAddress}
e2tInstance.AssociatedRanList = append(e2tInstance.AssociatedRanList, RanName)
readerMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance, nil)
updatedE2tInstance := *e2tInstance
updatedE2tInstance.AssociatedRanList = []string{}
writerMock.On("SaveE2TInstance", &updatedE2tInstance).Return(nil)
err := manager.DissociateRan(E2TAddress, RanName)
assert.Nil(t, err)
readerMock.AssertExpectations(t)
writerMock.AssertExpectations(t)
httpClientMock.AssertExpectations(t)
}
func TestRemoveE2tInstanceSuccessWithOrphans(t *testing.T) {
manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
ranNamesToBeDissociated := []string{RanName, "test1"}
data := models.NewRoutingManagerDeleteRequestModel(E2TAddress, ranNamesToBeDissociated, nil)
mockHttpClientDelete(httpClientMock, data, true)
writerMock.On("RemoveE2TInstance", E2TAddress).Return(nil)
e2tAddresses := []string{E2TAddress}
readerMock.On("GetE2TAddresses").Return(e2tAddresses, nil)
e2tAddressesNew := []string{}
writerMock.On("SaveE2TAddresses", e2tAddressesNew).Return(nil)
e2tInstance1 := &entities.E2TInstance{Address: E2TAddress, AssociatedRanList:ranNamesToBeDissociated}
err := manager.RemoveE2tInstance(e2tInstance1)
assert.Nil(t, err)
readerMock.AssertExpectations(t)
writerMock.AssertExpectations(t)
httpClientMock.AssertExpectations(t)
}
func TestRemoveE2tInstanceFailureRoutingManager(t *testing.T) {
manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
data := models.NewRoutingManagerDeleteRequestModel(E2TAddress, []string{"test1"}, nil)
mockHttpClientDelete(httpClientMock, data, false)
writerMock.On("RemoveE2TInstance", E2TAddress).Return(nil)
e2tAddresses := []string{E2TAddress}
readerMock.On("GetE2TAddresses").Return(e2tAddresses, nil)
e2tAddressesNew := []string{}
writerMock.On("SaveE2TAddresses", e2tAddressesNew).Return(nil)
e2tInstance1 := &entities.E2TInstance{Address: E2TAddress, AssociatedRanList:[]string{"test1"}}
//readerMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance1, e2managererrors.NewRnibDbError())
err := manager.RemoveE2tInstance(e2tInstance1)
assert.Nil(t, err)
readerMock.AssertExpectations(t)
writerMock.AssertExpectations(t)
httpClientMock.AssertExpectations(t)
}
func TestRemoveE2tInstanceFailureInE2TInstanceManager(t *testing.T) {
data := models.NewRoutingManagerDeleteRequestModel(E2TAddress, []string{"test1"}, nil)
manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
mockHttpClientDelete(httpClientMock, data, true)
writerMock.On("RemoveE2TInstance", E2TAddress).Return(nil)
var e2tAddresses []string
readerMock.On("GetE2TAddresses").Return(e2tAddresses, e2managererrors.NewRnibDbError())
e2tInstance1 := &entities.E2TInstance{Address: E2TAddress, AssociatedRanList:[]string{"test1"}}
err := manager.RemoveE2tInstance(e2tInstance1)
assert.NotNil(t, err)
readerMock.AssertExpectations(t)
writerMock.AssertExpectations(t)
httpClientMock.AssertExpectations(t)
}
func TestRemoveE2tInstanceFailureInE2tInstanceAddRansToInstance(t *testing.T) {
manager, readerMock, writerMock, httpClientMock := initE2TAssociationManagerTest(t)
data := models.NewRoutingManagerDeleteRequestModel(E2TAddress, nil, nil)
mockHttpClientDelete(httpClientMock, data, true)
writerMock.On("RemoveE2TInstance", E2TAddress).Return(nil)
e2tAddresses := []string{E2TAddress, E2TAddress2, E2TAddress3}
readerMock.On("GetE2TAddresses").Return(e2tAddresses, nil)
e2tAddressesNew := []string{E2TAddress2, E2TAddress3}
writerMock.On("SaveE2TAddresses", e2tAddressesNew).Return(nil)
e2tInstance1 := &entities.E2TInstance{Address: E2TAddress}
err := manager.RemoveE2tInstance(e2tInstance1)
assert.Nil(t, err)
readerMock.AssertExpectations(t)
writerMock.AssertExpectations(t)
httpClientMock.AssertExpectations(t)
}
func mockHttpClientDelete(httpClientMock *mocks.HttpClientMock, data *models.RoutingManagerDeleteRequestModel, isSuccessful bool) {
marshaled, _ := json.Marshal(data)
body := bytes.NewBuffer(marshaled)
respBody := ioutil.NopCloser(bytes.NewBufferString(""))
var respStatusCode int
if isSuccessful {
respStatusCode = http.StatusCreated
} else {
respStatusCode = http.StatusBadRequest
}
httpClientMock.On("Delete", "e2t", "application/json", body).Return(&http.Response{StatusCode: respStatusCode, Body: respBody}, nil)
}

View File

@@ -0,0 +1,449 @@
//
// Copyright 2019 AT&T Intellectual Property
// Copyright 2019 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.
//
// This source code is part of the near-RT RIC (RAN Intelligent Controller)
// platform project (RICP).
package managers
import (
"e2mgr/e2managererrors"
"e2mgr/logger"
"e2mgr/services"
"gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common"
"gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
"math"
"sync"
"time"
)
type E2TInstancesManager struct {
rnibDataService services.RNibDataService
logger *logger.Logger
mux sync.Mutex
}
type IE2TInstancesManager interface {
GetE2TAddresses() ([]string, error)
GetE2TInstance(e2tAddress string) (*entities.E2TInstance, error)
GetE2TInstances() ([]*entities.E2TInstance, error)
GetE2TInstancesNoLogs() ([]*entities.E2TInstance, error)
AddE2TInstance(e2tAddress string, podName string) error
RemoveE2TInstance(e2tAddress string) error
SelectE2TInstance() (string, error)
AddRansToInstance(e2tAddress string, ranNames []string) error
RemoveRanFromInstance(ranName string, e2tAddress string) error
ResetKeepAliveTimestamp(e2tAddress string) error
ClearRansOfAllE2TInstances() error
SetE2tInstanceState(e2tAddress string, currentState entities.E2TInstanceState, newState entities.E2TInstanceState) error
}
func NewE2TInstancesManager(rnibDataService services.RNibDataService, logger *logger.Logger) *E2TInstancesManager {
return &E2TInstancesManager{
rnibDataService: rnibDataService,
logger: logger,
}
}
func (m *E2TInstancesManager) GetE2TInstance(e2tAddress string) (*entities.E2TInstance, error) {
e2tInstance, err := m.rnibDataService.GetE2TInstance(e2tAddress)
if err != nil {
_, ok := err.(*common.ResourceNotFoundError)
if !ok {
m.logger.Errorf("#E2TInstancesManager.GetE2TInstance - E2T Instance address: %s - Failed retrieving E2TInstance. error: %s", e2tAddress, err)
} else {
m.logger.Infof("#E2TInstancesManager.GetE2TInstance - E2T Instance address: %s not found on DB", e2tAddress)
}
}
return e2tInstance, err
}
func (m *E2TInstancesManager) GetE2TInstancesNoLogs() ([]*entities.E2TInstance, error) {
e2tAddresses, err := m.rnibDataService.GetE2TAddressesNoLogs()
if err != nil {
_, ok := err.(*common.ResourceNotFoundError)
if !ok {
m.logger.Errorf("#E2TInstancesManager.GetE2TInstancesNoLogs - Failed retrieving E2T addresses. error: %s", err)
return nil, e2managererrors.NewRnibDbError()
}
return []*entities.E2TInstance{}, nil
}
if len(e2tAddresses) == 0 {
return []*entities.E2TInstance{}, nil
}
e2tInstances, err := m.rnibDataService.GetE2TInstancesNoLogs(e2tAddresses)
if err != nil {
_, ok := err.(*common.ResourceNotFoundError)
if !ok {
m.logger.Errorf("#E2TInstancesManager.GetE2TInstancesNoLogs - Failed retrieving E2T instances list. error: %s", err)
}
return e2tInstances, err
}
return e2tInstances, nil
}
func (m *E2TInstancesManager) GetE2TAddresses() ([]string, error) {
e2tAddresses, err := m.rnibDataService.GetE2TAddresses()
if err != nil {
_, ok := err.(*common.ResourceNotFoundError)
if !ok {
m.logger.Errorf("#E2TInstancesManager.GetE2TAddresses - Failed retrieving E2T addresses. error: %s", err)
return nil, e2managererrors.NewRnibDbError()
}
}
return e2tAddresses, nil
}
func (m *E2TInstancesManager) GetE2TInstances() ([]*entities.E2TInstance, error) {
e2tAddresses, err := m.GetE2TAddresses()
if err != nil {
return nil, e2managererrors.NewRnibDbError()
}
if len(e2tAddresses) == 0 {
m.logger.Infof("#E2TInstancesManager.GetE2TInstances - Empty E2T addresses list")
return []*entities.E2TInstance{}, nil
}
e2tInstances, err := m.rnibDataService.GetE2TInstances(e2tAddresses)
if err != nil {
m.logger.Errorf("#E2TInstancesManager.GetE2TInstances - Failed retrieving E2T instances list. error: %s", err)
return e2tInstances, e2managererrors.NewRnibDbError()
}
if len(e2tInstances) == 0 {
m.logger.Warnf("#E2TInstancesManager.GetE2TInstances - Empty E2T instances list")
return e2tInstances, nil
}
return e2tInstances, nil
}
func (m *E2TInstancesManager) ResetKeepAliveTimestampsForAllE2TInstances() {
e2tInstances, err := m.GetE2TInstances()
if err != nil {
m.logger.Errorf("E2TInstancesManager.ResetKeepAliveTimestampForAllE2TInstances - Couldn't reset timestamps due to a DB error")
return
}
if len(e2tInstances) == 0 {
m.logger.Infof("E2TInstancesManager.ResetKeepAliveTimestampForAllE2TInstances - No instances, ignoring reset")
return
}
for _, v := range e2tInstances {
if v.State != entities.Active {
continue
}
v.KeepAliveTimestamp = time.Now().UnixNano()
err := m.rnibDataService.SaveE2TInstance(v)
if err != nil {
m.logger.Errorf("E2TInstancesManager.ResetKeepAliveTimestampForAllE2TInstances - E2T address: %s - failed resetting e2t instance keep alive timestamp. error: %s", v.Address, err)
}
}
m.logger.Infof("E2TInstancesManager.ResetKeepAliveTimestampForAllE2TInstances - Done with reset")
}
func findActiveE2TInstanceWithMinimumAssociatedRans(e2tInstances []*entities.E2TInstance) *entities.E2TInstance {
var minInstance *entities.E2TInstance
minAssociatedRanCount := math.MaxInt32
for _, v := range e2tInstances {
if v.State == entities.Active && len(v.AssociatedRanList) < minAssociatedRanCount {
minAssociatedRanCount = len(v.AssociatedRanList)
minInstance = v
}
}
return minInstance
}
func (m *E2TInstancesManager) AddE2TInstance(e2tAddress string, podName string) error {
m.mux.Lock()
defer m.mux.Unlock()
e2tInstance := entities.NewE2TInstance(e2tAddress, podName)
err := m.rnibDataService.SaveE2TInstance(e2tInstance)
if err != nil {
m.logger.Errorf("#E2TInstancesManager.AddE2TInstance - E2T Instance address: %s - Failed saving E2T instance. error: %s", e2tInstance.Address, err)
return err
}
e2tAddresses, err := m.rnibDataService.GetE2TAddresses()
if err != nil {
_, ok := err.(*common.ResourceNotFoundError)
if !ok {
m.logger.Errorf("#E2TInstancesManager.AddE2TInstance - E2T Instance address: %s - Failed retrieving E2T addresses list. error: %s", e2tInstance.Address, err)
return err
}
}
e2tAddresses = append(e2tAddresses, e2tInstance.Address)
err = m.rnibDataService.SaveE2TAddresses(e2tAddresses)
if err != nil {
m.logger.Errorf("#E2TInstancesManager.AddE2TInstance - E2T Instance address: %s - Failed saving E2T addresses list. error: %s", e2tInstance.Address, err)
return err
}
m.logger.Infof("#E2TInstancesManager.AddE2TInstance - E2T Instance address: %s, pod name: %s - successfully added E2T instance", e2tInstance.Address, e2tInstance.PodName)
return nil
}
func (m *E2TInstancesManager) RemoveRanFromInstance(ranName string, e2tAddress string) error {
m.mux.Lock()
defer m.mux.Unlock()
e2tInstance, err := m.rnibDataService.GetE2TInstance(e2tAddress)
if err != nil {
m.logger.Errorf("#E2TInstancesManager.RemoveRanFromInstance - E2T Instance address: %s - Failed retrieving E2TInstance. error: %s", e2tAddress, err)
return e2managererrors.NewRnibDbError()
}
i := 0 // output index
for _, v := range e2tInstance.AssociatedRanList {
if v != ranName {
// copy and increment index
e2tInstance.AssociatedRanList[i] = v
i++
}
}
e2tInstance.AssociatedRanList = e2tInstance.AssociatedRanList[:i]
err = m.rnibDataService.SaveE2TInstance(e2tInstance)
if err != nil {
m.logger.Errorf("#E2TInstancesManager.RemoveRanFromInstance - E2T Instance address: %s - Failed saving E2TInstance. error: %s", e2tAddress, err)
return e2managererrors.NewRnibDbError()
}
m.logger.Infof("#E2TInstancesManager.RemoveRanFromInstance - successfully dissociated RAN %s from E2T %s", ranName, e2tInstance.Address)
return nil
}
func (m *E2TInstancesManager) RemoveE2TInstance(e2tAddress string) error {
m.mux.Lock()
defer m.mux.Unlock()
err := m.rnibDataService.RemoveE2TInstance(e2tAddress)
if err != nil {
m.logger.Errorf("#E2TInstancesManager.RemoveE2TInstance - E2T Instance address: %s - Failed removing E2TInstance. error: %s", e2tAddress, err)
return e2managererrors.NewRnibDbError()
}
e2tAddresses, err := m.rnibDataService.GetE2TAddresses()
if err != nil {
m.logger.Errorf("#E2TInstancesManager.RemoveE2TInstance - E2T Instance address: %s - Failed retrieving E2T addresses list. error: %s", e2tAddress, err)
return e2managererrors.NewRnibDbError()
}
e2tAddresses = m.removeAddressFromList(e2tAddresses, e2tAddress)
err = m.rnibDataService.SaveE2TAddresses(e2tAddresses)
if err != nil {
m.logger.Errorf("#E2TInstancesManager.RemoveE2TInstance - E2T Instance address: %s - Failed saving E2T addresses list. error: %s", e2tAddress, err)
return e2managererrors.NewRnibDbError()
}
return nil
}
func (m *E2TInstancesManager) removeAddressFromList(e2tAddresses []string, addressToRemove string) []string {
newAddressList := []string{}
for _, address := range e2tAddresses {
if address != addressToRemove {
newAddressList = append(newAddressList, address)
}
}
return newAddressList
}
func (m *E2TInstancesManager) SelectE2TInstance() (string, error) {
e2tInstances, err := m.GetE2TInstances()
if err != nil {
return "", err
}
if len(e2tInstances) == 0 {
m.logger.Errorf("#E2TInstancesManager.SelectE2TInstance - No E2T instance found")
return "", e2managererrors.NewE2TInstanceAbsenceError()
}
min := findActiveE2TInstanceWithMinimumAssociatedRans(e2tInstances)
if min == nil {
m.logger.Errorf("#E2TInstancesManager.SelectE2TInstance - No active E2T instance found")
return "", e2managererrors.NewE2TInstanceAbsenceError()
}
m.logger.Infof("#E2TInstancesManager.SelectE2TInstance - successfully selected E2T instance. address: %s", min.Address)
return min.Address, nil
}
func (m *E2TInstancesManager) AddRansToInstance(e2tAddress string, ranNames []string) error {
m.mux.Lock()
defer m.mux.Unlock()
e2tInstance, err := m.rnibDataService.GetE2TInstance(e2tAddress)
if err != nil {
m.logger.Errorf("#E2TInstancesManager.AddRansToInstance - E2T Instance address: %s - Failed retrieving E2TInstance. error: %s", e2tAddress, err)
return e2managererrors.NewRnibDbError()
}
e2tInstance.AssociatedRanList = append(e2tInstance.AssociatedRanList, ranNames...)
err = m.rnibDataService.SaveE2TInstance(e2tInstance)
if err != nil {
m.logger.Errorf("#E2TInstancesManager.AddRansToInstance - E2T Instance address: %s - Failed saving E2TInstance. error: %s", e2tAddress, err)
return e2managererrors.NewRnibDbError()
}
m.logger.Infof("#E2TInstancesManager.AddRansToInstance - RAN %s were added successfully to E2T %s", ranNames, e2tInstance.Address)
return nil
}
func (m *E2TInstancesManager) ResetKeepAliveTimestamp(e2tAddress string) error {
m.mux.Lock()
defer m.mux.Unlock()
e2tInstance, err := m.rnibDataService.GetE2TInstanceNoLogs(e2tAddress)
if err != nil {
m.logger.Errorf("#E2TInstancesManager.ResetKeepAliveTimestamp - E2T Instance address: %s - Failed retrieving E2TInstance. error: %s", e2tAddress, err)
return err
}
if e2tInstance.State == entities.ToBeDeleted {
m.logger.Warnf("#E2TInstancesManager.ResetKeepAliveTimestamp - Ignore. This Instance is about to be deleted")
return nil
}
e2tInstance.KeepAliveTimestamp = time.Now().UnixNano()
err = m.rnibDataService.SaveE2TInstanceNoLogs(e2tInstance)
if err != nil {
m.logger.Errorf("#E2TInstancesManager.ResetKeepAliveTimestamp - E2T Instance address: %s - Failed saving E2TInstance. error: %s", e2tAddress, err)
return err
}
return nil
}
func (m *E2TInstancesManager) SetE2tInstanceState(e2tAddress string, currentState entities.E2TInstanceState, newState entities.E2TInstanceState) error {
m.mux.Lock()
defer m.mux.Unlock()
e2tInstance, err := m.rnibDataService.GetE2TInstance(e2tAddress)
if err != nil {
m.logger.Errorf("#E2TInstancesManager.SetE2tInstanceState - E2T Instance address: %s - Failed retrieving E2TInstance. error: %s", e2tAddress, err)
return e2managererrors.NewRnibDbError()
}
if (currentState != e2tInstance.State) {
m.logger.Warnf("#E2TInstancesManager.SetE2tInstanceState - E2T Instance address: %s - Current state is not: %s", e2tAddress, currentState)
return e2managererrors.NewInternalError()
}
e2tInstance.State = newState
if (newState == entities.Active) {
e2tInstance.KeepAliveTimestamp = time.Now().UnixNano()
}
err = m.rnibDataService.SaveE2TInstance(e2tInstance)
if err != nil {
m.logger.Errorf("#E2TInstancesManager.SetE2tInstanceState - E2T Instance address: %s - Failed saving E2TInstance. error: %s", e2tInstance.Address, err)
return err
}
m.logger.Infof("#E2TInstancesManager.SetE2tInstanceState - E2T Instance address: %s - State change: %s --> %s", e2tAddress, currentState, newState)
return nil
}
func (m *E2TInstancesManager) ClearRansOfAllE2TInstances() error {
m.logger.Infof("#E2TInstancesManager.ClearRansOfAllE2TInstances - Going to clear associated RANs from E2T instances")
m.mux.Lock()
defer m.mux.Unlock()
e2tInstances, err := m.GetE2TInstances()
if err != nil {
return err
}
if len(e2tInstances) == 0 {
m.logger.Errorf("#E2TInstancesManager.ClearRansOfAllE2TInstances - No E2T instances to clear associated RANs from")
return nil
}
for _, v := range e2tInstances {
v.AssociatedRanList = []string{}
err := m.rnibDataService.SaveE2TInstance(v)
if err != nil {
m.logger.Errorf("#E2TInstancesManager.ClearRansOfAllE2TInstances - e2t address: %s - failed saving e2t instance. error: %s", v.Address, err)
}
}
return nil
}

View File

@@ -0,0 +1,553 @@
//
// Copyright 2019 AT&T Intellectual Property
// Copyright 2019 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.
// This source code is part of the near-RT RIC (RAN Intelligent Controller)
// platform project (RICP).
package managers
import (
"e2mgr/configuration"
"e2mgr/e2managererrors"
"e2mgr/logger"
"e2mgr/mocks"
"e2mgr/services"
"fmt"
"gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common"
"gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"testing"
)
const E2TAddress = "10.10.2.15:9800"
const E2TAddress2 = "10.10.2.16:9800"
const PodName = "som_ pod_name"
func initE2TInstancesManagerTest(t *testing.T) (*mocks.RnibReaderMock, *mocks.RnibWriterMock, *E2TInstancesManager) {
logger, err := logger.InitLogger(logger.DebugLevel)
if err != nil {
t.Errorf("#... - failed to initialize logger, error: %s", err)
}
config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: 3}
readerMock := &mocks.RnibReaderMock{}
writerMock := &mocks.RnibWriterMock{}
rnibDataService := services.NewRnibDataService(logger, config, readerMock, writerMock)
e2tInstancesManager := NewE2TInstancesManager(rnibDataService, logger)
return readerMock, writerMock, e2tInstancesManager
}
func TestAddNewE2TInstanceSaveE2TInstanceFailure(t *testing.T) {
rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t)
rnibWriterMock.On("SaveE2TInstance", mock.Anything).Return(common.NewInternalError(errors.New("Error")))
err := e2tInstancesManager.AddE2TInstance(E2TAddress, PodName)
assert.NotNil(t, err)
rnibReaderMock.AssertNotCalled(t, "GetE2TAddresses")
}
func TestAddNewE2TInstanceGetE2TAddressesInternalFailure(t *testing.T) {
rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t)
rnibWriterMock.On("SaveE2TInstance", mock.Anything).Return(nil)
e2tAddresses := []string{}
rnibReaderMock.On("GetE2TAddresses").Return(e2tAddresses, common.NewInternalError(errors.New("Error")))
err := e2tInstancesManager.AddE2TInstance(E2TAddress, PodName)
assert.NotNil(t, err)
rnibReaderMock.AssertNotCalled(t, "SaveE2TAddresses")
}
func TestAddNewE2TInstanceSaveE2TAddressesFailure(t *testing.T) {
rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t)
rnibWriterMock.On("SaveE2TInstance", mock.Anything).Return(nil)
E2TAddresses := []string{}
rnibReaderMock.On("GetE2TAddresses").Return(E2TAddresses, nil)
E2TAddresses = append(E2TAddresses, E2TAddress)
rnibWriterMock.On("SaveE2TAddresses", E2TAddresses).Return(common.NewResourceNotFoundError(""))
err := e2tInstancesManager.AddE2TInstance(E2TAddress, PodName)
assert.NotNil(t, err)
}
func TestAddNewE2TInstanceNoE2TAddressesSuccess(t *testing.T) {
rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t)
rnibWriterMock.On("SaveE2TInstance", mock.Anything).Return(nil)
e2tAddresses := []string{}
rnibReaderMock.On("GetE2TAddresses").Return(e2tAddresses, common.NewResourceNotFoundError(""))
e2tAddresses = append(e2tAddresses, E2TAddress)
rnibWriterMock.On("SaveE2TAddresses", e2tAddresses).Return(nil)
err := e2tInstancesManager.AddE2TInstance(E2TAddress, PodName)
assert.Nil(t, err)
rnibWriterMock.AssertCalled(t, "SaveE2TAddresses", e2tAddresses)
}
func TestAddNewE2TInstanceEmptyE2TAddressesSuccess(t *testing.T) {
rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t)
rnibWriterMock.On("SaveE2TInstance", mock.Anything).Return(nil)
e2tAddresses := []string{}
rnibReaderMock.On("GetE2TAddresses").Return(e2tAddresses, nil)
e2tAddresses = append(e2tAddresses, E2TAddress)
rnibWriterMock.On("SaveE2TAddresses", e2tAddresses).Return(nil)
err := e2tInstancesManager.AddE2TInstance(E2TAddress, PodName)
assert.Nil(t, err)
rnibWriterMock.AssertCalled(t, "SaveE2TAddresses", e2tAddresses)
}
func TestAddNewE2TInstanceExistingE2TAddressesSuccess(t *testing.T) {
rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t)
rnibWriterMock.On("SaveE2TInstance", mock.Anything).Return(nil)
E2TAddresses := []string{"10.0.1.15:3030"}
rnibReaderMock.On("GetE2TAddresses").Return(E2TAddresses, nil)
E2TAddresses = append(E2TAddresses, E2TAddress)
rnibWriterMock.On("SaveE2TAddresses", E2TAddresses).Return(nil)
err := e2tInstancesManager.AddE2TInstance(E2TAddress, PodName)
assert.Nil(t, err)
}
func TestGetE2TInstanceFailure(t *testing.T) {
rnibReaderMock, _, e2tInstancesManager := initE2TInstancesManagerTest(t)
var e2tInstance *entities.E2TInstance
rnibReaderMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance, common.NewInternalError(fmt.Errorf("for test")))
res, err := e2tInstancesManager.GetE2TInstance(E2TAddress)
assert.NotNil(t, err)
assert.Nil(t, res)
}
func TestGetE2TInstanceSuccess(t *testing.T) {
rnibReaderMock, _, e2tInstancesManager := initE2TInstancesManagerTest(t)
address := "10.10.2.15:9800"
e2tInstance := entities.NewE2TInstance(address, PodName)
rnibReaderMock.On("GetE2TInstance", address).Return(e2tInstance, nil)
res, err := e2tInstancesManager.GetE2TInstance(address)
assert.Nil(t, err)
assert.Equal(t, e2tInstance, res)
}
func TestAddRanToInstanceGetInstanceFailure(t *testing.T) {
rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t)
var e2tInstance1 *entities.E2TInstance
rnibReaderMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance1, common.NewInternalError(fmt.Errorf("for test")))
err := e2tInstancesManager.AddRansToInstance(E2TAddress, []string{"test1"})
assert.NotNil(t, err)
rnibWriterMock.AssertNotCalled(t, "SaveE2TInstance")
}
func TestAddRanToInstanceSaveInstanceFailure(t *testing.T) {
rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t)
e2tInstance1 := entities.NewE2TInstance(E2TAddress, PodName)
rnibReaderMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance1, nil)
rnibWriterMock.On("SaveE2TInstance", mock.Anything).Return(common.NewInternalError(fmt.Errorf("for test")))
err := e2tInstancesManager.AddRansToInstance(E2TAddress, []string{"test1"})
assert.NotNil(t, err)
rnibReaderMock.AssertExpectations(t)
rnibWriterMock.AssertExpectations(t)
}
func TestAddRanToInstanceSuccess(t *testing.T) {
rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t)
e2tInstance := entities.NewE2TInstance(E2TAddress, PodName)
rnibReaderMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance, nil)
updateE2TInstance := *e2tInstance
updateE2TInstance.AssociatedRanList = append(updateE2TInstance.AssociatedRanList, "test1")
rnibWriterMock.On("SaveE2TInstance", &updateE2TInstance).Return(nil)
err := e2tInstancesManager.AddRansToInstance(E2TAddress, []string{"test1"})
assert.Nil(t, err)
rnibReaderMock.AssertExpectations(t)
rnibWriterMock.AssertExpectations(t)
}
func TestRemoveRanFromInstanceGetInstanceFailure(t *testing.T) {
rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t)
var e2tInstance1 *entities.E2TInstance
rnibReaderMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance1, common.NewInternalError(fmt.Errorf("for test")))
err := e2tInstancesManager.RemoveRanFromInstance("test1", E2TAddress)
assert.NotNil(t, err)
rnibWriterMock.AssertNotCalled(t, "SaveE2TInstance")
}
func TestRemoveRanFromInstanceSaveInstanceFailure(t *testing.T) {
rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t)
e2tInstance1 := entities.NewE2TInstance(E2TAddress, PodName)
rnibReaderMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance1, nil)
rnibWriterMock.On("SaveE2TInstance", mock.Anything).Return(common.NewInternalError(fmt.Errorf("for test")))
err := e2tInstancesManager.RemoveRanFromInstance("test1", E2TAddress)
assert.NotNil(t, err)
rnibReaderMock.AssertExpectations(t)
rnibWriterMock.AssertExpectations(t)
}
func TestRemoveRanFromInstanceSuccess(t *testing.T) {
rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t)
e2tInstance := entities.NewE2TInstance(E2TAddress, PodName)
e2tInstance.AssociatedRanList = []string{"test0", "test1"}
updatedE2TInstance := *e2tInstance
updatedE2TInstance.AssociatedRanList = []string{"test0"}
rnibReaderMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance, nil)
rnibWriterMock.On("SaveE2TInstance", &updatedE2TInstance).Return(nil)
err := e2tInstancesManager.RemoveRanFromInstance("test1", E2TAddress)
assert.Nil(t, err)
rnibReaderMock.AssertExpectations(t)
rnibWriterMock.AssertExpectations(t)
}
func TestSelectE2TInstancesGetE2TAddressesFailure(t *testing.T) {
rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t)
rnibReaderMock.On("GetE2TAddresses").Return([]string{}, common.NewInternalError(fmt.Errorf("for test")))
address, err := e2tInstancesManager.SelectE2TInstance()
assert.NotNil(t, err)
assert.Empty(t, address)
rnibReaderMock.AssertExpectations(t)
rnibWriterMock.AssertNotCalled(t, "GetE2TInstances")
}
func TestSelectE2TInstancesEmptyE2TAddressList(t *testing.T) {
rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t)
rnibReaderMock.On("GetE2TAddresses").Return([]string{}, nil)
address, err := e2tInstancesManager.SelectE2TInstance()
assert.NotNil(t, err)
assert.Empty(t, address)
rnibReaderMock.AssertExpectations(t)
rnibWriterMock.AssertNotCalled(t, "GetE2TInstances")
}
func TestSelectE2TInstancesGetE2TInstancesFailure(t *testing.T) {
rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t)
addresses := []string{E2TAddress}
rnibReaderMock.On("GetE2TAddresses").Return(addresses, nil)
rnibReaderMock.On("GetE2TInstances", addresses).Return([]*entities.E2TInstance{}, common.NewInternalError(fmt.Errorf("for test")))
address, err := e2tInstancesManager.SelectE2TInstance()
assert.NotNil(t, err)
assert.Empty(t, address)
rnibReaderMock.AssertExpectations(t)
rnibWriterMock.AssertExpectations(t)
}
func TestSelectE2TInstancesEmptyE2TInstancesList(t *testing.T) {
rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t)
addresses := []string{E2TAddress}
rnibReaderMock.On("GetE2TAddresses").Return(addresses, nil)
rnibReaderMock.On("GetE2TInstances", addresses).Return([]*entities.E2TInstance{}, nil)
address, err := e2tInstancesManager.SelectE2TInstance()
assert.NotNil(t, err)
assert.Empty(t, address)
rnibReaderMock.AssertExpectations(t)
rnibWriterMock.AssertExpectations(t)
}
func TestSelectE2TInstancesNoActiveE2TInstance(t *testing.T) {
rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t)
addresses := []string{E2TAddress, E2TAddress2}
e2tInstance1 := entities.NewE2TInstance(E2TAddress, PodName)
e2tInstance1.State = entities.ToBeDeleted
e2tInstance1.AssociatedRanList = []string{"test1", "test2", "test3"}
e2tInstance2 := entities.NewE2TInstance(E2TAddress2, PodName)
e2tInstance2.State = entities.ToBeDeleted
e2tInstance2.AssociatedRanList = []string{"test4", "test5", "test6", "test7"}
rnibReaderMock.On("GetE2TAddresses").Return(addresses, nil)
rnibReaderMock.On("GetE2TInstances", addresses).Return([]*entities.E2TInstance{e2tInstance1, e2tInstance2}, nil)
address, err := e2tInstancesManager.SelectE2TInstance()
assert.NotNil(t, err)
assert.Equal(t, "", address)
rnibReaderMock.AssertExpectations(t)
rnibWriterMock.AssertExpectations(t)
}
func TestSelectE2TInstancesSuccess(t *testing.T) {
rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t)
addresses := []string{E2TAddress, E2TAddress2}
e2tInstance1 := entities.NewE2TInstance(E2TAddress, PodName)
e2tInstance1.AssociatedRanList = []string{"test1", "test2", "test3"}
e2tInstance2 := entities.NewE2TInstance(E2TAddress2, PodName)
e2tInstance2.AssociatedRanList = []string{"test4", "test5", "test6", "test7"}
rnibReaderMock.On("GetE2TAddresses").Return(addresses, nil)
rnibReaderMock.On("GetE2TInstances", addresses).Return([]*entities.E2TInstance{e2tInstance1, e2tInstance2}, nil)
address, err := e2tInstancesManager.SelectE2TInstance()
assert.Nil(t, err)
assert.Equal(t, E2TAddress, address)
rnibReaderMock.AssertExpectations(t)
rnibWriterMock.AssertExpectations(t)
}
func TestActivateE2TInstanceSuccess(t *testing.T) {
rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t)
e2tInstance1 := entities.NewE2TInstance(E2TAddress, PodName)
e2tInstance1.State = entities.ToBeDeleted
e2tInstance1.AssociatedRanList = []string{"test1","test2","test3"}
rnibReaderMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance1, nil)
rnibWriterMock.On("SaveE2TInstance", mock.MatchedBy(func(e2tInstance *entities.E2TInstance) bool { return e2tInstance.State == entities.Active })).Return(nil)
err := e2tInstancesManager.SetE2tInstanceState(E2TAddress, entities.ToBeDeleted, entities.Active)
assert.Nil(t, err)
assert.Equal(t, entities.Active, e2tInstance1.State)
rnibWriterMock.AssertExpectations(t)
}
func TestActivateE2TInstance_RnibError(t *testing.T) {
rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t)
var e2tInstance1 *entities.E2TInstance
rnibReaderMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance1, common.NewInternalError(errors.New("for test")))
err := e2tInstancesManager.SetE2tInstanceState(E2TAddress, entities.ToBeDeleted, entities.Active)
assert.NotNil(t, err)
rnibWriterMock.AssertExpectations(t)
}
func TestActivateE2TInstance_NoInstance(t *testing.T) {
rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t)
var e2tInstance1 *entities.E2TInstance
rnibReaderMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance1, e2managererrors.NewResourceNotFoundError())
err := e2tInstancesManager.SetE2tInstanceState(E2TAddress, entities.ToBeDeleted, entities.Active)
assert.NotNil(t, err)
rnibWriterMock.AssertNotCalled(t, "SaveE2TInstance")
}
func TestResetKeepAliveTimestampGetInternalFailure(t *testing.T) {
rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t)
address := "10.10.2.15:9800"
e2tInstance := entities.NewE2TInstance(address, PodName)
rnibReaderMock.On("GetE2TInstance", address).Return(e2tInstance, common.NewInternalError(errors.New("Error")))
rnibWriterMock.On("SaveE2TInstance", mock.Anything).Return(nil)
err := e2tInstancesManager.ResetKeepAliveTimestamp(address)
assert.NotNil(t, err)
rnibReaderMock.AssertNotCalled(t, "SaveE2TInstance")
}
func TestAResetKeepAliveTimestampSaveInternalFailure(t *testing.T) {
rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t)
address := "10.10.2.15:9800"
e2tInstance := entities.NewE2TInstance(address, PodName)
rnibReaderMock.On("GetE2TInstance", address).Return(e2tInstance, nil)
rnibWriterMock.On("SaveE2TInstance", mock.Anything).Return(common.NewInternalError(errors.New("Error")))
err := e2tInstancesManager.ResetKeepAliveTimestamp(address)
assert.NotNil(t, err)
}
func TestResetKeepAliveTimestampSuccess(t *testing.T) {
rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t)
address := "10.10.2.15:9800"
e2tInstance := entities.NewE2TInstance(address, PodName)
rnibReaderMock.On("GetE2TInstance", address).Return(e2tInstance, nil)
rnibWriterMock.On("SaveE2TInstance", mock.Anything).Return(nil)
err := e2tInstancesManager.ResetKeepAliveTimestamp(address)
assert.Nil(t, err)
rnibReaderMock.AssertCalled(t, "GetE2TInstance", address)
rnibWriterMock.AssertNumberOfCalls(t, "SaveE2TInstance", 1)
}
func TestResetKeepAliveTimestampToBeDeleted(t *testing.T) {
rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t)
address := "10.10.2.15:9800"
e2tInstance := entities.NewE2TInstance(address, PodName)
e2tInstance.State = entities.ToBeDeleted
rnibReaderMock.On("GetE2TInstance", address).Return(e2tInstance, nil)
err := e2tInstancesManager.ResetKeepAliveTimestamp(address)
assert.Nil(t, err)
rnibReaderMock.AssertCalled(t, "GetE2TInstance", address)
rnibWriterMock.AssertNotCalled(t, "SaveE2TInstance")
}
func TestResetKeepAliveTimestampsForAllE2TInstancesGetE2TInstancesFailure(t *testing.T) {
rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t)
rnibReaderMock.On("GetE2TAddresses").Return([]string{}, common.NewInternalError(errors.New("Error")))
e2tInstancesManager.ResetKeepAliveTimestampsForAllE2TInstances()
rnibWriterMock.AssertNotCalled(t, "SaveE2TInstance")
}
func TestResetKeepAliveTimestampsForAllE2TInstancesNoInstances(t *testing.T) {
rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t)
rnibReaderMock.On("GetE2TAddresses").Return([]string{}, nil)
e2tInstancesManager.ResetKeepAliveTimestampsForAllE2TInstances()
rnibWriterMock.AssertNotCalled(t, "SaveE2TInstance")
}
func TestResetKeepAliveTimestampsForAllE2TInstancesNoActiveInstances(t *testing.T) {
rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t)
e2tAddresses := []string{E2TAddress, E2TAddress2}
rnibReaderMock.On("GetE2TAddresses").Return(e2tAddresses, nil)
e2tInstance1 := entities.NewE2TInstance(E2TAddress, PodName)
e2tInstance1.State = entities.ToBeDeleted
e2tInstance2 := entities.NewE2TInstance(E2TAddress2, PodName)
e2tInstance2.State = entities.ToBeDeleted
rnibReaderMock.On("GetE2TInstances", e2tAddresses).Return([]*entities.E2TInstance{e2tInstance1, e2tInstance2}, nil)
e2tInstancesManager.ResetKeepAliveTimestampsForAllE2TInstances()
rnibWriterMock.AssertNotCalled(t, "SaveE2TInstance")
}
func TestResetKeepAliveTimestampsForAllE2TInstancesOneActiveInstance(t *testing.T) {
rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t)
e2tAddresses := []string{E2TAddress, E2TAddress2}
rnibReaderMock.On("GetE2TAddresses").Return(e2tAddresses, nil)
e2tInstance1 := entities.NewE2TInstance(E2TAddress, PodName)
e2tInstance1.State = entities.Active
e2tInstance2 := entities.NewE2TInstance(E2TAddress2, PodName)
e2tInstance2.State = entities.ToBeDeleted
rnibReaderMock.On("GetE2TInstances", e2tAddresses).Return([]*entities.E2TInstance{e2tInstance1, e2tInstance2}, nil)
rnibWriterMock.On("SaveE2TInstance", mock.Anything).Return(nil)
e2tInstancesManager.ResetKeepAliveTimestampsForAllE2TInstances()
rnibWriterMock.AssertNumberOfCalls(t, "SaveE2TInstance",1)
}
func TestResetKeepAliveTimestampsForAllE2TInstancesSaveE2TInstanceFailure(t *testing.T) {
rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t)
e2tAddresses := []string{E2TAddress, E2TAddress2}
rnibReaderMock.On("GetE2TAddresses").Return(e2tAddresses, nil)
e2tInstance1 := entities.NewE2TInstance(E2TAddress, PodName)
e2tInstance1.State = entities.Active
e2tInstance2 := entities.NewE2TInstance(E2TAddress2, PodName)
e2tInstance2.State = entities.ToBeDeleted
rnibReaderMock.On("GetE2TInstances", e2tAddresses).Return([]*entities.E2TInstance{e2tInstance1, e2tInstance2}, nil)
rnibWriterMock.On("SaveE2TInstance", mock.Anything).Return(common.NewInternalError(errors.New("Error")))
e2tInstancesManager.ResetKeepAliveTimestampsForAllE2TInstances()
rnibWriterMock.AssertNumberOfCalls(t, "SaveE2TInstance",1)
}
func TestRemoveE2TInstanceSuccess(t *testing.T) {
rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t)
rnibWriterMock.On("RemoveE2TInstance", E2TAddress).Return(nil)
e2tAddresses := []string{E2TAddress, E2TAddress2}
rnibReaderMock.On("GetE2TAddresses").Return(e2tAddresses, nil)
e2tAddressesNew := []string{E2TAddress2}
rnibWriterMock.On("SaveE2TAddresses", e2tAddressesNew).Return(nil)
err := e2tInstancesManager.RemoveE2TInstance(E2TAddress)
assert.Nil(t, err)
rnibReaderMock.AssertExpectations(t)
rnibWriterMock.AssertExpectations(t)
}
func TestRemoveE2TInstanceRnibErrorInRemoveInstance(t *testing.T) {
rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t)
rnibWriterMock.On("RemoveE2TInstance", E2TAddress).Return(e2managererrors.NewRnibDbError())
err := e2tInstancesManager.RemoveE2TInstance(E2TAddress)
assert.NotNil(t, err)
assert.IsType(t, e2managererrors.NewRnibDbError(), err)
rnibReaderMock.AssertExpectations(t)
rnibWriterMock.AssertExpectations(t)
}
func TestRemoveE2TInstanceRnibErrorInGetAddresses(t *testing.T) {
rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t)
rnibWriterMock.On("RemoveE2TInstance", E2TAddress).Return(nil)
var e2tAddresses []string
rnibReaderMock.On("GetE2TAddresses").Return(e2tAddresses, e2managererrors.NewRnibDbError())
err := e2tInstancesManager.RemoveE2TInstance(E2TAddress)
assert.NotNil(t, err)
assert.IsType(t, e2managererrors.NewRnibDbError(), err)
rnibReaderMock.AssertExpectations(t)
rnibWriterMock.AssertExpectations(t)
}
func TestRemoveE2TInstanceRnibErrorInSaveAddresses(t *testing.T) {
rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t)
rnibWriterMock.On("RemoveE2TInstance", E2TAddress).Return(nil)
e2tAddresses := []string{E2TAddress, E2TAddress2}
rnibReaderMock.On("GetE2TAddresses").Return(e2tAddresses, nil)
e2tAddressesNew := []string{E2TAddress2}
rnibWriterMock.On("SaveE2TAddresses", e2tAddressesNew).Return(e2managererrors.NewRnibDbError())
err := e2tInstancesManager.RemoveE2TInstance(E2TAddress)
assert.NotNil(t, err)
assert.IsType(t, e2managererrors.NewRnibDbError(), err)
rnibReaderMock.AssertExpectations(t)
rnibWriterMock.AssertExpectations(t)
}
func TestSetE2tInstanceStateCurrentStateHasChanged(t *testing.T) {
rnibReaderMock, _, e2tInstancesManager := initE2TInstancesManagerTest(t)
e2tInstance := entities.NewE2TInstance(E2TAddress, PodName)
e2tInstance.State = entities.Active
rnibReaderMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance, nil)
err := e2tInstancesManager.SetE2tInstanceState(E2TAddress, entities.ToBeDeleted, entities.Active)
assert.NotNil(t, err)
assert.IsType(t, e2managererrors.NewInternalError(), err)
rnibReaderMock.AssertExpectations(t)
}
func TestSetE2tInstanceStateErrorInSaveE2TInstance(t *testing.T) {
rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t)
e2tInstance := entities.NewE2TInstance(E2TAddress, PodName)
e2tInstance.State = entities.ToBeDeleted
rnibReaderMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance, nil)
rnibWriterMock.On("SaveE2TInstance", mock.Anything).Return(common.NewInternalError(fmt.Errorf("for testing")))
err := e2tInstancesManager.SetE2tInstanceState(E2TAddress, entities.ToBeDeleted, entities.Active)
assert.NotNil(t, err)
assert.IsType(t, &common.InternalError{}, err)
rnibReaderMock.AssertExpectations(t)
}
func TestClearRansOfAllE2TInstancesEmptyList(t *testing.T) {
rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t)
E2TAddresses := []string{}
rnibReaderMock.On("GetE2TAddresses").Return(E2TAddresses, nil)
err := e2tInstancesManager.ClearRansOfAllE2TInstances()
assert.Nil(t, err)
rnibReaderMock.AssertExpectations(t)
rnibWriterMock.AssertExpectations(t)
}
func TestClearRansOfAllE2TInstancesErrorInSaveE2TInstance(t *testing.T) {
rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t)
addresses := []string{E2TAddress, E2TAddress2}
e2tInstance1 := entities.NewE2TInstance(E2TAddress, PodName)
e2tInstance1.AssociatedRanList = []string{"test1", "test2", "test3"}
e2tInstance2 := entities.NewE2TInstance(E2TAddress2, PodName)
e2tInstance2.AssociatedRanList = []string{"test4", "test5", "test6", "test7"}
rnibReaderMock.On("GetE2TAddresses").Return(addresses, nil)
rnibReaderMock.On("GetE2TInstances", addresses).Return([]*entities.E2TInstance{e2tInstance1, e2tInstance2}, nil)
rnibWriterMock.On("SaveE2TInstance", mock.MatchedBy(func(e2tInstance *entities.E2TInstance) bool { return e2tInstance.Address == E2TAddress})).Return(common.NewInternalError(fmt.Errorf("for testing")))
rnibWriterMock.On("SaveE2TInstance", mock.MatchedBy(func(e2tInstance *entities.E2TInstance) bool { return e2tInstance.Address == E2TAddress2})).Return(nil)
err := e2tInstancesManager.ClearRansOfAllE2TInstances()
assert.Nil(t, err)
rnibReaderMock.AssertExpectations(t)
rnibWriterMock.AssertExpectations(t)
}

View File

@@ -0,0 +1,89 @@
//
// Copyright 2019 AT&T Intellectual Property
// Copyright 2019 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.
//
// This source code is part of the near-RT RIC (RAN Intelligent Controller)
// platform project (RICP).
package managers
import (
"e2mgr/configuration"
"e2mgr/logger"
"e2mgr/models"
"e2mgr/rmrCgo"
"e2mgr/services/rmrsender"
"time"
)
type E2TKeepAliveWorker struct {
logger *logger.Logger
e2tShutdownManager IE2TShutdownManager
e2TInstancesManager IE2TInstancesManager
rmrSender *rmrsender.RmrSender
config *configuration.Configuration
}
func NewE2TKeepAliveWorker(logger *logger.Logger, rmrSender *rmrsender.RmrSender, e2TInstancesManager IE2TInstancesManager, e2tShutdownManager IE2TShutdownManager, config *configuration.Configuration) E2TKeepAliveWorker {
return E2TKeepAliveWorker{
logger: logger,
e2tShutdownManager: e2tShutdownManager,
e2TInstancesManager: e2TInstancesManager,
rmrSender: rmrSender,
config: config,
}
}
func (h E2TKeepAliveWorker) Execute() {
h.logger.Infof("#E2TKeepAliveWorker.Execute - keep alive started")
ticker := time.NewTicker(time.Duration(h.config.KeepAliveDelayMs) * time.Millisecond)
for _ = range ticker.C {
h.SendKeepAliveRequest()
h.E2TKeepAliveExpired()
}
}
func (h E2TKeepAliveWorker) E2TKeepAliveExpired() {
e2tInstances, err := h.e2TInstancesManager.GetE2TInstancesNoLogs()
if err != nil || len(e2tInstances) == 0 {
return
}
for _, e2tInstance := range e2tInstances {
delta := int64(time.Now().UnixNano()) - e2tInstance.KeepAliveTimestamp
timestampNanosec := int64(time.Duration(h.config.KeepAliveResponseTimeoutMs) * time.Millisecond)
if delta > timestampNanosec {
h.logger.Warnf("#E2TKeepAliveWorker.E2TKeepAliveExpired - e2t address: %s time expired, shutdown e2 instance", e2tInstance.Address)
h.e2tShutdownManager.Shutdown(e2tInstance)
}
}
}
func (h E2TKeepAliveWorker) SendKeepAliveRequest() {
rmrMessage := models.RmrMessage{MsgType: rmrCgo.E2_TERM_KEEP_ALIVE_REQ}
h.rmrSender.SendWithoutLogs(&rmrMessage)
}

View File

@@ -0,0 +1,205 @@
//
// Copyright 2019 AT&T Intellectual Property
// Copyright 2019 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.
//
// This source code is part of the near-RT RIC (RAN Intelligent Controller)
// platform project (RICP).
package managers
import (
"e2mgr/configuration"
"e2mgr/logger"
"e2mgr/mocks"
"e2mgr/rmrCgo"
"e2mgr/services"
"gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common"
"gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
"github.com/pkg/errors"
"github.com/stretchr/testify/mock"
"testing"
"time"
"unsafe"
)
func initE2TKeepAliveTest(t *testing.T) (*mocks.RmrMessengerMock, *mocks.RnibReaderMock, *mocks.RnibWriterMock, *mocks.E2TShutdownManagerMock, *E2TKeepAliveWorker) {
logger, err := logger.InitLogger(logger.DebugLevel)
if err != nil {
t.Errorf("#... - failed to initialize logger, error: %s", err)
}
config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: 3, KeepAliveResponseTimeoutMs: 400, KeepAliveDelayMs: 100}
readerMock := &mocks.RnibReaderMock{}
writerMock := &mocks.RnibWriterMock{}
e2tShutdownManagerMock := &mocks.E2TShutdownManagerMock{}
rnibDataService := services.NewRnibDataService(logger, config, readerMock, writerMock)
e2tInstancesManager := NewE2TInstancesManager(rnibDataService, logger)
rmrMessengerMock := &mocks.RmrMessengerMock{}
rmrSender := initRmrSender(rmrMessengerMock, logger)
e2tKeepAliveWorker := NewE2TKeepAliveWorker(logger, rmrSender, e2tInstancesManager, e2tShutdownManagerMock, config)
return rmrMessengerMock, readerMock, writerMock, e2tShutdownManagerMock, &e2tKeepAliveWorker
}
func TestSendKeepAliveRequest(t *testing.T) {
rmrMessengerMock, _, _, _, e2tKeepAliveWorker := initE2TKeepAliveTest(t)
rmrMessengerMock.On("SendMsg", mock.Anything, false).Return(&rmrCgo.MBuf{}, nil)
e2tKeepAliveWorker.SendKeepAliveRequest()
var payload, xAction []byte
var msgSrc unsafe.Pointer
req := rmrCgo.NewMBuf(rmrCgo.E2_TERM_KEEP_ALIVE_REQ, 0, "", &payload, &xAction, msgSrc)
rmrMessengerMock.AssertCalled(t, "SendMsg", req, false)
}
func TestShutdownExpiredE2T_InternalError(t *testing.T) {
rmrMessengerMock, readerMock, _, _, e2tKeepAliveWorker := initE2TKeepAliveTest(t)
readerMock.On("GetE2TAddresses").Return([]string{}, common.NewInternalError(errors.New("#reader.GetNodeb - Internal Error")))
e2tKeepAliveWorker.E2TKeepAliveExpired()
rmrMessengerMock.AssertNotCalled(t, "Shutdown")
}
func TestShutdownExpiredE2T_NoAddresses(t *testing.T) {
rmrMessengerMock, readerMock, _, _, e2tKeepAliveWorker := initE2TKeepAliveTest(t)
addresses := []string{}
readerMock.On("GetE2TAddresses").Return(addresses, nil)
e2tKeepAliveWorker.E2TKeepAliveExpired()
rmrMessengerMock.AssertNotCalled(t, "Shutdown")
}
func TestShutdownExpiredE2T_NotExpired_InternalError(t *testing.T) {
rmrMessengerMock, readerMock, _, _, e2tKeepAliveWorker := initE2TKeepAliveTest(t)
addresses := []string{E2TAddress,E2TAddress2}
e2tInstance1 := entities.NewE2TInstance(E2TAddress, PodName)
e2tInstance1.AssociatedRanList = []string{"test1","test2","test3"}
e2tInstance2 := entities.NewE2TInstance(E2TAddress2, PodName)
e2tInstance2.AssociatedRanList = []string{"test4","test5","test6", "test7"}
readerMock.On("GetE2TAddresses").Return(addresses, nil)
readerMock.On("GetE2TInstances",addresses).Return([]*entities.E2TInstance{e2tInstance1, e2tInstance2}, common.NewInternalError(errors.New("#reader.GetNodeb - Internal Error")))
e2tKeepAliveWorker.E2TKeepAliveExpired()
rmrMessengerMock.AssertNotCalled(t, "Shutdown")
}
func TestShutdownExpiredE2T_NoE2T(t *testing.T) {
rmrMessengerMock, readerMock, _, _, e2tKeepAliveWorker := initE2TKeepAliveTest(t)
readerMock.On("GetE2TAddresses").Return([]string{}, common.NewResourceNotFoundError("not found"))
e2tKeepAliveWorker.E2TKeepAliveExpired()
rmrMessengerMock.AssertNotCalled(t, "Shutdown")
}
func TestShutdownExpiredE2T_NotExpired(t *testing.T) {
rmrMessengerMock, readerMock, _, _, e2tKeepAliveWorker := initE2TKeepAliveTest(t)
addresses := []string{E2TAddress,E2TAddress2}
e2tInstance1 := entities.NewE2TInstance(E2TAddress, PodName)
e2tInstance1.AssociatedRanList = []string{"test1","test2","test3"}
e2tInstance2 := entities.NewE2TInstance(E2TAddress2, PodName)
e2tInstance2.AssociatedRanList = []string{"test4","test5","test6", "test7"}
readerMock.On("GetE2TAddresses").Return(addresses, nil)
readerMock.On("GetE2TInstances",addresses).Return([]*entities.E2TInstance{e2tInstance1, e2tInstance2}, nil)
e2tKeepAliveWorker.E2TKeepAliveExpired()
rmrMessengerMock.AssertNotCalled(t, "Shutdown")
}
func TestShutdownExpiredE2T_One_E2TExpired(t *testing.T) {
_, readerMock, _, e2tShutdownManagerMock, e2tKeepAliveWorker := initE2TKeepAliveTest(t)
addresses := []string{E2TAddress,E2TAddress2}
e2tInstance1 := entities.NewE2TInstance(E2TAddress, PodName)
e2tInstance1.AssociatedRanList = []string{"test1","test2","test3"}
time.Sleep(time.Duration(400) * time.Millisecond)
e2tInstance2 := entities.NewE2TInstance(E2TAddress2, PodName)
e2tInstance2.AssociatedRanList = []string{"test4","test5","test6", "test7"}
readerMock.On("GetE2TAddresses").Return(addresses, nil)
readerMock.On("GetE2TInstances",addresses).Return([]*entities.E2TInstance{e2tInstance1, e2tInstance2}, nil)
e2tShutdownManagerMock.On("Shutdown", e2tInstance1).Return(nil)
e2tKeepAliveWorker.E2TKeepAliveExpired()
e2tShutdownManagerMock.AssertNumberOfCalls(t, "Shutdown", 1)
}
func TestShutdownExpiredE2T_Two_E2TExpired(t *testing.T) {
_, readerMock, _, e2tShutdownManagerMock, e2tKeepAliveWorker := initE2TKeepAliveTest(t)
addresses := []string{E2TAddress,E2TAddress2}
e2tInstance1 := entities.NewE2TInstance(E2TAddress, PodName)
e2tInstance1.AssociatedRanList = []string{"test1","test2","test3"}
e2tInstance2 := entities.NewE2TInstance(E2TAddress2, PodName)
e2tInstance2.AssociatedRanList = []string{"test4","test5","test6", "test7"}
time.Sleep(time.Duration(400) * time.Millisecond)
readerMock.On("GetE2TAddresses").Return(addresses, nil)
readerMock.On("GetE2TInstances",addresses).Return([]*entities.E2TInstance{e2tInstance1, e2tInstance2}, nil)
e2tShutdownManagerMock.On("Shutdown", e2tInstance1).Return(nil)
e2tShutdownManagerMock.On("Shutdown", e2tInstance2).Return(nil)
e2tKeepAliveWorker.E2TKeepAliveExpired()
e2tShutdownManagerMock.AssertNumberOfCalls(t, "Shutdown", 2)
}
func TestExecute_Two_E2TExpired(t *testing.T) {
rmrMessengerMock, readerMock, _, e2tShutdownManagerMock, e2tKeepAliveWorker := initE2TKeepAliveTest(t)
addresses := []string{E2TAddress,E2TAddress2}
e2tInstance1 := entities.NewE2TInstance(E2TAddress, PodName)
e2tInstance1.AssociatedRanList = []string{"test1","test2","test3"}
readerMock.On("GetE2TAddresses").Return(addresses, nil)
readerMock.On("GetE2TInstances",addresses).Return([]*entities.E2TInstance{e2tInstance1}, nil)
e2tShutdownManagerMock.On("Shutdown", e2tInstance1).Return(nil)
rmrMessengerMock.On("SendMsg", mock.Anything, false).Return(&rmrCgo.MBuf{}, nil)
go e2tKeepAliveWorker.Execute()
time.Sleep(time.Duration(500) * time.Millisecond)
var payload, xAction []byte
var msgSrc unsafe.Pointer
req := rmrCgo.NewMBuf(rmrCgo.E2_TERM_KEEP_ALIVE_REQ, 0, "", &payload, &xAction, msgSrc)
rmrMessengerMock.AssertCalled(t, "SendMsg", req, false)
e2tShutdownManagerMock.AssertCalled(t, "Shutdown", e2tInstance1)
}

View File

@@ -0,0 +1,124 @@
//
// Copyright 2019 AT&T Intellectual Property
// Copyright 2019 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.
//
// This source code is part of the near-RT RIC (RAN Intelligent Controller)
// platform project (RICP).
package managers
import (
"e2mgr/configuration"
"e2mgr/logger"
"e2mgr/services"
"gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common"
"gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
"time"
)
type IE2TShutdownManager interface {
Shutdown(e2tInstance *entities.E2TInstance) error
}
type E2TShutdownManager struct {
logger *logger.Logger
config *configuration.Configuration
rnibDataService services.RNibDataService
e2TInstancesManager IE2TInstancesManager
e2tAssociationManager *E2TAssociationManager
kubernetesManager *KubernetesManager
}
func NewE2TShutdownManager(logger *logger.Logger, config *configuration.Configuration, rnibDataService services.RNibDataService, e2TInstancesManager IE2TInstancesManager, e2tAssociationManager *E2TAssociationManager, kubernetes *KubernetesManager) *E2TShutdownManager {
return &E2TShutdownManager{
logger: logger,
config: config,
rnibDataService: rnibDataService,
e2TInstancesManager: e2TInstancesManager,
e2tAssociationManager: e2tAssociationManager,
kubernetesManager: kubernetes,
}
}
func (m E2TShutdownManager) Shutdown(e2tInstance *entities.E2TInstance) error {
m.logger.Infof("#E2TShutdownManager.Shutdown - E2T %s is Dead, RIP", e2tInstance.Address)
isE2tInstanceBeingDeleted := m.isE2tInstanceAlreadyBeingDeleted(e2tInstance)
if isE2tInstanceBeingDeleted {
m.logger.Infof("#E2TShutdownManager.Shutdown - E2T %s is already being deleted", e2tInstance.Address)
return nil
}
//go m.kubernetesManager.DeletePod(e2tInstance.PodName)
err := m.markE2tInstanceToBeDeleted(e2tInstance)
if err != nil {
m.logger.Errorf("#E2TShutdownManager.Shutdown - Failed to mark E2T %s as 'ToBeDeleted'.", e2tInstance.Address)
return err
}
err = m.clearNodebsAssociation(e2tInstance.AssociatedRanList)
if err != nil {
m.logger.Errorf("#E2TShutdownManager.Shutdown - Failed to clear nodebs association to E2T %s.", e2tInstance.Address)
return err
}
err = m.e2tAssociationManager.RemoveE2tInstance(e2tInstance)
if err != nil {
m.logger.Errorf("#E2TShutdownManager.Shutdown - Failed to remove E2T %s.", e2tInstance.Address)
return err
}
m.logger.Infof("#E2TShutdownManager.Shutdown - E2T %s was shutdown successfully.", e2tInstance.Address)
return nil
}
func (m E2TShutdownManager) clearNodebsAssociation(ranNamesToBeDissociated []string) error {
for _, ranName := range ranNamesToBeDissociated {
nodeb, err := m.rnibDataService.GetNodeb(ranName)
if err != nil {
m.logger.Warnf("#E2TShutdownManager.associateAndSetupNodebs - Failed to get nodeb %s from db.", ranName)
_, ok := err.(*common.ResourceNotFoundError)
if !ok {
continue
}
return err
}
nodeb.AssociatedE2TInstanceAddress = ""
nodeb.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED
err = m.rnibDataService.UpdateNodebInfo(nodeb)
if err != nil {
m.logger.Errorf("#E2TShutdownManager.associateAndSetupNodebs - Failed to save nodeb %s from db.", ranName)
return err
}
}
return nil
}
func (m E2TShutdownManager) markE2tInstanceToBeDeleted(e2tInstance *entities.E2TInstance) error {
e2tInstance.State = entities.ToBeDeleted
e2tInstance.DeletionTimestamp = time.Now().UnixNano()
return m.rnibDataService.SaveE2TInstance(e2tInstance)
}
func (m E2TShutdownManager) isE2tInstanceAlreadyBeingDeleted(e2tInstance *entities.E2TInstance) bool {
delta := time.Now().UnixNano() - e2tInstance.DeletionTimestamp
timestampNanosec := int64(time.Duration(m.config.E2TInstanceDeletionTimeoutMs) * time.Millisecond)
return e2tInstance.State == entities.ToBeDeleted && delta <= timestampNanosec
}

View File

@@ -0,0 +1,510 @@
//
// Copyright 2019 AT&T Intellectual Property
// Copyright 2019 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.
//
// This source code is part of the near-RT RIC (RAN Intelligent Controller)
// platform project (RICP).
package managers
import (
"bytes"
"e2mgr/clients"
"e2mgr/configuration"
"e2mgr/e2managererrors"
"e2mgr/mocks"
"e2mgr/models"
"e2mgr/services"
"encoding/json"
"fmt"
"gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common"
"gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"io/ioutil"
//"k8s.io/apimachinery/pkg/runtime"
//"k8s.io/client-go/kubernetes/fake"
"net/http"
"testing"
"time"
)
const E2TAddress3 = "10.10.2.17:9800"
func initE2TShutdownManagerTest(t *testing.T) (*E2TShutdownManager, *mocks.RnibReaderMock, *mocks.RnibWriterMock, *mocks.HttpClientMock, *KubernetesManager) {
log := initLog(t)
config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: 3, E2TInstanceDeletionTimeoutMs: 15000}
readerMock := &mocks.RnibReaderMock{}
writerMock := &mocks.RnibWriterMock{}
rnibDataService := services.NewRnibDataService(log, config, readerMock, writerMock)
e2tInstancesManager := NewE2TInstancesManager(rnibDataService, log)
httpClientMock := &mocks.HttpClientMock{}
rmClient := clients.NewRoutingManagerClient(log, config, httpClientMock)
associationManager := NewE2TAssociationManager(log, rnibDataService, e2tInstancesManager, rmClient)
//kubernetesManager := initKubernetesManagerTest(t)
/*shutdownManager := NewE2TShutdownManager(log, config, rnibDataService, e2tInstancesManager, associationManager, kubernetesManager)
return shutdownManager, readerMock, writerMock, httpClientMock, kubernetesManager*/
shutdownManager := NewE2TShutdownManager(log, config, rnibDataService, e2tInstancesManager, associationManager, nil)
return shutdownManager, readerMock, writerMock, httpClientMock, nil
}
func TestShutdownSuccess1OutOf3Instances(t *testing.T) {
shutdownManager, readerMock, writerMock, httpClientMock,_ := initE2TShutdownManagerTest(t)
e2tInstance1 := entities.NewE2TInstance(E2TAddress, PodName)
e2tInstance1.State = entities.Active
e2tInstance1.AssociatedRanList = []string{"test1", "test2", "test5"}
e2tInstance2 := entities.NewE2TInstance(E2TAddress2, PodName)
e2tInstance2.State = entities.Active
e2tInstance2.AssociatedRanList = []string{"test3"}
e2tInstance3 := entities.NewE2TInstance(E2TAddress3, PodName)
e2tInstance3.State = entities.Active
e2tInstance3.AssociatedRanList = []string{"test4"}
writerMock.On("SaveE2TInstance", mock.MatchedBy(func(e2tInstance *entities.E2TInstance) bool { return e2tInstance.Address == E2TAddress && e2tInstance.State == entities.ToBeDeleted })).Return(nil)
nodeb1 := &entities.NodebInfo{RanName:"test1", AssociatedE2TInstanceAddress:E2TAddress, ConnectionStatus:entities.ConnectionStatus_CONNECTED, E2ApplicationProtocol:entities.E2ApplicationProtocol_X2_SETUP_REQUEST}
readerMock.On("GetNodeb", "test1").Return(nodeb1, nil)
nodeb2 := &entities.NodebInfo{RanName:"test2", AssociatedE2TInstanceAddress:E2TAddress, ConnectionStatus:entities.ConnectionStatus_SHUTTING_DOWN, E2ApplicationProtocol:entities.E2ApplicationProtocol_X2_SETUP_REQUEST}
readerMock.On("GetNodeb", "test2").Return(nodeb2, nil)
nodeb5 := &entities.NodebInfo{RanName:"test5", AssociatedE2TInstanceAddress:E2TAddress, ConnectionStatus:entities.ConnectionStatus_CONNECTED, E2ApplicationProtocol:entities.E2ApplicationProtocol_X2_SETUP_REQUEST}
readerMock.On("GetNodeb", "test5").Return(nodeb5, nil)
e2tAddresses := []string{E2TAddress, E2TAddress2,E2TAddress3}
readerMock.On("GetE2TAddresses").Return(e2tAddresses, nil)
data := models.NewRoutingManagerDeleteRequestModel(E2TAddress, e2tInstance1.AssociatedRanList, nil)
marshaled, _ := json.Marshal(data)
body := bytes.NewBuffer(marshaled)
respBody := ioutil.NopCloser(bytes.NewBufferString(""))
httpClientMock.On("Delete", "e2t", "application/json", body).Return(&http.Response{StatusCode: http.StatusCreated, Body: respBody}, nil)
writerMock.On("RemoveE2TInstance", E2TAddress).Return(nil)
writerMock.On("SaveE2TAddresses", []string{E2TAddress2,E2TAddress3}).Return(nil)
nodeb1connected := *nodeb1
nodeb1connected.AssociatedE2TInstanceAddress = ""
nodeb1connected.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED
writerMock.On("UpdateNodebInfo", &nodeb1connected).Return(nil)
nodeb2connected := *nodeb2
nodeb2connected.AssociatedE2TInstanceAddress = ""
nodeb2connected.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED
writerMock.On("UpdateNodebInfo", &nodeb2connected).Return(nil)
nodeb5connected := *nodeb5
nodeb5connected.AssociatedE2TInstanceAddress = ""
nodeb5connected.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED
writerMock.On("UpdateNodebInfo", &nodeb5connected).Return(nil)
err := shutdownManager.Shutdown(e2tInstance1)
assert.Nil(t, err)
readerMock.AssertExpectations(t)
writerMock.AssertExpectations(t)
httpClientMock.AssertExpectations(t)
}
func TestShutdownSuccess1InstanceWithoutRans(t *testing.T) {
shutdownManager, readerMock, writerMock, httpClientMock,_ := initE2TShutdownManagerTest(t)
e2tInstance1 := entities.NewE2TInstance(E2TAddress, PodName)
e2tInstance1.State = entities.Active
e2tInstance1.AssociatedRanList = []string{}
writerMock.On("SaveE2TInstance", mock.MatchedBy(func(e2tInstance *entities.E2TInstance) bool { return e2tInstance.Address == E2TAddress && e2tInstance.State == entities.ToBeDeleted })).Return(nil)
data := models.NewRoutingManagerDeleteRequestModel(E2TAddress, nil, nil)
marshaled, _ := json.Marshal(data)
body := bytes.NewBuffer(marshaled)
respBody := ioutil.NopCloser(bytes.NewBufferString(""))
httpClientMock.On("Delete", "e2t", "application/json", body).Return(&http.Response{StatusCode: http.StatusCreated, Body: respBody}, nil)
writerMock.On("RemoveE2TInstance", E2TAddress).Return(nil)
readerMock.On("GetE2TAddresses").Return([]string{E2TAddress}, nil)
writerMock.On("SaveE2TAddresses", []string{}).Return(nil)
err := shutdownManager.Shutdown(e2tInstance1)
assert.Nil(t, err)
readerMock.AssertExpectations(t)
writerMock.AssertExpectations(t)
httpClientMock.AssertExpectations(t)
}
func TestShutdownSuccess1Instance2Rans(t *testing.T) {
shutdownManager, readerMock, writerMock, httpClientMock,_ := initE2TShutdownManagerTest(t)
e2tInstance1 := entities.NewE2TInstance(E2TAddress, PodName)
e2tInstance1.State = entities.Active
e2tInstance1.AssociatedRanList = []string{"test1", "test2"}
writerMock.On("SaveE2TInstance", mock.MatchedBy(func(e2tInstance *entities.E2TInstance) bool { return e2tInstance.Address == E2TAddress && e2tInstance.State == entities.ToBeDeleted })).Return(nil)
nodeb1 := &entities.NodebInfo{RanName:"test1", AssociatedE2TInstanceAddress:E2TAddress, ConnectionStatus:entities.ConnectionStatus_CONNECTED, E2ApplicationProtocol:entities.E2ApplicationProtocol_X2_SETUP_REQUEST}
readerMock.On("GetNodeb", "test1").Return(nodeb1, nil)
nodeb2 := &entities.NodebInfo{RanName:"test2", AssociatedE2TInstanceAddress:E2TAddress, ConnectionStatus:entities.ConnectionStatus_DISCONNECTED, E2ApplicationProtocol:entities.E2ApplicationProtocol_X2_SETUP_REQUEST}
readerMock.On("GetNodeb", "test2").Return(nodeb2, nil)
data := models.NewRoutingManagerDeleteRequestModel(E2TAddress, []string{"test1", "test2"}, nil)
marshaled, _ := json.Marshal(data)
body := bytes.NewBuffer(marshaled)
respBody := ioutil.NopCloser(bytes.NewBufferString(""))
httpClientMock.On("Delete", "e2t", "application/json", body).Return(&http.Response{StatusCode: http.StatusCreated, Body: respBody}, nil)
writerMock.On("RemoveE2TInstance", E2TAddress).Return(nil)
readerMock.On("GetE2TAddresses").Return([]string{E2TAddress}, nil)
writerMock.On("SaveE2TAddresses", []string{}).Return(nil)
nodeb1new := *nodeb1
nodeb1new.AssociatedE2TInstanceAddress = ""
nodeb1new.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED
writerMock.On("UpdateNodebInfo", &nodeb1new).Return(nil)
nodeb2new := *nodeb2
nodeb2new.AssociatedE2TInstanceAddress = ""
nodeb2new.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED
writerMock.On("UpdateNodebInfo", &nodeb2new).Return(nil)
err := shutdownManager.Shutdown(e2tInstance1)
assert.Nil(t, err)
readerMock.AssertExpectations(t)
writerMock.AssertExpectations(t)
httpClientMock.AssertExpectations(t)
}
func TestShutdownE2tInstanceAlreadyBeingDeleted(t *testing.T) {
shutdownManager, readerMock, writerMock, httpClientMock,_ := initE2TShutdownManagerTest(t)
e2tInstance1 := entities.NewE2TInstance(E2TAddress, PodName)
e2tInstance1.State = entities.ToBeDeleted
e2tInstance1.AssociatedRanList = []string{"test1"}
e2tInstance1.DeletionTimestamp = time.Now().UnixNano()
err := shutdownManager.Shutdown(e2tInstance1)
assert.Nil(t, err)
readerMock.AssertExpectations(t)
writerMock.AssertExpectations(t)
httpClientMock.AssertExpectations(t)
}
func TestShutdownFailureMarkInstanceAsToBeDeleted(t *testing.T) {
shutdownManager, readerMock, writerMock, httpClientMock,_ := initE2TShutdownManagerTest(t)
e2tInstance1 := entities.NewE2TInstance(E2TAddress, PodName)
e2tInstance1.State = entities.Active
e2tInstance1.AssociatedRanList = []string{"test1", "test2", "test5"}
writerMock.On("SaveE2TInstance", mock.MatchedBy(func(e2tInstance *entities.E2TInstance) bool { return e2tInstance.Address == E2TAddress && e2tInstance.State == entities.ToBeDeleted })).Return(e2managererrors.NewRnibDbError())
err := shutdownManager.Shutdown(e2tInstance1)
assert.NotNil(t, err)
readerMock.AssertExpectations(t)
writerMock.AssertExpectations(t)
httpClientMock.AssertExpectations(t)
}
func TestShutdownFailureRoutingManagerError(t *testing.T) {
shutdownManager, readerMock, writerMock, httpClientMock,_ := initE2TShutdownManagerTest(t)
e2tInstance1 := entities.NewE2TInstance(E2TAddress, PodName)
e2tInstance1.State = entities.Active
e2tInstance1.AssociatedRanList = []string{"test1", "test2", "test5"}
e2tInstance2 := entities.NewE2TInstance(E2TAddress2, PodName)
e2tInstance2.State = entities.Active
e2tInstance2.AssociatedRanList = []string{"test3"}
e2tInstance3 := entities.NewE2TInstance(E2TAddress3, PodName)
e2tInstance3.State = entities.Active
e2tInstance3.AssociatedRanList = []string{"test4"}
writerMock.On("SaveE2TInstance", mock.MatchedBy(func(e2tInstance *entities.E2TInstance) bool { return e2tInstance.Address == E2TAddress && e2tInstance.State == entities.ToBeDeleted })).Return(nil)
nodeb1 := &entities.NodebInfo{RanName:"test1", AssociatedE2TInstanceAddress:E2TAddress, ConnectionStatus:entities.ConnectionStatus_CONNECTED, E2ApplicationProtocol:entities.E2ApplicationProtocol_X2_SETUP_REQUEST}
readerMock.On("GetNodeb", "test1").Return(nodeb1, nil)
nodeb2 := &entities.NodebInfo{RanName:"test2", AssociatedE2TInstanceAddress:E2TAddress, ConnectionStatus:entities.ConnectionStatus_SHUTTING_DOWN, E2ApplicationProtocol:entities.E2ApplicationProtocol_X2_SETUP_REQUEST}
readerMock.On("GetNodeb", "test2").Return(nodeb2, nil)
nodeb5 := &entities.NodebInfo{RanName:"test5", AssociatedE2TInstanceAddress:E2TAddress, ConnectionStatus:entities.ConnectionStatus_CONNECTED, E2ApplicationProtocol:entities.E2ApplicationProtocol_X2_SETUP_REQUEST}
readerMock.On("GetNodeb", "test5").Return(nodeb5, nil)
e2tAddresses := []string{E2TAddress, E2TAddress2,E2TAddress3}
readerMock.On("GetE2TAddresses").Return(e2tAddresses, nil)
data := models.NewRoutingManagerDeleteRequestModel(E2TAddress, e2tInstance1.AssociatedRanList, nil)
marshaled, _ := json.Marshal(data)
body := bytes.NewBuffer(marshaled)
respBody := ioutil.NopCloser(bytes.NewBufferString(""))
httpClientMock.On("Delete", "e2t", "application/json", body).Return(&http.Response{StatusCode: http.StatusBadRequest, Body: respBody}, nil)
writerMock.On("RemoveE2TInstance", E2TAddress).Return(nil)
writerMock.On("SaveE2TAddresses", []string{E2TAddress2,E2TAddress3}).Return(nil)
nodeb1connected := *nodeb1
nodeb1connected.AssociatedE2TInstanceAddress = ""
nodeb1connected.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED
writerMock.On("UpdateNodebInfo", &nodeb1connected).Return(nil)
nodeb2connected := *nodeb2
nodeb2connected.AssociatedE2TInstanceAddress = ""
nodeb2connected.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED
writerMock.On("UpdateNodebInfo", &nodeb2connected).Return(nil)
nodeb5connected := *nodeb5
nodeb5connected.AssociatedE2TInstanceAddress = ""
nodeb5connected.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED
writerMock.On("UpdateNodebInfo", &nodeb5connected).Return(nil)
err := shutdownManager.Shutdown(e2tInstance1)
assert.Nil(t, err)
readerMock.AssertExpectations(t)
writerMock.AssertExpectations(t)
httpClientMock.AssertExpectations(t)
}
func TestShutdownFailureInClearNodebsAssociation(t *testing.T) {
shutdownManager, readerMock, writerMock, httpClientMock,_ := initE2TShutdownManagerTest(t)
e2tInstance1 := entities.NewE2TInstance(E2TAddress, PodName)
e2tInstance1.State = entities.Active
e2tInstance1.AssociatedRanList = []string{"test1", "test2"}
writerMock.On("SaveE2TInstance", mock.MatchedBy(func(e2tInstance *entities.E2TInstance) bool { return e2tInstance.Address == E2TAddress && e2tInstance.State == entities.ToBeDeleted })).Return(nil)
nodeb1 := &entities.NodebInfo{RanName:"test1", AssociatedE2TInstanceAddress:E2TAddress, ConnectionStatus:entities.ConnectionStatus_CONNECTED, E2ApplicationProtocol:entities.E2ApplicationProtocol_X2_SETUP_REQUEST}
readerMock.On("GetNodeb", "test1").Return(nodeb1, nil)
nodeb1new := *nodeb1
nodeb1new.AssociatedE2TInstanceAddress = ""
nodeb1new.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED
writerMock.On("UpdateNodebInfo", &nodeb1new).Return(common.NewInternalError(fmt.Errorf("for tests")))
err := shutdownManager.Shutdown(e2tInstance1)
assert.NotNil(t, err)
readerMock.AssertExpectations(t)
writerMock.AssertExpectations(t)
httpClientMock.AssertExpectations(t)
}
func TestShutdownResourceNotFoundErrorInGetNodeb(t *testing.T) {
shutdownManager, readerMock, writerMock, httpClientMock,_ := initE2TShutdownManagerTest(t)
e2tInstance1 := entities.NewE2TInstance(E2TAddress, PodName)
e2tInstance1.State = entities.Active
e2tInstance1.AssociatedRanList = []string{"test1", "test2"}
writerMock.On("SaveE2TInstance", mock.MatchedBy(func(e2tInstance *entities.E2TInstance) bool { return e2tInstance.Address == E2TAddress && e2tInstance.State == entities.ToBeDeleted })).Return(nil)
nodeb1 := &entities.NodebInfo{RanName:"test1", AssociatedE2TInstanceAddress:E2TAddress, ConnectionStatus:entities.ConnectionStatus_CONNECTED, E2ApplicationProtocol:entities.E2ApplicationProtocol_X2_SETUP_REQUEST}
readerMock.On("GetNodeb", "test1").Return(nodeb1, nil)
var nodeb2 *entities.NodebInfo
readerMock.On("GetNodeb", "test2").Return(nodeb2, common.NewResourceNotFoundError("for testing"))
nodeb1new := *nodeb1
nodeb1new.AssociatedE2TInstanceAddress = ""
nodeb1new.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED
writerMock.On("UpdateNodebInfo", &nodeb1new).Return(nil)
err := shutdownManager.Shutdown(e2tInstance1)
assert.NotNil(t, err)
readerMock.AssertExpectations(t)
writerMock.AssertExpectations(t)
httpClientMock.AssertExpectations(t)
}
func TestShutdownResourceGeneralErrorInGetNodeb(t *testing.T) {
shutdownManager, readerMock, writerMock, httpClientMock,_ := initE2TShutdownManagerTest(t)
e2tInstance1 := entities.NewE2TInstance(E2TAddress, PodName)
e2tInstance1.State = entities.Active
e2tInstance1.AssociatedRanList = []string{"test1", "test2"}
writerMock.On("SaveE2TInstance", mock.MatchedBy(func(e2tInstance *entities.E2TInstance) bool { return e2tInstance.Address == E2TAddress && e2tInstance.State == entities.ToBeDeleted })).Return(nil)
var nodeb1 *entities.NodebInfo
readerMock.On("GetNodeb", "test1").Return(nodeb1, common.NewInternalError(fmt.Errorf("for testing")))
nodeb2 := &entities.NodebInfo{RanName:"test2", AssociatedE2TInstanceAddress:E2TAddress, ConnectionStatus:entities.ConnectionStatus_DISCONNECTED, E2ApplicationProtocol:entities.E2ApplicationProtocol_X2_SETUP_REQUEST}
readerMock.On("GetNodeb", "test2").Return(nodeb2, nil)
data := models.NewRoutingManagerDeleteRequestModel(E2TAddress, []string{"test1", "test2"}, nil)
marshaled, _ := json.Marshal(data)
body := bytes.NewBuffer(marshaled)
respBody := ioutil.NopCloser(bytes.NewBufferString(""))
httpClientMock.On("Delete", "e2t", "application/json", body).Return(&http.Response{StatusCode: http.StatusCreated, Body: respBody}, nil)
writerMock.On("RemoveE2TInstance", E2TAddress).Return(nil)
readerMock.On("GetE2TAddresses").Return([]string{E2TAddress}, nil)
writerMock.On("SaveE2TAddresses", []string{}).Return(nil)
nodeb2new := *nodeb2
nodeb2new.AssociatedE2TInstanceAddress = ""
nodeb2new.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED
writerMock.On("UpdateNodebInfo", &nodeb2new).Return(nil)
err := shutdownManager.Shutdown(e2tInstance1)
assert.Nil(t, err)
readerMock.AssertExpectations(t)
writerMock.AssertExpectations(t)
httpClientMock.AssertExpectations(t)
}
func TestShutdownFailureInRemoveE2TInstance(t *testing.T) {
shutdownManager, readerMock, writerMock, httpClientMock,_ := initE2TShutdownManagerTest(t)
e2tInstance1 := entities.NewE2TInstance(E2TAddress, PodName)
e2tInstance1.State = entities.Active
e2tInstance1.AssociatedRanList = []string{"test1", "test2", "test5"}
e2tInstance2 := entities.NewE2TInstance(E2TAddress2, PodName)
e2tInstance2.State = entities.Active
e2tInstance2.AssociatedRanList = []string{"test3"}
e2tInstance3 := entities.NewE2TInstance(E2TAddress3, PodName)
e2tInstance3.State = entities.Active
e2tInstance3.AssociatedRanList = []string{"test4"}
writerMock.On("SaveE2TInstance", mock.MatchedBy(func(e2tInstance *entities.E2TInstance) bool { return e2tInstance.Address == E2TAddress && e2tInstance.State == entities.ToBeDeleted })).Return(nil)
nodeb1 := &entities.NodebInfo{RanName:"test1", AssociatedE2TInstanceAddress:E2TAddress, ConnectionStatus:entities.ConnectionStatus_CONNECTED, E2ApplicationProtocol:entities.E2ApplicationProtocol_X2_SETUP_REQUEST}
readerMock.On("GetNodeb", "test1").Return(nodeb1, nil)
nodeb2 := &entities.NodebInfo{RanName:"test2", AssociatedE2TInstanceAddress:E2TAddress, ConnectionStatus:entities.ConnectionStatus_SHUTTING_DOWN, E2ApplicationProtocol:entities.E2ApplicationProtocol_X2_SETUP_REQUEST}
readerMock.On("GetNodeb", "test2").Return(nodeb2, nil)
nodeb5 := &entities.NodebInfo{RanName:"test5", AssociatedE2TInstanceAddress:E2TAddress, ConnectionStatus:entities.ConnectionStatus_CONNECTED, E2ApplicationProtocol:entities.E2ApplicationProtocol_X2_SETUP_REQUEST}
readerMock.On("GetNodeb", "test5").Return(nodeb5, nil)
data := models.NewRoutingManagerDeleteRequestModel(E2TAddress, e2tInstance1.AssociatedRanList, nil)
marshaled, _ := json.Marshal(data)
body := bytes.NewBuffer(marshaled)
respBody := ioutil.NopCloser(bytes.NewBufferString(""))
httpClientMock.On("Delete", "e2t", "application/json", body).Return(&http.Response{StatusCode: http.StatusCreated, Body: respBody}, nil)
writerMock.On("RemoveE2TInstance", E2TAddress).Return(common.NewInternalError(fmt.Errorf("for tests")))
nodeb1connected := *nodeb1
nodeb1connected.AssociatedE2TInstanceAddress = ""
nodeb1connected.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED
writerMock.On("UpdateNodebInfo", &nodeb1connected).Return(nil)
nodeb2connected := *nodeb2
nodeb2connected.AssociatedE2TInstanceAddress = ""
nodeb2connected.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED
writerMock.On("UpdateNodebInfo", &nodeb2connected).Return(nil)
nodeb5connected := *nodeb5
nodeb5connected.AssociatedE2TInstanceAddress = ""
nodeb5connected.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED
writerMock.On("UpdateNodebInfo", &nodeb5connected).Return(nil)
err := shutdownManager.Shutdown(e2tInstance1)
assert.IsType(t, &e2managererrors.RnibDbError{}, err)
readerMock.AssertExpectations(t)
writerMock.AssertExpectations(t)
httpClientMock.AssertExpectations(t)
}
/*
func TestShutdownSuccess2Instance2Rans(t *testing.T) {
shutdownManager, readerMock, writerMock, httpClientMock,kubernetesManager := initE2TShutdownManagerTest(t)
e2tInstance1 := entities.NewE2TInstance(E2TAddress, PodName)
e2tInstance1.State = entities.Active
e2tInstance1.AssociatedRanList = []string{"test2"}
writerMock.On("SaveE2TInstance", mock.MatchedBy(func(e2tInstance *entities.E2TInstance) bool { return e2tInstance.Address == E2TAddress && e2tInstance.State == entities.ToBeDeleted })).Return(nil)
nodeb1 := &entities.NodebInfo{RanName:"test1", AssociatedE2TInstanceAddress:E2TAddress2, ConnectionStatus:entities.ConnectionStatus_CONNECTED, E2ApplicationProtocol:entities.E2ApplicationProtocol_X2_SETUP_REQUEST}
nodeb2 := &entities.NodebInfo{RanName:"test2", AssociatedE2TInstanceAddress:E2TAddress, ConnectionStatus:entities.ConnectionStatus_DISCONNECTED, E2ApplicationProtocol:entities.E2ApplicationProtocol_X2_SETUP_REQUEST}
readerMock.On("GetNodeb", "test2").Return(nodeb2, nil)
data := models.NewRoutingManagerDeleteRequestModel(E2TAddress, []string{"test2"}, nil)
marshaled, _ := json.Marshal(data)
body := bytes.NewBuffer(marshaled)
respBody := ioutil.NopCloser(bytes.NewBufferString(""))
httpClientMock.On("Delete", "e2t", "application/json", body).Return(&http.Response{StatusCode: http.StatusCreated, Body: respBody}, nil)
writerMock.On("RemoveE2TInstance", E2TAddress).Return(nil)
readerMock.On("GetE2TAddresses").Return([]string{E2TAddress}, nil)
writerMock.On("SaveE2TAddresses", []string{}).Return(nil)
nodeb1new := *nodeb1
nodeb1new.AssociatedE2TInstanceAddress = ""
nodeb1new.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED
nodeb2new := *nodeb2
nodeb2new.AssociatedE2TInstanceAddress = ""
nodeb2new.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED
writerMock.On("UpdateNodebInfo", &nodeb2new).Return(nil)
test := TestStruct{
description: "namespace, 2 pods in Oran",
namespace: "oran",
objs: []runtime.Object{pod("oran", PodName), pod("oran", "e2t_2"), pod("some-namespace", "POD_Test_1")},
}
t.Run(test.description, func(t *testing.T) {
kubernetesManager.ClientSet = fake.NewSimpleClientset(test.objs...)
err := shutdownManager.Shutdown(e2tInstance1)
assert.Nil(t, err)
readerMock.AssertExpectations(t)
writerMock.AssertExpectations(t)
httpClientMock.AssertExpectations(t)
})
}
func TestShutdownSuccess2Instance2RansNoPod(t *testing.T) {
shutdownManager, readerMock, writerMock, httpClientMock,kubernetesManager := initE2TShutdownManagerTest(t)
e2tInstance1 := entities.NewE2TInstance(E2TAddress, PodName)
e2tInstance1.State = entities.Active
e2tInstance1.AssociatedRanList = []string{"test2"}
writerMock.On("SaveE2TInstance", mock.MatchedBy(func(e2tInstance *entities.E2TInstance) bool { return e2tInstance.Address == E2TAddress && e2tInstance.State == entities.ToBeDeleted })).Return(nil)
nodeb1 := &entities.NodebInfo{RanName:"test1", AssociatedE2TInstanceAddress:E2TAddress2, ConnectionStatus:entities.ConnectionStatus_CONNECTED, E2ApplicationProtocol:entities.E2ApplicationProtocol_X2_SETUP_REQUEST}
nodeb2 := &entities.NodebInfo{RanName:"test2", AssociatedE2TInstanceAddress:E2TAddress, ConnectionStatus:entities.ConnectionStatus_DISCONNECTED, E2ApplicationProtocol:entities.E2ApplicationProtocol_X2_SETUP_REQUEST}
readerMock.On("GetNodeb", "test2").Return(nodeb2, nil)
data := models.NewRoutingManagerDeleteRequestModel(E2TAddress, []string{"test2"}, nil)
marshaled, _ := json.Marshal(data)
body := bytes.NewBuffer(marshaled)
respBody := ioutil.NopCloser(bytes.NewBufferString(""))
httpClientMock.On("Delete", "e2t", "application/json", body).Return(&http.Response{StatusCode: http.StatusCreated, Body: respBody}, nil)
writerMock.On("RemoveE2TInstance", E2TAddress).Return(nil)
readerMock.On("GetE2TAddresses").Return([]string{E2TAddress}, nil)
writerMock.On("SaveE2TAddresses", []string{}).Return(nil)
nodeb1new := *nodeb1
nodeb1new.AssociatedE2TInstanceAddress = ""
nodeb1new.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED
nodeb2new := *nodeb2
nodeb2new.AssociatedE2TInstanceAddress = ""
nodeb2new.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED
writerMock.On("UpdateNodebInfo", &nodeb2new).Return(nil)
test := TestStruct{
description: "namespace, 2 pods in Oran",
namespace: "oran",
objs: []runtime.Object{pod("oran", "e2t_2"), pod("some-namespace", "POD_Test_1")},
}
t.Run(test.description, func(t *testing.T) {
kubernetesManager.ClientSet = fake.NewSimpleClientset(test.objs...)
err := shutdownManager.Shutdown(e2tInstance1)
assert.Nil(t, err)
readerMock.AssertExpectations(t)
writerMock.AssertExpectations(t)
httpClientMock.AssertExpectations(t)
})
}*/

View File

@@ -0,0 +1,54 @@
//
// Copyright 2019 AT&T Intellectual Property
// Copyright 2019 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.
// This source code is part of the near-RT RIC (RAN Intelligent Controller)
// platform project (RICP).
package managers
import (
"e2mgr/converters"
"e2mgr/logger"
"gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
)
type EndcSetupFailureResponseManager struct {
converter converters.IEndcSetupFailureResponseConverter
}
func NewEndcSetupFailureResponseManager(converter converters.IEndcSetupFailureResponseConverter) *EndcSetupFailureResponseManager {
return &EndcSetupFailureResponseManager{
converter: converter,
}
}
func (m *EndcSetupFailureResponseManager) PopulateNodebByPdu(logger *logger.Logger, nbIdentity *entities.NbIdentity, nodebInfo *entities.NodebInfo, payload []byte) error {
failureResponse, err := m.converter.UnpackEndcSetupFailureResponseAndExtract(payload)
if err != nil {
logger.Errorf("#EndcSetupFailureResponseManager.PopulateNodebByPdu - RAN name: %s - Unpack and extract failed. Error: %v", nodebInfo.RanName, err)
return err
}
logger.Infof("#EndcSetupFailureResponseManager.PopulateNodebByPdu - RAN name: %s - Unpacked payload and extracted protobuf successfully", nodebInfo.RanName)
nodebInfo.ConnectionStatus = entities.ConnectionStatus_CONNECTED_SETUP_FAILED
nodebInfo.SetupFailure = failureResponse
nodebInfo.FailureType = entities.Failure_ENDC_X2_SETUP_FAILURE
return nil
}

View File

@@ -0,0 +1,70 @@
//
// Copyright 2019 AT&T Intellectual Property
// Copyright 2019 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.
//
// This source code is part of the near-RT RIC (RAN Intelligent Controller)
// platform project (RICP).
package managers
import (
"e2mgr/converters"
"e2mgr/tests"
"fmt"
"gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
"github.com/stretchr/testify/assert"
"math/rand"
"testing"
)
func TestPopulateNodebByPduFailure(t *testing.T) {
logger := tests.InitLog(t)
nodebInfo := &entities.NodebInfo{}
nodebIdentity := &entities.NbIdentity{}
converter := converters.NewEndcSetupFailureResponseConverter(logger)
handler := NewEndcSetupFailureResponseManager(converter)
err := handler.PopulateNodebByPdu(logger, nodebIdentity, nodebInfo, createRandomPayload())
assert.NotNil(t, err)
}
func TestPopulateNodebByPduSuccess(t *testing.T) {
logger := tests.InitLog(t)
nodebInfo := &entities.NodebInfo{}
nodebIdentity := &entities.NbIdentity{}
converter := converters.NewEndcSetupFailureResponseConverter(logger)
handler := NewEndcSetupFailureResponseManager(converter)
err := handler.PopulateNodebByPdu(logger, nodebIdentity, nodebInfo, createSetupFailureResponsePayload(t))
assert.Nil(t, err)
assert.Equal(t, entities.ConnectionStatus_CONNECTED_SETUP_FAILED, nodebInfo.ConnectionStatus)
assert.Equal(t, entities.Failure_ENDC_X2_SETUP_FAILURE, nodebInfo.FailureType)
}
func createSetupFailureResponsePayload(t *testing.T) []byte {
packedPdu := "4024001a0000030005400200000016400100001140087821a00000008040"
var payload []byte
_, err := fmt.Sscanf(packedPdu, "%x", &payload)
if err != nil {
t.Errorf("convert inputPayloadAsStr to payloadAsByte. Error: %v\n", err)
}
return payload
}
func createRandomPayload() []byte {
payload := make([]byte, 20)
rand.Read(payload)
return payload
}

View File

@@ -0,0 +1,57 @@
//
// Copyright 2019 AT&T Intellectual Property
// Copyright 2019 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.
// This source code is part of the near-RT RIC (RAN Intelligent Controller)
// platform project (RICP).
package managers
import (
"e2mgr/converters"
"e2mgr/logger"
"gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
)
type EndcSetupResponseManager struct{
converter converters.IEndcSetupResponseConverter
}
func NewEndcSetupResponseManager(converter converters.IEndcSetupResponseConverter) *EndcSetupResponseManager {
return &EndcSetupResponseManager{
converter: converter,
}
}
func (m *EndcSetupResponseManager) PopulateNodebByPdu(logger *logger.Logger, nbIdentity *entities.NbIdentity, nodebInfo *entities.NodebInfo, payload []byte) error {
gnbId, gnb, err := m.converter.UnpackEndcSetupResponseAndExtract(payload)
if err != nil {
logger.Errorf("#EndcSetupResponseManager.PopulateNodebByPdu - RAN name: %s - Unpack and extract failed. Error: %v", nodebInfo.RanName, err)
return err
}
logger.Infof("#EndcSetupResponseManager.PopulateNodebByPdu - RAN name: %s - Unpacked payload and extracted protobuf successfully", nodebInfo.RanName)
nbIdentity.GlobalNbId = gnbId
nodebInfo.GlobalNbId = gnbId
nodebInfo.ConnectionStatus = entities.ConnectionStatus_CONNECTED
nodebInfo.NodeType = entities.Node_GNB
nodebInfo.Configuration = &entities.NodebInfo_Gnb{Gnb: gnb}
return nil
}

View File

@@ -0,0 +1,63 @@
//
// Copyright 2019 AT&T Intellectual Property
// Copyright 2019 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.
//
// This source code is part of the near-RT RIC (RAN Intelligent Controller)
// platform project (RICP).
package managers
import (
"e2mgr/converters"
"e2mgr/tests"
"fmt"
"gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
"github.com/stretchr/testify/assert"
"testing"
)
func TestSetupResponsePopulateNodebByPduFailure(t *testing.T) {
logger := tests.InitLog(t)
nodebInfo := &entities.NodebInfo{}
nodebIdentity := &entities.NbIdentity{}
converter:= converters.NewEndcSetupResponseConverter(logger)
handler := NewEndcSetupResponseManager(converter)
err := handler.PopulateNodebByPdu(logger, nodebIdentity, nodebInfo, createRandomPayload())
assert.NotNil(t, err)
}
func TestSetupResponsePopulateNodebByPduSuccess(t *testing.T) {
logger := tests.InitLog(t)
nodebInfo := &entities.NodebInfo{}
nodebIdentity := &entities.NbIdentity{}
converter:= converters.NewEndcSetupResponseConverter(logger)
handler := NewEndcSetupResponseManager(converter)
err := handler.PopulateNodebByPdu(logger, nodebIdentity, nodebInfo, createSetupResponsePayload(t))
assert.Nil(t, err)
assert.Equal(t, entities.ConnectionStatus_CONNECTED, nodebInfo.ConnectionStatus)
assert.Equal(t, entities.Node_GNB, nodebInfo.NodeType)
}
func createSetupResponsePayload(t *testing.T) []byte {
packedPdu := "202400808e00000100f600808640000200fc00090002f829504a952a0a00fd007200010c0005001e3f271f2e3d4ff03d44d34e4f003e4e5e4400010000150400000a000211e148033e4e5e4c0005001e3f271f2e3d4ff03d44d34e4f003e4e5e4400010000150400000a00021a0044033e4e5e000000002c001e3f271f2e3d4ff0031e3f274400010000150400000a00020000"
var payload []byte
_, err := fmt.Sscanf(packedPdu, "%x", &payload)
if err != nil {
t.Errorf("convert inputPayloadAsStr to payloadAsByte. Error: %v\n", err)
}
return payload
}

View File

@@ -0,0 +1,30 @@
//
// Copyright 2019 AT&T Intellectual Property
// Copyright 2019 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.
// This source code is part of the near-RT RIC (RAN Intelligent Controller)
// platform project (RICP).
package managers
import (
"e2mgr/logger"
"gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
)
type ISetupResponseManager interface {
PopulateNodebByPdu(logger *logger.Logger, nbIdentity *entities.NbIdentity, nodebInfo *entities.NodebInfo, payload []byte) error
}

View File

@@ -0,0 +1,87 @@
//
// Copyright 2019 AT&T Intellectual Property
// Copyright 2019 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.
//
// This source code is part of the near-RT RIC (RAN Intelligent Controller)
// platform project (RICP).
package managers
import (
"e2mgr/configuration"
"e2mgr/logger"
"k8s.io/client-go/kubernetes"
)
type KubernetesManager struct {
Logger *logger.Logger
ClientSet kubernetes.Interface
Config *configuration.Configuration
}
func NewKubernetesManager(logger *logger.Logger, config *configuration.Configuration) *KubernetesManager {
return &KubernetesManager{
Logger: logger,
//ClientSet: createClientSet(logger, config),
Config: config,
}
}
/*func createClientSet(logger *logger.Logger, config *configuration.Configuration) kubernetes.Interface {
absConfigPath,err := filepath.Abs(config.Kubernetes.ConfigPath)
if err != nil {
logger.Errorf("#KubernetesManager.init - error: %s", err)
return nil
}
kubernetesConfig, err := clientcmd.BuildConfigFromFlags("", absConfigPath)
if err != nil {
logger.Errorf("#KubernetesManager.init - error: %s", err)
return nil
}
clientSet, err := kubernetes.NewForConfig(kubernetesConfig)
if err != nil {
logger.Errorf("#KubernetesManager.init - error: %s", err)
return nil
}
return clientSet
}*/
/*func (km KubernetesManager) DeletePod(podName string) error {
km.Logger.Infof("#KubernetesManager.DeletePod - POD name: %s ", podName)
if km.ClientSet == nil {
km.Logger.Errorf("#KubernetesManager.DeletePod - no kubernetesManager connection")
return e2managererrors.NewInternalError()
}
if len(podName) == 0 {
km.Logger.Warnf("#KubernetesManager.DeletePod - empty pod name")
return e2managererrors.NewInternalError()
}
err := km.ClientSet.CoreV1().Pods(km.Config.Kubernetes.KubeNamespace).Delete(podName, &metaV1.DeleteOptions{})
if err != nil {
km.Logger.Errorf("#KubernetesManager.DeletePod - POD %s can't be deleted, error: %s", podName, err)
return err
}
km.Logger.Infof("#KubernetesManager.DeletePod - POD %s was deleted", podName)
return nil
}*/

View File

@@ -0,0 +1,152 @@
//
// Copyright 2019 AT&T Intellectual Property
// Copyright 2019 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.
//
// This source code is part of the near-RT RIC (RAN Intelligent Controller)
// platform project (RICP).
package managers
/*
import (
"e2mgr/configuration"
"e2mgr/logger"
"github.com/stretchr/testify/assert"
"k8s.io/api/core/v1"
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes/fake"
"testing"
)
type TestStruct struct {
description string
namespace string
expected []string
objs []runtime.Object
}
func initKubernetesManagerTest(t *testing.T) *KubernetesManager {
logger, err := logger.InitLogger(logger.DebugLevel)
if err != nil {
t.Errorf("#... - failed to initialize logger, error: %s", err)
}
config := &configuration.Configuration{}
config.Kubernetes.KubeNamespace = "oran"
config.Kubernetes.ConfigPath = "somePath"
kubernetesManager := NewKubernetesManager(logger, config)
return kubernetesManager
}
func TestDelete_NoPodName(t *testing.T) {
test := TestStruct{
description: "2 namespace, 2 pods in oran",
namespace: "oran",
objs: []runtime.Object{pod("oran", "POD_Test_1"), pod("oran", "POD_Test_2"), pod("some-namespace", "POD_Test_1")},
}
kubernetesManager := initKubernetesManagerTest(t)
t.Run(test.description, func(t *testing.T) {
kubernetesManager.ClientSet = fake.NewSimpleClientset(test.objs...)
err := kubernetesManager.DeletePod("")
assert.NotNil(t, err)
})
}
func TestDelete_NoPods(t *testing.T) {
test := TestStruct{
description: "no pods",
namespace: "oran",
expected: nil,
objs: nil,
}
kubernetesManager := initKubernetesManagerTest(t)
t.Run(test.description, func(t *testing.T) {
kubernetesManager.ClientSet = fake.NewSimpleClientset(test.objs...)
err := kubernetesManager.DeletePod("POD_Test")
assert.NotNil(t, err)
})
}
func TestDelete_PodExists(t *testing.T) {
test := TestStruct{
description: "2 namespace, 2 pods in oran",
namespace: "oran",
objs: []runtime.Object{pod("oran", "POD_Test_1"), pod("oran", "POD_Test_2"), pod("some-namespace", "POD_Test_1")},
}
kubernetesManager := initKubernetesManagerTest(t)
t.Run(test.description, func(t *testing.T) {
kubernetesManager.ClientSet = fake.NewSimpleClientset(test.objs...)
err := kubernetesManager.DeletePod("POD_Test_1")
assert.Nil(t, err)
})
}
func TestDelete_NoPodInNamespace(t *testing.T) {
test := TestStruct{
description: "2 namespace, 2 pods in oran",
namespace: "oran",
objs: []runtime.Object{pod("oran", "POD_Test_1"), pod("oran", "POD_Test_2"), pod("some-namespace", "POD_Test")},
}
kubernetesManager := initKubernetesManagerTest(t)
t.Run(test.description, func(t *testing.T) {
kubernetesManager.ClientSet = fake.NewSimpleClientset(test.objs...)
err := kubernetesManager.DeletePod("POD_Test")
assert.NotNil(t, err)
})
}
func TestDelete_NoNamespace(t *testing.T) {
test := TestStruct{
description: "No oran namespace",
namespace: "oran",
objs: []runtime.Object{pod("some-namespace", "POD_Test_1"), pod("some-namespace", "POD_Test_2"), pod("some-namespace", "POD_Test")},
}
kubernetesManager := initKubernetesManagerTest(t)
t.Run(test.description, func(t *testing.T) {
kubernetesManager.ClientSet = fake.NewSimpleClientset(test.objs...)
err := kubernetesManager.DeletePod("POD_Test")
assert.NotNil(t, err)
})
}
func pod(namespace, image string) *v1.Pod {
return &v1.Pod{
ObjectMeta: metaV1.ObjectMeta{
Name: image,
Namespace: namespace,
Annotations: map[string]string{},
},
}
}
*/

View File

@@ -0,0 +1,55 @@
//
// Copyright 2019 AT&T Intellectual Property
// Copyright 2019 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.
// This source code is part of the near-RT RIC (RAN Intelligent Controller)
// platform project (RICP).
package notificationmanager
import (
"e2mgr/logger"
"e2mgr/models"
"e2mgr/providers/rmrmsghandlerprovider"
"e2mgr/rmrCgo"
"time"
)
type NotificationManager struct {
logger *logger.Logger
notificationHandlerProvider *rmrmsghandlerprovider.NotificationHandlerProvider
}
func NewNotificationManager(logger *logger.Logger, notificationHandlerProvider *rmrmsghandlerprovider.NotificationHandlerProvider) *NotificationManager {
return &NotificationManager{
logger: logger,
notificationHandlerProvider: notificationHandlerProvider,
}
}
func (m NotificationManager) HandleMessage(mbuf *rmrCgo.MBuf) error {
notificationHandler, err := m.notificationHandlerProvider.GetNotificationHandler(mbuf.MType)
if err != nil {
m.logger.Errorf("#NotificationManager.HandleMessage - Error: %s", err)
return err
}
notificationRequest := models.NewNotificationRequest(mbuf.Meid, *mbuf.Payload, time.Now(), *mbuf.XAction, mbuf.GetMsgSrc())
go notificationHandler.Handle(notificationRequest)
return nil
}

View File

@@ -0,0 +1,92 @@
//
// Copyright 2019 AT&T Intellectual Property
// Copyright 2019 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.
// This source code is part of the near-RT RIC (RAN Intelligent Controller)
// platform project (RICP).
package notificationmanager
import (
"e2mgr/clients"
"e2mgr/configuration"
"e2mgr/logger"
"e2mgr/managers"
"e2mgr/mocks"
"e2mgr/providers/rmrmsghandlerprovider"
"e2mgr/rmrCgo"
"e2mgr/services"
"e2mgr/services/rmrsender"
"e2mgr/tests"
"fmt"
"gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
"github.com/stretchr/testify/assert"
"testing"
)
func initNotificationManagerTest(t *testing.T) (*logger.Logger, *mocks.RnibReaderMock, *NotificationManager) {
logger := initLog(t)
config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: 3}
readerMock := &mocks.RnibReaderMock{}
writerMock := &mocks.RnibWriterMock{}
httpClient := &mocks.HttpClientMock{}
rmrSender := initRmrSender(&mocks.RmrMessengerMock{}, logger)
rnibDataService := services.NewRnibDataService(logger, config, readerMock, writerMock)
ranSetupManager := managers.NewRanSetupManager(logger, rmrSender, rnibDataService)
e2tInstancesManager := managers.NewE2TInstancesManager(rnibDataService, logger)
routingManagerClient := clients.NewRoutingManagerClient(logger, config, httpClient)
e2tAssociationManager := managers.NewE2TAssociationManager(logger, rnibDataService, e2tInstancesManager, routingManagerClient)
rmrNotificationHandlerProvider := rmrmsghandlerprovider.NewNotificationHandlerProvider()
rmrNotificationHandlerProvider.Init(logger, config, rnibDataService, rmrSender, ranSetupManager, e2tInstancesManager,routingManagerClient, e2tAssociationManager)
notificationManager := NewNotificationManager(logger, rmrNotificationHandlerProvider )
return logger, readerMock, notificationManager
}
func TestHandleMessageUnexistingMessageType(t *testing.T) {
_, _, nm := initNotificationManagerTest(t)
mbuf := &rmrCgo.MBuf{MType: 1234}
err := nm.HandleMessage(mbuf)
assert.NotNil(t, err)
}
func TestHandleMessageExistingMessageType(t *testing.T) {
_, readerMock, nm := initNotificationManagerTest(t)
payload := []byte("123")
xaction := []byte("test")
mbuf := &rmrCgo.MBuf{MType: rmrCgo.RIC_X2_SETUP_RESP, Meid: "test", Payload: &payload, XAction: &xaction}
readerMock.On("GetNodeb", "test").Return(&entities.NodebInfo{}, fmt.Errorf("Some error"))
err := nm.HandleMessage(mbuf)
assert.Nil(t, err)
}
// TODO: extract to test_utils
func initRmrSender(rmrMessengerMock *mocks.RmrMessengerMock, log *logger.Logger) *rmrsender.RmrSender {
rmrMessenger := rmrCgo.RmrMessenger(rmrMessengerMock)
rmrMessengerMock.On("Init", tests.GetPort(), tests.MaxMsgSize, tests.Flags, log).Return(&rmrMessenger)
return rmrsender.NewRmrSender(log, rmrMessenger)
}
// TODO: extract to test_utils
func initLog(t *testing.T) *logger.Logger {
log, err := logger.InitLogger(logger.InfoLevel)
if err != nil {
t.Errorf("#delete_all_request_handler_test.TestHandleSuccessFlow - failed to initialize logger, error: %s", err)
}
return log
}

View File

@@ -0,0 +1,93 @@
//
// Copyright 2019 AT&T Intellectual Property
// Copyright 2019 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.
// This source code is part of the near-RT RIC (RAN Intelligent Controller)
// platform project (RICP).
package managers
import (
"e2mgr/configuration"
"e2mgr/logger"
"e2mgr/services"
"gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
)
type IRanDisconnectionManager interface {
DisconnectRan(inventoryName string) error
}
type RanDisconnectionManager struct {
logger *logger.Logger
config *configuration.Configuration
rnibDataService services.RNibDataService
ranSetupManager *RanSetupManager
e2tAssociationManager *E2TAssociationManager
}
func NewRanDisconnectionManager(logger *logger.Logger, config *configuration.Configuration, rnibDataService services.RNibDataService, e2tAssociationManager *E2TAssociationManager) *RanDisconnectionManager {
return &RanDisconnectionManager{
logger: logger,
config: config,
rnibDataService: rnibDataService,
e2tAssociationManager: e2tAssociationManager,
}
}
func (m *RanDisconnectionManager) DisconnectRan(inventoryName string) error {
nodebInfo, err := m.rnibDataService.GetNodeb(inventoryName)
if err != nil {
m.logger.Errorf("#RanDisconnectionManager.DisconnectRan - RAN name: %s - Failed fetching RAN from rNib. Error: %v", inventoryName, err)
return err
}
connectionStatus := nodebInfo.GetConnectionStatus()
m.logger.Infof("#RanDisconnectionManager.DisconnectRan - RAN name: %s - RAN's connection status: %s", nodebInfo.RanName, connectionStatus)
if connectionStatus == entities.ConnectionStatus_SHUT_DOWN {
m.logger.Warnf("#RanDisconnectionManager.DisconnectRan - RAN name: %s - quit. RAN's connection status is SHUT_DOWN", nodebInfo.RanName)
return nil
}
if connectionStatus == entities.ConnectionStatus_SHUTTING_DOWN {
return m.updateNodebInfo(nodebInfo, entities.ConnectionStatus_SHUT_DOWN)
}
err = m.updateNodebInfo(nodebInfo, entities.ConnectionStatus_DISCONNECTED)
if err != nil {
return err
}
e2tAddress := nodebInfo.AssociatedE2TInstanceAddress
return m.e2tAssociationManager.DissociateRan(e2tAddress, nodebInfo.RanName)
}
func (m *RanDisconnectionManager) updateNodebInfo(nodebInfo *entities.NodebInfo, connectionStatus entities.ConnectionStatus) error {
nodebInfo.ConnectionStatus = connectionStatus;
err := m.rnibDataService.UpdateNodebInfo(nodebInfo)
if err != nil {
m.logger.Errorf("#RanDisconnectionManager.updateNodebInfo - RAN name: %s - Failed updating RAN's connection status to %s in rNib. Error: %v", nodebInfo.RanName, connectionStatus, err)
return err
}
m.logger.Infof("#RanDisconnectionManager.updateNodebInfo - RAN name: %s - Successfully updated rNib. RAN's current connection status: %s", nodebInfo.RanName, nodebInfo.ConnectionStatus)
return nil
}

View File

@@ -0,0 +1,204 @@
//
// Copyright 2019 AT&T Intellectual Property
// Copyright 2019 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.
// This source code is part of the near-RT RIC (RAN Intelligent Controller)
// platform project (RICP).
package managers
import (
"e2mgr/clients"
"e2mgr/configuration"
"e2mgr/logger"
"e2mgr/mocks"
"e2mgr/rmrCgo"
"e2mgr/services"
"e2mgr/services/rmrsender"
"e2mgr/tests"
"gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common"
"gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"testing"
)
const ranName = "test"
const e2tAddress = "10.10.2.15:9800"
func initRanLostConnectionTest(t *testing.T) (*logger.Logger, *mocks.RmrMessengerMock, *mocks.RnibReaderMock, *mocks.RnibWriterMock, *RanDisconnectionManager, *mocks.HttpClientMock) {
logger, err := logger.InitLogger(logger.DebugLevel)
if err != nil {
t.Errorf("#... - failed to initialize logger, error: %s", err)
}
config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: 3}
rmrMessengerMock := &mocks.RmrMessengerMock{}
readerMock := &mocks.RnibReaderMock{}
writerMock := &mocks.RnibWriterMock{}
rnibDataService := services.NewRnibDataService(logger, config, readerMock, writerMock)
e2tInstancesManager := NewE2TInstancesManager(rnibDataService, logger)
httpClient := &mocks.HttpClientMock{}
routingManagerClient := clients.NewRoutingManagerClient(logger, config, httpClient)
e2tAssociationManager := NewE2TAssociationManager(logger, rnibDataService, e2tInstancesManager, routingManagerClient)
ranDisconnectionManager := NewRanDisconnectionManager(logger, configuration.ParseConfiguration(), rnibDataService, e2tAssociationManager)
return logger, rmrMessengerMock, readerMock, writerMock, ranDisconnectionManager, httpClient
}
func TestRanDisconnectionGetNodebFailure(t *testing.T) {
_, _, readerMock, writerMock, ranDisconnectionManager, _ := initRanLostConnectionTest(t)
var nodebInfo *entities.NodebInfo
readerMock.On("GetNodeb", ranName).Return(nodebInfo, common.NewInternalError(errors.New("Error")))
err := ranDisconnectionManager.DisconnectRan(ranName)
assert.NotNil(t, err)
readerMock.AssertCalled(t, "GetNodeb", ranName)
writerMock.AssertNotCalled(t, "UpdateNodebInfo")
}
func TestShutdownRan(t *testing.T) {
_, _, readerMock, writerMock, ranDisconnectionManager, _ := initRanLostConnectionTest(t)
origNodebInfo := &entities.NodebInfo{RanName: ranName, GlobalNbId: &entities.GlobalNbId{PlmnId: "xxx", NbId: "yyy"}, ConnectionStatus: entities.ConnectionStatus_SHUT_DOWN}
var rnibErr error
readerMock.On("GetNodeb", ranName).Return(origNodebInfo, rnibErr)
err := ranDisconnectionManager.DisconnectRan(ranName)
assert.Nil(t, err)
readerMock.AssertCalled(t, "GetNodeb", ranName)
writerMock.AssertNotCalled(t, "UpdateNodebInfo")
}
func TestShuttingdownRan(t *testing.T) {
_, _, readerMock, writerMock, ranDisconnectionManager, _ := initRanLostConnectionTest(t)
origNodebInfo := &entities.NodebInfo{RanName: ranName, GlobalNbId: &entities.GlobalNbId{PlmnId: "xxx", NbId: "yyy"}, ConnectionStatus: entities.ConnectionStatus_SHUTTING_DOWN}
var rnibErr error
readerMock.On("GetNodeb", ranName).Return(origNodebInfo, rnibErr)
updatedNodebInfo := *origNodebInfo
updatedNodebInfo.ConnectionStatus = entities.ConnectionStatus_SHUT_DOWN
writerMock.On("UpdateNodebInfo", &updatedNodebInfo).Return(rnibErr)
err := ranDisconnectionManager.DisconnectRan(ranName)
assert.Nil(t, err)
readerMock.AssertCalled(t, "GetNodeb", ranName)
writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 1)
}
func TestShuttingDownRanUpdateNodebInfoFailure(t *testing.T) {
_, _, readerMock, writerMock, ranDisconnectionManager, _ := initRanLostConnectionTest(t)
origNodebInfo := &entities.NodebInfo{RanName: ranName, GlobalNbId: &entities.GlobalNbId{PlmnId: "xxx", NbId: "yyy"}, ConnectionStatus: entities.ConnectionStatus_SHUTTING_DOWN}
var rnibErr error
readerMock.On("GetNodeb", ranName).Return(origNodebInfo, rnibErr)
updatedNodebInfo := *origNodebInfo
updatedNodebInfo.ConnectionStatus = entities.ConnectionStatus_SHUT_DOWN
writerMock.On("UpdateNodebInfo", &updatedNodebInfo).Return(common.NewInternalError(errors.New("Error")))
err := ranDisconnectionManager.DisconnectRan(ranName)
assert.NotNil(t, err)
readerMock.AssertCalled(t, "GetNodeb", ranName)
writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 1)
}
func TestConnectingRanUpdateNodebInfoFailure(t *testing.T) {
_, _, readerMock, writerMock, ranDisconnectionManager, _ := initRanLostConnectionTest(t)
origNodebInfo := &entities.NodebInfo{RanName: ranName, GlobalNbId: &entities.GlobalNbId{PlmnId: "xxx", NbId: "yyy"}, ConnectionStatus: entities.ConnectionStatus_CONNECTING}
var rnibErr error
readerMock.On("GetNodeb", ranName).Return(origNodebInfo, rnibErr)
updatedNodebInfo := *origNodebInfo
updatedNodebInfo.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED
writerMock.On("UpdateNodebInfo", &updatedNodebInfo).Return(common.NewInternalError(errors.New("Error")))
err := ranDisconnectionManager.DisconnectRan(ranName)
assert.NotNil(t, err)
readerMock.AssertCalled(t, "GetNodeb", ranName)
writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 1)
}
func TestConnectingRanDisconnectSucceeds(t *testing.T) {
_, _, readerMock, writerMock, ranDisconnectionManager, httpClient := initRanLostConnectionTest(t)
origNodebInfo := &entities.NodebInfo{RanName: ranName, GlobalNbId: &entities.GlobalNbId{PlmnId: "xxx", NbId: "yyy"}, ConnectionStatus: entities.ConnectionStatus_CONNECTING, AssociatedE2TInstanceAddress: E2TAddress}
var rnibErr error
readerMock.On("GetNodeb", ranName).Return(origNodebInfo, rnibErr)
updatedNodebInfo1 := *origNodebInfo
updatedNodebInfo1.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED
writerMock.On("UpdateNodebInfo", &updatedNodebInfo1).Return(rnibErr)
updatedNodebInfo2 := *origNodebInfo
updatedNodebInfo2.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED
updatedNodebInfo2.AssociatedE2TInstanceAddress = ""
writerMock.On("UpdateNodebInfo", &updatedNodebInfo2).Return(rnibErr)
e2tInstance := &entities.E2TInstance{Address: E2TAddress, AssociatedRanList: []string{ranName}}
readerMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance, nil)
e2tInstanceToSave := * e2tInstance
e2tInstanceToSave.AssociatedRanList = []string{}
writerMock.On("SaveE2TInstance", &e2tInstanceToSave).Return(nil)
mockHttpClient(httpClient, clients.DissociateRanE2TInstanceApiSuffix, true)
err := ranDisconnectionManager.DisconnectRan(ranName)
assert.Nil(t, err)
readerMock.AssertCalled(t, "GetNodeb", ranName)
writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 2)
}
func TestConnectingRanDissociateFailsRmError(t *testing.T) {
_, _, readerMock, writerMock, ranDisconnectionManager, httpClient := initRanLostConnectionTest(t)
origNodebInfo := &entities.NodebInfo{RanName: ranName, GlobalNbId: &entities.GlobalNbId{PlmnId: "xxx", NbId: "yyy"}, ConnectionStatus: entities.ConnectionStatus_CONNECTING, AssociatedE2TInstanceAddress: E2TAddress}
var rnibErr error
readerMock.On("GetNodeb", ranName).Return(origNodebInfo, rnibErr)
updatedNodebInfo1 := *origNodebInfo
updatedNodebInfo1.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED
writerMock.On("UpdateNodebInfo", &updatedNodebInfo1).Return(rnibErr)
updatedNodebInfo2 := *origNodebInfo
updatedNodebInfo2.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED
updatedNodebInfo2.AssociatedE2TInstanceAddress = ""
writerMock.On("UpdateNodebInfo", &updatedNodebInfo2).Return(rnibErr)
e2tInstance := &entities.E2TInstance{Address: E2TAddress, AssociatedRanList: []string{ranName}}
readerMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance, nil)
e2tInstanceToSave := * e2tInstance
e2tInstanceToSave.AssociatedRanList = []string{}
writerMock.On("SaveE2TInstance", &e2tInstanceToSave).Return(nil)
mockHttpClient(httpClient, clients.DissociateRanE2TInstanceApiSuffix, false)
err := ranDisconnectionManager.DisconnectRan(ranName)
assert.Nil(t, err)
readerMock.AssertCalled(t, "GetNodeb", ranName)
writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 2)
}
func TestConnectingRanDissociateFailsDbError(t *testing.T) {
_, _, readerMock, writerMock, ranDisconnectionManager, _ := initRanLostConnectionTest(t)
origNodebInfo := &entities.NodebInfo{RanName: ranName, GlobalNbId: &entities.GlobalNbId{PlmnId: "xxx", NbId: "yyy"}, ConnectionStatus: entities.ConnectionStatus_CONNECTING, AssociatedE2TInstanceAddress: e2tAddress}
var rnibErr error
readerMock.On("GetNodeb", ranName).Return(origNodebInfo, rnibErr)
updatedNodebInfo1 := *origNodebInfo
updatedNodebInfo1.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED
writerMock.On("UpdateNodebInfo", &updatedNodebInfo1).Return(rnibErr)
updatedNodebInfo2 := *origNodebInfo
updatedNodebInfo2.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED
updatedNodebInfo2.AssociatedE2TInstanceAddress = ""
writerMock.On("UpdateNodebInfo", &updatedNodebInfo2).Return(rnibErr)
e2tInstance := &entities.E2TInstance{Address: e2tAddress, AssociatedRanList: []string{ranName}}
readerMock.On("GetE2TInstance", e2tAddress).Return(e2tInstance, common.NewInternalError(errors.New("Error")))
err := ranDisconnectionManager.DisconnectRan(ranName)
assert.NotNil(t, err)
readerMock.AssertCalled(t, "GetNodeb", ranName)
writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 2)
writerMock.AssertNotCalled(t, "SaveE2TInstance", )
}
func initRmrSender(rmrMessengerMock *mocks.RmrMessengerMock, log *logger.Logger) *rmrsender.RmrSender {
rmrMessenger := rmrCgo.RmrMessenger(rmrMessengerMock)
rmrMessengerMock.On("Init", tests.GetPort(), tests.MaxMsgSize, tests.Flags, log).Return(&rmrMessenger)
return rmrsender.NewRmrSender(log, rmrMessenger)
}

View File

@@ -0,0 +1,131 @@
//
// Copyright 2019 AT&T Intellectual Property
// Copyright 2019 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.
// This source code is part of the near-RT RIC (RAN Intelligent Controller)
// platform project (RICP).
package managers
import (
"e2mgr/e2managererrors"
"e2mgr/e2pdus"
"e2mgr/logger"
"e2mgr/models"
"e2mgr/rmrCgo"
"e2mgr/services"
"e2mgr/services/rmrsender"
"gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
"unsafe"
)
type RanSetupManager struct {
logger *logger.Logger
rnibDataService services.RNibDataService
rmrSender *rmrsender.RmrSender
}
type IRanSetupManager interface {
ExecuteSetup(nodebInfo *entities.NodebInfo, status entities.ConnectionStatus) error
}
func NewRanSetupManager(logger *logger.Logger, rmrSender *rmrsender.RmrSender, rnibDataService services.RNibDataService) *RanSetupManager {
return &RanSetupManager{
logger: logger,
rnibDataService: rnibDataService,
rmrSender: rmrSender,
}
}
// Update retries and connection status
func (m *RanSetupManager) updateConnectionStatus(nodebInfo *entities.NodebInfo, status entities.ConnectionStatus) error {
// Update retries and connection status
nodebInfo.ConnectionStatus = status
err := m.rnibDataService.UpdateNodebInfo(nodebInfo)
if err != nil {
m.logger.Errorf("#RanSetupManager.updateConnectionStatus - Ran name: %s - Failed updating RAN's connection status to %v : %s", nodebInfo.RanName, status, err)
} else {
m.logger.Infof("#RanSetupManager.updateConnectionStatus - Ran name: %s - Successfully updated rNib. RAN's current connection status: %v", nodebInfo.RanName, status)
}
return err
}
// Decrement retries and connection status (disconnected)
func (m *RanSetupManager) updateConnectionStatusDisconnected(nodebInfo *entities.NodebInfo) error {
// Update retries and connection status
nodebInfo.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED
err := m.rnibDataService.UpdateNodebInfo(nodebInfo)
if err != nil {
m.logger.Errorf("#RanSetupManager.updateConnectionStatusDisconnected - Ran name: %s - Failed updating RAN's connection status to DISCONNECTED : %s", nodebInfo.RanName, err)
} else {
m.logger.Infof("#RanSetupManager.updateConnectionStatusDisconnected - Ran name: %s - Successfully updated rNib. RAN's current connection status: DISCONNECTED", nodebInfo.RanName)
}
return err
}
func (m *RanSetupManager) prepareSetupRequest(nodebInfo *entities.NodebInfo) (int, *models.E2RequestMessage, error) {
// Build the endc/x2 setup request
switch nodebInfo.E2ApplicationProtocol {
case entities.E2ApplicationProtocol_X2_SETUP_REQUEST:
rmrMsgType := rmrCgo.RIC_X2_SETUP_REQ
request := models.NewE2RequestMessage(nodebInfo.RanName /*tid*/, nodebInfo.Ip, uint16(nodebInfo.Port), nodebInfo.RanName, e2pdus.PackedX2setupRequest)
return rmrMsgType, request, nil
case entities.E2ApplicationProtocol_ENDC_X2_SETUP_REQUEST:
rmrMsgType := rmrCgo.RIC_ENDC_X2_SETUP_REQ
request := models.NewE2RequestMessage(nodebInfo.RanName /*tid*/, nodebInfo.Ip, uint16(nodebInfo.Port), nodebInfo.RanName, e2pdus.PackedEndcX2setupRequest)
return rmrMsgType, request, nil
}
m.logger.Errorf("#RanSetupManager.prepareSetupRequest - Unsupported nodebInfo.E2ApplicationProtocol %d ", nodebInfo.E2ApplicationProtocol)
return 0, nil, e2managererrors.NewInternalError()
}
// ExecuteSetup updates the connection status and number of attempts in the nodebInfo and send an endc/x2 setup request to establish a connection with the RAN
func (m *RanSetupManager) ExecuteSetup(nodebInfo *entities.NodebInfo, status entities.ConnectionStatus) error {
// Update retries and connection status
if err := m.updateConnectionStatus(nodebInfo, status); err != nil {
return e2managererrors.NewRnibDbError()
}
// Build the endc/x2 setup request
rmrMsgType, request, err := m.prepareSetupRequest(nodebInfo)
if err != nil {
return err
}
// Send the endc/x2 setup request
var xAction []byte
var msgSrc unsafe.Pointer
msg := models.NewRmrMessage(rmrMsgType, nodebInfo.RanName, request.GetMessageAsBytes(m.logger), xAction, msgSrc)
err = m.rmrSender.Send(msg)
if err != nil {
m.logger.Errorf("#RanSetupManager.ExecuteSetup - failed sending setup request to RMR: %s", err)
err := m.updateConnectionStatusDisconnected(nodebInfo)
// Decrement retries and connection status (disconnected)
if err != nil {
return e2managererrors.NewRnibDbError()
}
return e2managererrors.NewRmrError()
}
return nil
}

View File

@@ -0,0 +1,219 @@
//
// Copyright 2019 AT&T Intellectual Property
// Copyright 2019 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.
// This source code is part of the near-RT RIC (RAN Intelligent Controller)
// platform project (RICP).
package managers
import (
"e2mgr/configuration"
"e2mgr/e2managererrors"
"e2mgr/e2pdus"
"e2mgr/logger"
"e2mgr/mocks"
"e2mgr/rmrCgo"
"e2mgr/services"
"fmt"
"gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common"
"gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"testing"
"unsafe"
)
func initRanSetupManagerTest(t *testing.T) (*mocks.RmrMessengerMock, *mocks.RnibWriterMock, *RanSetupManager) {
logger, err := logger.InitLogger(logger.DebugLevel)
if err != nil {
t.Errorf("#... - failed to initialize logger, error: %s", err)
}
config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: 3}
rmrMessengerMock := &mocks.RmrMessengerMock{}
rmrSender := initRmrSender(rmrMessengerMock, logger)
readerMock := &mocks.RnibReaderMock{}
writerMock := &mocks.RnibWriterMock{}
rnibDataService := services.NewRnibDataService(logger, config, readerMock, writerMock)
ranSetupManager := NewRanSetupManager(logger, rmrSender, rnibDataService)
return rmrMessengerMock, writerMock, ranSetupManager
}
func TestExecuteSetupConnectingX2Setup(t *testing.T) {
rmrMessengerMock, writerMock, mgr := initRanSetupManagerTest(t)
ranName := "test1"
var initialNodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTED, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST}
var argNodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTING, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST}
var rnibErr error
writerMock.On("UpdateNodebInfo", argNodeb).Return(rnibErr)
payload := e2pdus.PackedX2setupRequest
xAction := []byte(ranName)
var msgSrc unsafe.Pointer
msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_SETUP_REQ, len(payload), ranName, &payload, &xAction, msgSrc)
rmrMessengerMock.On("SendMsg", mock.Anything, true).Return(msg, nil)
if err := mgr.ExecuteSetup(initialNodeb, entities.ConnectionStatus_CONNECTING); err != nil {
t.Errorf("want: success, got: error: %s", err)
}
writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 1)
rmrMessengerMock.AssertNumberOfCalls(t, "SendMsg", 1)
}
func TestExecuteSetupConnectingEndcX2Setup(t *testing.T) {
rmrMessengerMock, writerMock, mgr := initRanSetupManagerTest(t)
ranName := "test1"
var initialNodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTED, E2ApplicationProtocol: entities.E2ApplicationProtocol_ENDC_X2_SETUP_REQUEST}
var argNodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTING, E2ApplicationProtocol: entities.E2ApplicationProtocol_ENDC_X2_SETUP_REQUEST}
var rnibErr error
writerMock.On("UpdateNodebInfo", argNodeb).Return(rnibErr)
payload := e2pdus.PackedEndcX2setupRequest
xAction := []byte(ranName)
var msgSrc unsafe.Pointer
msg := rmrCgo.NewMBuf(rmrCgo.RIC_ENDC_X2_SETUP_REQ, len(payload), ranName, &payload, &xAction, msgSrc)
rmrMessengerMock.On("SendMsg", mock.Anything, true).Return(msg, nil)
if err := mgr.ExecuteSetup(initialNodeb, entities.ConnectionStatus_CONNECTING); err != nil {
t.Errorf("want: success, got: error: %s", err)
}
writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 1)
rmrMessengerMock.AssertNumberOfCalls(t, "SendMsg", 1)
}
func TestExecuteSetupDisconnected(t *testing.T) {
rmrMessengerMock, writerMock, mgr := initRanSetupManagerTest(t)
ranName := "test1"
var initialNodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTED, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST}
var argNodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTING, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST}
var argNodebDisconnected = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_DISCONNECTED, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST}
var rnibErr error
writerMock.On("UpdateNodebInfo", argNodeb).Return(rnibErr)
writerMock.On("UpdateNodebInfo", argNodebDisconnected).Return(rnibErr)
payload := []byte{0}
xAction := []byte(ranName)
var msgSrc unsafe.Pointer
msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_SETUP_REQ, len(payload), ranName, &payload, &xAction, msgSrc)
rmrMessengerMock.On("SendMsg", mock.Anything, true).Return(msg, fmt.Errorf("send failure"))
if err := mgr.ExecuteSetup(initialNodeb, entities.ConnectionStatus_CONNECTING); err == nil {
t.Errorf("want: failure, got: success")
}
writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 2)
rmrMessengerMock.AssertNumberOfCalls(t, "SendMsg", 1)
}
func TestExecuteSetupConnectingRnibError(t *testing.T) {
rmrMessengerMock, writerMock, mgr := initRanSetupManagerTest(t)
ranName := "test1"
var initialNodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTED, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST}
var argNodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTING, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST}
var argNodebDisconnected = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_DISCONNECTED, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST}
var rnibErr = common.NewInternalError(fmt.Errorf("DB error"))
writerMock.On("UpdateNodebInfo", argNodeb).Return(rnibErr)
writerMock.On("UpdateNodebInfo", argNodebDisconnected).Return(rnibErr)
payload := []byte{0}
xAction := []byte(ranName)
var msgSrc unsafe.Pointer
msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_SETUP_REQ, len(payload), ranName, &payload, &xAction, msgSrc)
rmrMessengerMock.On("SendMsg", mock.Anything, true).Return(msg, fmt.Errorf("send failure"))
if err := mgr.ExecuteSetup(initialNodeb, entities.ConnectionStatus_CONNECTING); err == nil {
t.Errorf("want: failure, got: success")
} else {
assert.IsType(t, e2managererrors.NewRnibDbError(), err)
}
writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 1)
rmrMessengerMock.AssertNumberOfCalls(t, "SendMsg", 0)
}
func TestExecuteSetupDisconnectedRnibError(t *testing.T) {
rmrMessengerMock, writerMock, mgr := initRanSetupManagerTest(t)
ranName := "test1"
var initialNodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTED, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST}
var argNodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTING, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST}
var argNodebDisconnected = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_DISCONNECTED, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST}
var rnibErr error
writerMock.On("UpdateNodebInfo", argNodeb).Return(rnibErr)
writerMock.On("UpdateNodebInfo", argNodebDisconnected).Return(common.NewInternalError(fmt.Errorf("DB error")))
payload := []byte{0}
xAction := []byte(ranName)
var msgSrc unsafe.Pointer
msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_SETUP_REQ, len(payload), ranName, &payload, &xAction, msgSrc)
rmrMessengerMock.On("SendMsg", mock.Anything, true).Return(msg, fmt.Errorf("send failure"))
if err := mgr.ExecuteSetup(initialNodeb, entities.ConnectionStatus_CONNECTING); err == nil {
t.Errorf("want: failure, got: success")
} else {
assert.IsType(t, e2managererrors.NewRnibDbError(), err)
}
writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 2)
rmrMessengerMock.AssertNumberOfCalls(t, "SendMsg", 1)
}
func TestExecuteSetupUnsupportedProtocol(t *testing.T) {
rmrMessengerMock, writerMock, mgr := initRanSetupManagerTest(t)
ranName := "test1"
var initialNodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTED, E2ApplicationProtocol: entities.E2ApplicationProtocol_UNKNOWN_E2_APPLICATION_PROTOCOL}
var argNodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTING, E2ApplicationProtocol: entities.E2ApplicationProtocol_UNKNOWN_E2_APPLICATION_PROTOCOL}
var rnibErr error
writerMock.On("UpdateNodebInfo", argNodeb).Return(rnibErr)
payload := e2pdus.PackedX2setupRequest
xAction := []byte(ranName)
var msgSrc unsafe.Pointer
msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_SETUP_REQ, len(payload), ranName, &payload, &xAction, msgSrc)
rmrMessengerMock.On("SendMsg", mock.Anything, true).Return(msg, nil)
if err := mgr.ExecuteSetup(initialNodeb, entities.ConnectionStatus_CONNECTING); err == nil {
t.Errorf("want: error, got: success")
}
writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 1)
rmrMessengerMock.AssertNumberOfCalls(t, "SendMsg", 0)
}
func initLog(t *testing.T) *logger.Logger {
log, err := logger.InitLogger(logger.InfoLevel)
if err != nil {
t.Errorf("#initLog test - failed to initialize logger, error: %s", err)
}
return log
}

View File

@@ -0,0 +1,62 @@
//
// Copyright 2019 AT&T Intellectual Property
// Copyright 2019 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.
// This source code is part of the near-RT RIC (RAN Intelligent Controller)
// platform project (RICP).
package managers
import (
"e2mgr/enums"
"e2mgr/logger"
"e2mgr/models"
"e2mgr/services/rmrsender"
"encoding/json"
"gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
"unsafe"
)
type RanStatusChangeManager struct {
logger *logger.Logger
rmrSender *rmrsender.RmrSender
}
func NewRanStatusChangeManager(logger *logger.Logger, rmrSender *rmrsender.RmrSender) *RanStatusChangeManager {
return &RanStatusChangeManager{
logger: logger,
rmrSender: rmrSender,
}
}
type IRanStatusChangeManager interface {
Execute(msgType int, msgDirection enums.MessageDirection, nodebInfo *entities.NodebInfo) error
}
func (m *RanStatusChangeManager) Execute(msgType int, msgDirection enums.MessageDirection, nodebInfo *entities.NodebInfo) error {
resourceStatusPayload := models.NewResourceStatusPayload(nodebInfo.NodeType, msgDirection)
resourceStatusJson, err := json.Marshal(resourceStatusPayload)
if err != nil {
m.logger.Errorf("#RanStatusChangeManager.Execute - RAN name: %s - Error marshaling resource status payload: %v", nodebInfo.RanName, err)
return err
}
var xAction []byte
var msgSrc unsafe.Pointer
rmrMessage := models.NewRmrMessage(msgType, nodebInfo.RanName, resourceStatusJson, xAction, msgSrc)
return m.rmrSender.Send(rmrMessage)
}

View File

@@ -0,0 +1,66 @@
//
// Copyright 2019 AT&T Intellectual Property
// Copyright 2019 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.
// This source code is part of the near-RT RIC (RAN Intelligent Controller)
// platform project (RICP).
package managers
import (
"e2mgr/enums"
"e2mgr/logger"
"e2mgr/mocks"
"e2mgr/rmrCgo"
"e2mgr/services/rmrsender"
"gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"testing"
)
func initRanStatusChangeManagerTest(t *testing.T) (*logger.Logger, *mocks.RmrMessengerMock, *rmrsender.RmrSender) {
logger, err := logger.InitLogger(logger.DebugLevel)
if err != nil {
t.Fatalf("#initStatusChangeManagerTest - failed to initialize logger, error: %s", err)
}
rmrMessengerMock := &mocks.RmrMessengerMock{}
rmrSender := initRmrSender(rmrMessengerMock, logger)
return logger, rmrMessengerMock, rmrSender
}
func TestMarshalFailure(t *testing.T) {
logger, _, rmrSender := initRanStatusChangeManagerTest(t)
m := NewRanStatusChangeManager(logger, rmrSender)
nodebInfo := entities.NodebInfo{}
err := m.Execute(123, 4, &nodebInfo)
assert.NotNil(t, err)
}
func TestMarshalSuccess(t *testing.T) {
logger, rmrMessengerMock, rmrSender := initRanStatusChangeManagerTest(t)
m := NewRanStatusChangeManager(logger, rmrSender)
nodebInfo := entities.NodebInfo{NodeType: entities.Node_ENB}
var err error
rmrMessengerMock.On("SendMsg", mock.Anything, true).Return(&rmrCgo.MBuf{}, err)
err = m.Execute(rmrCgo.RAN_CONNECTED, enums.RIC_TO_RAN, &nodebInfo)
assert.Nil(t, err)
}

View File

@@ -0,0 +1,54 @@
//
// Copyright 2019 AT&T Intellectual Property
// Copyright 2019 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.
// This source code is part of the near-RT RIC (RAN Intelligent Controller)
// platform project (RICP).
package managers
import (
"e2mgr/converters"
"e2mgr/logger"
"gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
)
type X2SetupFailureResponseManager struct {
converter converters.IX2SetupFailureResponseConverter
}
func NewX2SetupFailureResponseManager(converter converters.IX2SetupFailureResponseConverter) *X2SetupFailureResponseManager {
return &X2SetupFailureResponseManager{
converter: converter,
}
}
func (m *X2SetupFailureResponseManager) PopulateNodebByPdu(logger *logger.Logger, nbIdentity *entities.NbIdentity, nodebInfo *entities.NodebInfo, payload []byte) error {
failureResponse, err := m.converter.UnpackX2SetupFailureResponseAndExtract(payload)
if err != nil {
logger.Errorf("#X2SetupFailureResponseManager.PopulateNodebByPdu - RAN name: %s - Unpack and extract failed. Error: %v", nodebInfo.RanName, err)
return err
}
logger.Infof("#X2SetupFailureResponseManager.PopulateNodebByPdu - RAN name: %s - Unpacked payload and extracted protobuf successfully", nodebInfo.RanName)
nodebInfo.ConnectionStatus = entities.ConnectionStatus_CONNECTED_SETUP_FAILED
nodebInfo.SetupFailure = failureResponse
nodebInfo.FailureType = entities.Failure_X2_SETUP_FAILURE
return nil
}

View File

@@ -0,0 +1,61 @@
//
// Copyright 2019 AT&T Intellectual Property
// Copyright 2019 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.
//
// This source code is part of the near-RT RIC (RAN Intelligent Controller)
// platform project (RICP).
package managers
import (
"e2mgr/converters"
"e2mgr/tests"
"fmt"
"gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
"github.com/stretchr/testify/assert"
"testing"
)
func TestPopulateX2NodebByPduFailure(t *testing.T) {
logger := tests.InitLog(t)
nodebInfo := &entities.NodebInfo{}
nodebIdentity := &entities.NbIdentity{}
handler := NewX2SetupFailureResponseManager(converters.NewX2SetupFailureResponseConverter(logger))
err := handler.PopulateNodebByPdu(logger, nodebIdentity, nodebInfo, createRandomPayload())
assert.NotNil(t, err)
}
func TestPopulateX2NodebByPduSuccess(t *testing.T) {
logger := tests.InitLog(t)
nodebInfo := &entities.NodebInfo{}
nodebIdentity := &entities.NbIdentity{}
handler := NewX2SetupFailureResponseManager(converters.NewX2SetupFailureResponseConverter(logger))
err := handler.PopulateNodebByPdu(logger, nodebIdentity, nodebInfo, createX2SetupFailureResponsePayload(t))
assert.Nil(t, err)
assert.Equal(t, entities.ConnectionStatus_CONNECTED_SETUP_FAILED, nodebInfo.ConnectionStatus)
assert.Equal(t, entities.Failure_X2_SETUP_FAILURE, nodebInfo.FailureType)
}
func createX2SetupFailureResponsePayload(t *testing.T) []byte {
packedPdu := "4006001a0000030005400200000016400100001140087821a00000008040"
var payload []byte
_, err := fmt.Sscanf(packedPdu, "%x", &payload)
if err != nil {
t.Errorf("convert inputPayloadAsStr to payloadAsByte. Error: %v\n", err)
}
return payload
}

View File

@@ -0,0 +1,57 @@
//
// Copyright 2019 AT&T Intellectual Property
// Copyright 2019 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.
// This source code is part of the near-RT RIC (RAN Intelligent Controller)
// platform project (RICP).
package managers
import (
"e2mgr/converters"
"e2mgr/logger"
"gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities"
)
type X2SetupResponseManager struct {
converter converters.IX2SetupResponseConverter
}
func NewX2SetupResponseManager(converter converters.IX2SetupResponseConverter) *X2SetupResponseManager {
return &X2SetupResponseManager{
converter: converter,
}
}
func (m *X2SetupResponseManager) PopulateNodebByPdu(logger *logger.Logger, nbIdentity *entities.NbIdentity, nodebInfo *entities.NodebInfo, payload []byte) error {
enbId, enb, err := m.converter.UnpackX2SetupResponseAndExtract(payload)
if err != nil {
logger.Errorf("#X2SetupResponseManager.PopulateNodebByPdu - RAN name: %s - Unpack and extract failed. %v", nodebInfo.RanName, err)
return err
}
logger.Infof("#X2SetupResponseManager.PopulateNodebByPdu - RAN name: %s - Unpacked payload and extracted protobuf successfully", nodebInfo.RanName)
nbIdentity.GlobalNbId = enbId
nodebInfo.GlobalNbId = enbId
nodebInfo.ConnectionStatus = entities.ConnectionStatus_CONNECTED
nodebInfo.NodeType = entities.Node_ENB
nodebInfo.Configuration = &entities.NodebInfo_Enb{Enb: enb}
return nil
}