From d4bddea0c4e3e36de9a8a84467329ce66ecf72b3 Mon Sep 17 00:00:00 2001 From: rh362j Date: Thu, 14 Nov 2019 16:52:53 +0200 Subject: [PATCH] [RICPLT-2492] - RSM - Read & Write from RSM DB the General Configuration. Change-Id: I82724545d4dc05cd3e8c5df6afc2f57b897063d0 Signed-off-by: rh362j --- RSM/converters/x2apPdu_asn1_unpacker.go | 2 - RSM/e2pdus/resource_status_request.go | 8 +- .../resource_status_failure_handler.go | 2 +- RSM/mocks/rsm_writer_mock.go | 5 + RSM/rsmdb/rsm_reader.go | 33 ++-- RSM/rsmdb/rsm_reader_test.go | 179 +++++++++++++++++++++ RSM/rsmdb/rsm_writer.go | 27 +++- RSM/rsmdb/rsm_writer_test.go | 136 ++++++++++++++++ 8 files changed, 356 insertions(+), 36 deletions(-) create mode 100644 RSM/rsmdb/rsm_reader_test.go create mode 100644 RSM/rsmdb/rsm_writer_test.go diff --git a/RSM/converters/x2apPdu_asn1_unpacker.go b/RSM/converters/x2apPdu_asn1_unpacker.go index e95b7ee..d8f817c 100644 --- a/RSM/converters/x2apPdu_asn1_unpacker.go +++ b/RSM/converters/x2apPdu_asn1_unpacker.go @@ -44,8 +44,6 @@ func (r X2apPduUnpacker) UnpackX2apPdu(packedBuf []byte) (*C.E2AP_PDU_t, error) return nil, errors.New("allocation failure (pdu)") } - r.logger.Infof("#x2apPdu_asn1_unpacker.UnpackX2apPdu - Packed pdu(%d):%x", len(packedBuf), packedBuf) - errBuf := make([]C.char, r.maxMessageBufferSize) if !C.per_unpack_pdu(pdu, C.ulong(len(packedBuf)), (*C.uchar)(unsafe.Pointer(&packedBuf[0])), C.ulong(len(errBuf)), &errBuf[0]) { return nil, errors.New(fmt.Sprintf("unpacking error: %s", C.GoString(&errBuf[0]))) diff --git a/RSM/e2pdus/resource_status_request.go b/RSM/e2pdus/resource_status_request.go index 7af3983..fdbbefd 100644 --- a/RSM/e2pdus/resource_status_request.go +++ b/RSM/e2pdus/resource_status_request.go @@ -60,15 +60,15 @@ func BuildPackedResourceStatusRequest(registrationRequest enums.Registration_Req packedBufSize := C.ulong(len(packedBuf)) pduAsString := "" - pLMNIdentities := make([]*C.char, len(request.CellIdList)) - eUTRANCellIdentifiers := make([]*C.char, len(request.CellIdList)) + pLMNIdentities := make([]*C.uchar, len(request.CellIdList)) + eUTRANCellIdentifiers := make([]*C.uchar, len(request.CellIdList)) for i, cellID := range request.CellIdList { - var pLMNIdentity, eUTRANCellIdentifier string + var pLMNIdentity, eUTRANCellIdentifier []byte if _, err := fmt.Sscanf(cellID, "%x:%x", &pLMNIdentity, &eUTRANCellIdentifier); err != nil { return nil, "", fmt.Errorf("BuildPackedResourceStatusRequest() - unexpected CellID value [%s]@%d (want: \":\"), err: %s", cellID, i, err) } - pLMNIdentities[i], eUTRANCellIdentifiers[i] = C.CString(pLMNIdentity), C.CString(eUTRANCellIdentifier) + pLMNIdentities[i], eUTRANCellIdentifiers[i] = (*C.uchar)(C.CBytes(pLMNIdentity)), (*C.uchar)(C.CBytes(eUTRANCellIdentifier)) } defer func() { diff --git a/RSM/handlers/rmrmsghandlers/resource_status_failure_handler.go b/RSM/handlers/rmrmsghandlers/resource_status_failure_handler.go index f7f5fb6..924b3f7 100644 --- a/RSM/handlers/rmrmsghandlers/resource_status_failure_handler.go +++ b/RSM/handlers/rmrmsghandlers/resource_status_failure_handler.go @@ -44,7 +44,7 @@ func (h ResourceStatusFailureHandler) Handle(request *models.RmrRequest) { h.logger.Errorf("#ResourceStatusFailureHandler.Handle - RAN name: %s - unpack failed. Error: %v", request.RanName, err) return } - h.logger.Infof("#ResourceStatusFailureHandler.Handle - RAN name: %s - message: %s", request.RanName, pduAsString) + h.logger.Debugf("#ResourceStatusFailureHandler.Handle - RAN name: %s - message: %s", request.RanName, pduAsString) } response, err := h.converter.Convert(request.Payload) if err != nil { diff --git a/RSM/mocks/rsm_writer_mock.go b/RSM/mocks/rsm_writer_mock.go index a2a62d8..bfabda7 100644 --- a/RSM/mocks/rsm_writer_mock.go +++ b/RSM/mocks/rsm_writer_mock.go @@ -29,3 +29,8 @@ func (m *RsmWriterMock) SaveRsmRanInfo(rsmRanInfo *models.RsmRanInfo) error { args := m.Called(rsmRanInfo) return args.Error(0) } + +func (m *RsmWriterMock) SaveRsmGeneralConfiguration(cfg *models.RsmGeneralConfiguration) error { + args := m.Called(cfg) + return args.Error(0) +} diff --git a/RSM/rsmdb/rsm_reader.go b/RSM/rsmdb/rsm_reader.go index cb47ad2..852346b 100644 --- a/RSM/rsmdb/rsm_reader.go +++ b/RSM/rsmdb/rsm_reader.go @@ -20,7 +20,6 @@ import ( "encoding/json" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common" "reflect" - "rsm/enums" "rsm/models" ) @@ -28,21 +27,18 @@ type rsmReaderInstance struct { sdl common.ISdlInstance } -/* -RNibReader interface allows retrieving data from redis BD by various keys -*/ +// RsmReader interface allows retrieving data from redis BD by various keys type RsmReader interface { GetRsmGeneralConfiguration() (*models.RsmGeneralConfiguration, error) GetRsmRanInfo(ranName string) (*models.RsmRanInfo, error) } -/* -GetRNibReader returns reference to RNibReader -*/ +// GetRsmReader returns reference to RsmReader func GetRsmReader(sdl common.ISdlInstance) RsmReader { return &rsmReaderInstance{sdl: sdl} } +// GetRsmRanInfo returns the rsm data associated with ran 'ranName' func (r *rsmReaderInstance) GetRsmRanInfo(ranName string) (*models.RsmRanInfo, error) { key, err := common.ValidateAndBuildNodeBNameKey(ranName) @@ -61,23 +57,14 @@ func (r *rsmReaderInstance) GetRsmRanInfo(ranName string) (*models.RsmRanInfo, e return rsmRanInfo, nil } -// TODO: implement +// GetRsmGeneralConfiguration returns resource status request related configuration func (r *rsmReaderInstance) GetRsmGeneralConfiguration() (*models.RsmGeneralConfiguration, error) { - return &models.RsmGeneralConfiguration{ - EnableResourceStatus: true, - PartialSuccessAllowed: true, - PrbPeriodic: true, - TnlLoadIndPeriodic: true, - HwLoadIndPeriodic: true, - AbsStatusPeriodic: true, - RsrpMeasurementPeriodic: true, - CsiPeriodic: true, - PeriodicityMs: enums.ReportingPeriodicity_one_thousand_ms, - PeriodicityRsrpMeasurementMs: enums.ReportingPeriodicityRSRPMR_four_hundred_80_ms, - PeriodicityCsiMs: enums.ReportingPeriodicityCSIR_ms20, - }, nil + cfg := &models.RsmGeneralConfiguration{} + err := r.getByKeyAndUnmarshal(buildRsmGeneralConfigurationKey(), cfg) + return cfg, err } +// getByKeyAndUnmarshal returns the value that is associated with key 'key' as a Go structure func (r *rsmReaderInstance) getByKeyAndUnmarshal(key string, entity interface{}) error { data, err := r.sdl.Get([]string{key}) if err != nil { @@ -92,3 +79,7 @@ func (r *rsmReaderInstance) getByKeyAndUnmarshal(key string, entity interface{}) } return common.NewResourceNotFoundErrorf("#rsmReader.getByKeyAndUnmarshal - entity of type %s not found. Key: %s", reflect.TypeOf(entity).String(), key) } + +func buildRsmGeneralConfigurationKey() string { + return "CFG:GENERAL:v1.0.0" +} diff --git a/RSM/rsmdb/rsm_reader_test.go b/RSM/rsmdb/rsm_reader_test.go new file mode 100644 index 0000000..e1703df --- /dev/null +++ b/RSM/rsmdb/rsm_reader_test.go @@ -0,0 +1,179 @@ +/******************************************************************************* + * + * Copyright (c) 2019 AT&T Intellectual Property. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *******************************************************************************/ +package rsmdb + +import ( + "fmt" + "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common" +// "gerrit.o-ran-sc.org/r/ric-plt/sdlgo" + "github.com/stretchr/testify/assert" +// "os" + "rsm/enums" + "rsm/mocks" + "rsm/models" + "testing" +) + +func TestGetRsmRanInfo(t *testing.T) { + sdl := &mocks.MockSdlInstance{} + reader := GetRsmReader(sdl) + ranName := "test1" + key, _ := common.ValidateAndBuildNodeBNameKey(ranName) + infoAsGoType := models.RsmRanInfo{ + RanName: ranName, + Enb1MeasurementId: 1, + Enb2MeasurementId: 2, + Action: enums.Start, + ActionStatus: false, + } + infoAsDbType:= "{\"ranName\":\"test1\",\"enb1MeasurementId\":1,\"enb2MeasurementId\":2,\"action\":\"start\",\"actionStatus\":false}" + sdl.On("Get", []string{key}).Return(map[string]interface{}{key: infoAsDbType}, nil) + info, err := reader.GetRsmRanInfo(ranName) + if err != nil { + t.Errorf("want: success, got: error: %v\n", err) + } + assert.Equal(t, info, &infoAsGoType) +} + +func TestGetRsmRanInfoValidationError(t *testing.T) { + sdl := &mocks.MockSdlInstance{} + reader := GetRsmReader(sdl) + ranName := "" + key, _ := common.ValidateAndBuildNodeBNameKey(ranName) + sdl.On("Get", []string{key}).Return(map[string]interface{}{key: ""}, nil) + _, err := reader.GetRsmRanInfo(ranName) + assert.NotNil(t, err) + assert.Equal(t, err.Error(), "#utils.ValidateAndBuildNodeBNameKey - an empty inventory name received") +} + +func TestGetRsmRanInfoDbError(t *testing.T) { + sdl := &mocks.MockSdlInstance{} + reader := GetRsmReader(sdl) + ranName := "test1" + key, _ := common.ValidateAndBuildNodeBNameKey(ranName) + sdl.On("Get", []string{key}).Return((map[string]interface{})(nil), fmt.Errorf("db error")) + _, err := reader.GetRsmRanInfo(ranName) + assert.NotNil(t, err) + assert.Equal(t, err.Error(), "db error") +} + +func TestGetGeneralConfiguration(t *testing.T) { + sdl := &mocks.MockSdlInstance{} + reader := GetRsmReader(sdl) + var testCases = []struct { + cfgAsGoType models.RsmGeneralConfiguration + cfgAsDbType string + }{ + { + cfgAsGoType: models.RsmGeneralConfiguration{ + EnableResourceStatus: true, + PartialSuccessAllowed: true, + PrbPeriodic: true, + TnlLoadIndPeriodic: true, + HwLoadIndPeriodic: true, + AbsStatusPeriodic: true, + RsrpMeasurementPeriodic: true, + CsiPeriodic: true, + PeriodicityMs: enums.ReportingPeriodicity_one_thousand_ms, + PeriodicityRsrpMeasurementMs: enums.ReportingPeriodicityRSRPMR_four_hundred_80_ms, + PeriodicityCsiMs: enums.ReportingPeriodicityCSIR_ms20, + }, + + cfgAsDbType: "{\"enableResourceStatus\":true,\"partialSuccessAllowed\":true,\"prbPeriodic\":true,\"tnlLoadIndPeriodic\":true,\"wwLoadIndPeriodic\":true,\"absStatusPeriodic\":true,\"rsrpMeasurementPeriodic\":true,\"csiPeriodic\":true,\"periodicityMs\":1,\"periodicityRsrpMeasurementMs\":3,\"periodicityCsiMs\":3}", + }, + } + + for _, tc := range testCases { + t.Run(tc.cfgAsDbType, func(t *testing.T) { + key := buildRsmGeneralConfigurationKey() + sdl.On("Get", []string{key}).Return(map[string]interface{}{key: tc.cfgAsDbType}, nil) + cfg, err := reader.GetRsmGeneralConfiguration() + if err != nil { + t.Errorf("want: success, got: error: %v\n", err) + } + assert.Equal(t, cfg, &tc.cfgAsGoType) + }) + } +} + +func TestGetGeneralConfigurationNotFound(t *testing.T) { + sdl := &mocks.MockSdlInstance{} + reader := GetRsmReader(sdl) + + key := buildRsmGeneralConfigurationKey() + sdl.On("Get", []string{key}).Return((map[string]interface{})(nil), nil) + _, err := reader.GetRsmGeneralConfiguration() + assert.NotNil(t, err) + assert.Equal(t, err.Error(), "#rsmReader.getByKeyAndUnmarshal - entity of type *models.RsmGeneralConfiguration not found. Key: CFG:GENERAL:v1.0.0") +} + +func TestGetGeneralConfigurationDbError(t *testing.T) { + sdl := &mocks.MockSdlInstance{} + reader := GetRsmReader(sdl) + + key := buildRsmGeneralConfigurationKey() + sdl.On("Get", []string{key}).Return((map[string]interface{})(nil), fmt.Errorf("db error")) + _, err := reader.GetRsmGeneralConfiguration() + assert.NotNil(t, err) + assert.Equal(t, err.Error(), "db error") +} + +func TestGetGeneralConfigurationUnmarshalError(t *testing.T) { + sdl := &mocks.MockSdlInstance{} + reader := GetRsmReader(sdl) + cfgAsDbTYpe := "{\"enableResourceStatus\":true, partialSuccessAllowed\":true,\"prbPeriodic\":true,\"tnlLoadIndPeriodic\":true,\"wwLoadIndPeriodic\":true,\"absStatusPeriodic\":true,\"rsrpMeasurementPeriodic\":true,\"csiPeriodic\":true,\"periodicityMs\":1,\"periodicityRsrpMeasurementMs\":3,\"periodicityCsiMs\":3}" + key := buildRsmGeneralConfigurationKey() + sdl.On("Get", []string{key}).Return(map[string]interface{}{key: cfgAsDbTYpe}, nil) + _, err := reader.GetRsmGeneralConfiguration() + assert.NotNil(t, err) + assert.Equal(t, err.Error(), "invalid character 'p' looking for beginning of object key string") +} + +/* +Test against redis. +Test execution depends on the existence of the environment variable DBAAS_SERVICE_HOST. +* + +func TestGetGeneralConfigurationIntegration(t *testing.T) { + if len(os.Getenv("DBAAS_SERVICE_HOST")) == 0 { + return + } + db := sdlgo.NewDatabase() + sdl := sdlgo.NewSdlInstance("rsm", db) + reader := GetRsmReader(sdl) + cfgAsGoType := models.RsmGeneralConfiguration{ + EnableResourceStatus: true, + PartialSuccessAllowed: true, + PrbPeriodic: true, + TnlLoadIndPeriodic: true, + HwLoadIndPeriodic: true, + AbsStatusPeriodic: true, + RsrpMeasurementPeriodic: true, + CsiPeriodic: true, + PeriodicityMs: enums.ReportingPeriodicity_one_thousand_ms, + PeriodicityRsrpMeasurementMs: enums.ReportingPeriodicityRSRPMR_four_hundred_80_ms, + PeriodicityCsiMs: enums.ReportingPeriodicityCSIR_ms20, + } + cfg, err := reader.GetRsmGeneralConfiguration() + if err != nil { + t.Errorf("want: success, got: error: %v\n", err) + } + + assert.Equal(t, &cfgAsGoType, cfg) +} +*/ \ No newline at end of file diff --git a/RSM/rsmdb/rsm_writer.go b/RSM/rsmdb/rsm_writer.go index fe7fa56..9a87689 100644 --- a/RSM/rsmdb/rsm_writer.go +++ b/RSM/rsmdb/rsm_writer.go @@ -26,20 +26,18 @@ type rsmWriterInstance struct { sdl common.ISdlInstance } -/* -RNibReader interface allows retrieving data from redis BD by various keys -*/ +// RsmWriter interface allows inserting/updating data to/in redis BD with various keys type RsmWriter interface { SaveRsmRanInfo(rsmRanInfo *models.RsmRanInfo) error + SaveRsmGeneralConfiguration(cfg *models.RsmGeneralConfiguration) error } -/* -GetRNibReader returns reference to RNibReader -*/ +// GetRsmWriter returns reference to RsmWriter func GetRsmWriter(sdl common.ISdlInstance) RsmWriter { return &rsmWriterInstance{sdl: sdl} } +// SaveRsmRanInfo saves the ran related rsm data with key RanName func (r *rsmWriterInstance) SaveRsmRanInfo(rsmRanInfo *models.RsmRanInfo) error { nodebNameKey, err := common.ValidateAndBuildNodeBNameKey(rsmRanInfo.RanName) @@ -48,14 +46,27 @@ func (r *rsmWriterInstance) SaveRsmRanInfo(rsmRanInfo *models.RsmRanInfo) error return err } - data, err := json.Marshal(rsmRanInfo) + return r.SaveWithKeyAndMarshal(nodebNameKey, rsmRanInfo) +} + +// SaveRsmGeneralConfiguration saves the resource status request related configuration +func (r *rsmWriterInstance) SaveRsmGeneralConfiguration(cfg *models.RsmGeneralConfiguration) error { + + return r.SaveWithKeyAndMarshal(buildRsmGeneralConfigurationKey(), cfg) +} + + +// SaveWithKeyAndMarshal marshals +func (r *rsmWriterInstance) SaveWithKeyAndMarshal(key string, entity interface{}) error { + + data, err := json.Marshal(entity) if err != nil { return common.NewInternalError(err) } var pairs []interface{} - pairs = append(pairs, nodebNameKey, data) + pairs = append(pairs, key, data) err = r.sdl.Set(pairs) diff --git a/RSM/rsmdb/rsm_writer_test.go b/RSM/rsmdb/rsm_writer_test.go new file mode 100644 index 0000000..627c2f1 --- /dev/null +++ b/RSM/rsmdb/rsm_writer_test.go @@ -0,0 +1,136 @@ +/******************************************************************************* + * + * Copyright (c) 2019 AT&T Intellectual Property. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *******************************************************************************/ +package rsmdb + +import ( + "fmt" + "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common" + "github.com/stretchr/testify/assert" + "rsm/enums" + "rsm/mocks" + "rsm/models" + "testing" +) + +func TestSaveRsmRanInfo(t *testing.T) { + sdl := &mocks.MockSdlInstance{} + writer := GetRsmWriter(sdl) + ranName := "test1" + key, _ := common.ValidateAndBuildNodeBNameKey(ranName) + infoAsGoType := models.RsmRanInfo{ + RanName: ranName, + Enb1MeasurementId: 1, + Enb2MeasurementId: 2, + Action: enums.Start, + ActionStatus: false, + } + infoAsDbType:= "{\"ranName\":\"test1\",\"enb1MeasurementId\":1,\"enb2MeasurementId\":2,\"action\":\"start\",\"actionStatus\":false}" + sdl.On("Set",[]interface{}{[]interface{}{key, []byte(infoAsDbType)}}).Return(nil) + err := writer.SaveRsmRanInfo(&infoAsGoType) + if err != nil { + t.Errorf("want: success, got: error: %v\n", err) + } + sdl.AssertNumberOfCalls(t, "Set",1) +} + + +func TestSaveRsmRanInfoValidationError(t *testing.T) { + sdl := &mocks.MockSdlInstance{} + writer := GetRsmWriter(sdl) + ranName := "" + key, _ := common.ValidateAndBuildNodeBNameKey(ranName) + infoAsGoType := models.RsmRanInfo{ + RanName: ranName, + Enb1MeasurementId: 1, + Enb2MeasurementId: 2, + Action: enums.Start, + ActionStatus: false, + } + infoAsDbType:= "{\"ranName\":\"test1\",\"enb1MeasurementId\":1,\"enb2MeasurementId\":2,\"action\":\"start\",\"actionStatus\":false}" + sdl.On("Set",[]interface{}{[]interface{}{key, []byte(infoAsDbType)}}).Return(nil) + err := writer.SaveRsmRanInfo(&infoAsGoType) + assert.NotNil(t, err) + assert.Equal(t, err.Error(), "#utils.ValidateAndBuildNodeBNameKey - an empty inventory name received") +} + + +func TestSaveGeneralConfiguration(t *testing.T) { + sdl := &mocks.MockSdlInstance{} + writer := GetRsmWriter(sdl) + var testCases = []struct { + cfgAsGoType models.RsmGeneralConfiguration + cfgAsDbType string + }{ + { + cfgAsGoType: models.RsmGeneralConfiguration{ + EnableResourceStatus: true, + PartialSuccessAllowed: true, + PrbPeriodic: true, + TnlLoadIndPeriodic: true, + HwLoadIndPeriodic: true, + AbsStatusPeriodic: true, + RsrpMeasurementPeriodic: true, + CsiPeriodic: true, + PeriodicityMs: enums.ReportingPeriodicity_one_thousand_ms, + PeriodicityRsrpMeasurementMs: enums.ReportingPeriodicityRSRPMR_four_hundred_80_ms, + PeriodicityCsiMs: enums.ReportingPeriodicityCSIR_ms20, + }, + + cfgAsDbType: "{\"enableResourceStatus\":true,\"partialSuccessAllowed\":true,\"prbPeriodic\":true,\"tnlLoadIndPeriodic\":true,\"wwLoadIndPeriodic\":true,\"absStatusPeriodic\":true,\"rsrpMeasurementPeriodic\":true,\"csiPeriodic\":true,\"periodicityMs\":1,\"periodicityRsrpMeasurementMs\":3,\"periodicityCsiMs\":3}", + }, + } + + for _, tc := range testCases { + t.Run(tc.cfgAsDbType, func(t *testing.T) { + key:= buildRsmGeneralConfigurationKey() + sdl.On("Set",[]interface{}{[]interface{}{key, []byte(tc.cfgAsDbType)}}).Return(nil) + err := writer.SaveRsmGeneralConfiguration(&tc.cfgAsGoType) + if err != nil { + t.Errorf("want: success, got: error: %v\n", err) + } + + sdl.AssertNumberOfCalls(t, "Set",1) + }) + } +} + + +func TestSaveGeneralConfigurationDbError(t *testing.T) { + sdl := &mocks.MockSdlInstance{} + writer := GetRsmWriter(sdl) + + cfgAsGoType:= models.RsmGeneralConfiguration{ + EnableResourceStatus: true, + PartialSuccessAllowed: true, + PrbPeriodic: true, + TnlLoadIndPeriodic: true, + HwLoadIndPeriodic: true, + AbsStatusPeriodic: true, + RsrpMeasurementPeriodic: true, + CsiPeriodic: true, + PeriodicityMs: enums.ReportingPeriodicity_one_thousand_ms, + PeriodicityRsrpMeasurementMs: enums.ReportingPeriodicityRSRPMR_four_hundred_80_ms, + PeriodicityCsiMs: enums.ReportingPeriodicityCSIR_ms20, + } + cfgAsDbTYpe:= "{\"enableResourceStatus\":true,\"partialSuccessAllowed\":true,\"prbPeriodic\":true,\"tnlLoadIndPeriodic\":true,\"wwLoadIndPeriodic\":true,\"absStatusPeriodic\":true,\"rsrpMeasurementPeriodic\":true,\"csiPeriodic\":true,\"periodicityMs\":1,\"periodicityRsrpMeasurementMs\":3,\"periodicityCsiMs\":3}" + key:= buildRsmGeneralConfigurationKey() + sdl.On("Set",[]interface{}{[]interface{}{key, []byte(cfgAsDbTYpe)}}).Return(fmt.Errorf("db error")) + err := writer.SaveRsmGeneralConfiguration(&cfgAsGoType) + assert.NotNil(t, err) + assert.Equal(t, err.Error(), "db error") +} -- 2.16.6