From 7df066d321434b649224b5695f97cedf94dcb20d Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Wed, 24 Jan 2024 12:03:49 +0100 Subject: [PATCH] Improve UseCase handling - Add support for checking if a usecase is set - Fix removing all usecases for an entity --- api/api.go | 3 ++ mocks/EntityLocalInterface.go | 47 ++++++++++++++++++++++++ model/nodemanagement_additions.go | 29 +++++++++++++++ model/nodemanagement_additions_test.go | 20 ++++++++++ spine/entity_local.go | 32 +++++++++++++++- spine/entity_local_test.go | 51 ++++++++++++++++++++++++++ 6 files changed, 181 insertions(+), 1 deletion(-) diff --git a/api/api.go b/api/api.go index fa7f472..054d3e8 100644 --- a/api/api.go +++ b/api/api.go @@ -97,6 +97,9 @@ type EntityLocalInterface interface { useCaseAvailable bool, scenarios []model.UseCaseScenarioSupportType, ) + HasUseCaseSupport( + actor model.UseCaseActorType, + useCaseName model.UseCaseNameType) bool RemoveUseCaseSupport( actor model.UseCaseActorType, useCaseName model.UseCaseNameType, diff --git a/mocks/EntityLocalInterface.go b/mocks/EntityLocalInterface.go index 3d918d0..ba5f338 100644 --- a/mocks/EntityLocalInterface.go +++ b/mocks/EntityLocalInterface.go @@ -472,6 +472,53 @@ func (_c *EntityLocalInterface_GetOrAddFeature_Call) RunAndReturn(run func(model return _c } +// HasUseCaseSupport provides a mock function with given fields: actor, useCaseName +func (_m *EntityLocalInterface) HasUseCaseSupport(actor model.UseCaseActorType, useCaseName model.UseCaseNameType) bool { + ret := _m.Called(actor, useCaseName) + + if len(ret) == 0 { + panic("no return value specified for HasUseCaseSupport") + } + + var r0 bool + if rf, ok := ret.Get(0).(func(model.UseCaseActorType, model.UseCaseNameType) bool); ok { + r0 = rf(actor, useCaseName) + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + +// EntityLocalInterface_HasUseCaseSupport_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'HasUseCaseSupport' +type EntityLocalInterface_HasUseCaseSupport_Call struct { + *mock.Call +} + +// HasUseCaseSupport is a helper method to define mock.On call +// - actor model.UseCaseActorType +// - useCaseName model.UseCaseNameType +func (_e *EntityLocalInterface_Expecter) HasUseCaseSupport(actor interface{}, useCaseName interface{}) *EntityLocalInterface_HasUseCaseSupport_Call { + return &EntityLocalInterface_HasUseCaseSupport_Call{Call: _e.mock.On("HasUseCaseSupport", actor, useCaseName)} +} + +func (_c *EntityLocalInterface_HasUseCaseSupport_Call) Run(run func(actor model.UseCaseActorType, useCaseName model.UseCaseNameType)) *EntityLocalInterface_HasUseCaseSupport_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(model.UseCaseActorType), args[1].(model.UseCaseNameType)) + }) + return _c +} + +func (_c *EntityLocalInterface_HasUseCaseSupport_Call) Return(_a0 bool) *EntityLocalInterface_HasUseCaseSupport_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *EntityLocalInterface_HasUseCaseSupport_Call) RunAndReturn(run func(model.UseCaseActorType, model.UseCaseNameType) bool) *EntityLocalInterface_HasUseCaseSupport_Call { + _c.Call.Return(run) + return _c +} + // Information provides a mock function with given fields: func (_m *EntityLocalInterface) Information() *model.NodeManagementDetailedDiscoveryEntityInformationType { ret := _m.Called() diff --git a/model/nodemanagement_additions.go b/model/nodemanagement_additions.go index 1ad61bc..0149b13 100644 --- a/model/nodemanagement_additions.go +++ b/model/nodemanagement_additions.go @@ -105,6 +105,18 @@ func (n *NodeManagementUseCaseDataType) AddUseCaseSupport( } } +func (n *NodeManagementUseCaseDataType) HasUseCaseSupport( + address FeatureAddressType, + actor UseCaseActorType, + useCaseName UseCaseNameType) bool { + nmMux.Lock() + defer nmMux.Unlock() + + // is there an entry for the entity address, actor and usecase name + _, ok := n.useCaseInformationIndex(address, actor, useCaseName) + return ok +} + // Remove a UseCaseSupportType with // a provided FeatureAddressType, UseCaseActorType and UseCaseNameType func (n *NodeManagementUseCaseDataType) RemoveUseCaseSupport( @@ -141,3 +153,20 @@ func (n *NodeManagementUseCaseDataType) RemoveUseCaseSupport( n.UseCaseInformation = usecaseInfo } + +// Remove all data for a given address type +func (n *NodeManagementUseCaseDataType) RemoveUseCaseDataForAddress(address FeatureAddressType) { + nmMux.Lock() + defer nmMux.Unlock() + + var usecaseInfo []UseCaseInformationDataType + + for _, item := range n.UseCaseInformation { + if !reflect.DeepEqual(item.Address, &address) { + usecaseInfo = append(usecaseInfo, item) + continue + } + } + + n.UseCaseInformation = usecaseInfo +} diff --git a/model/nodemanagement_additions_test.go b/model/nodemanagement_additions_test.go index 3a47115..0d7c15a 100644 --- a/model/nodemanagement_additions_test.go +++ b/model/nodemanagement_additions_test.go @@ -79,6 +79,9 @@ func (s *NodeManagementUseCaseDataTypeSuite) Test_AdditionsAndRemovals() { assert.Equal(s.T(), 2, len(ucs.UseCaseInformation[0].UseCaseSupport)) assert.Equal(s.T(), 1, len(ucs.UseCaseInformation[1].UseCaseSupport)) + hasUC := ucs.HasUseCaseSupport(address, UseCaseActorTypeCEM, UseCaseNameTypeEVChargingSummary) + assert.Equal(s.T(), false, hasUC) + ucs.RemoveUseCaseSupport( address, UseCaseActorTypeCEM, @@ -87,6 +90,9 @@ func (s *NodeManagementUseCaseDataTypeSuite) Test_AdditionsAndRemovals() { assert.Equal(s.T(), 2, len(ucs.UseCaseInformation)) assert.Equal(s.T(), 2, len(ucs.UseCaseInformation[0].UseCaseSupport)) + hasUC = ucs.HasUseCaseSupport(address, UseCaseActorTypeCEM, UseCaseNameTypeControlOfBattery) + assert.Equal(s.T(), true, hasUC) + ucs.RemoveUseCaseSupport( address, UseCaseActorTypeCEM, @@ -120,4 +126,18 @@ func (s *NodeManagementUseCaseDataTypeSuite) Test_AdditionsAndRemovals() { ) assert.Equal(s.T(), 1, len(ucs.UseCaseInformation)) + ucs.AddUseCaseSupport( + address, + UseCaseActorTypeEnergyGuard, + UseCaseNameTypeLimitationOfPowerConsumption, + SpecificationVersionType(""), + "", + true, + []UseCaseScenarioSupportType{}, + ) + assert.Equal(s.T(), 1, len(ucs.UseCaseInformation)) + assert.Equal(s.T(), 1, len(ucs.UseCaseInformation[0].UseCaseSupport)) + + ucs.RemoveUseCaseDataForAddress(address) + assert.Equal(s.T(), 0, len(ucs.UseCaseInformation)) } diff --git a/spine/entity_local.go b/spine/entity_local.go index 47a46f7..6b7eb9d 100644 --- a/spine/entity_local.go +++ b/spine/entity_local.go @@ -123,6 +123,22 @@ func (r *EntityLocal) AddUseCaseSupport( nodeMgmt.SetData(model.FunctionTypeNodeManagementUseCaseData, data) } +func (r *EntityLocal) HasUseCaseSupport(actor model.UseCaseActorType, useCaseName model.UseCaseNameType) bool { + nodeMgmt := r.device.NodeManagement() + + data := nodeMgmt.DataCopy(model.FunctionTypeNodeManagementUseCaseData).(*model.NodeManagementUseCaseDataType) + if data == nil { + return false + } + + address := model.FeatureAddressType{ + Device: r.address.Device, + Entity: r.address.Entity, + } + + return data.HasUseCaseSupport(address, actor, useCaseName) +} + // Remove a usecase with a given actor ans usecase name func (r *EntityLocal) RemoveUseCaseSupport( actor model.UseCaseActorType, @@ -147,7 +163,21 @@ func (r *EntityLocal) RemoveUseCaseSupport( // Remove all usecases func (r *EntityLocal) RemoveAllUseCaseSupports() { - r.RemoveUseCaseSupport("", "") + nodeMgmt := r.device.NodeManagement() + + data := nodeMgmt.DataCopy(model.FunctionTypeNodeManagementUseCaseData).(*model.NodeManagementUseCaseDataType) + if data == nil { + return + } + + address := model.FeatureAddressType{ + Device: r.address.Device, + Entity: r.address.Entity, + } + + data.RemoveUseCaseDataForAddress(address) + + nodeMgmt.SetData(model.FunctionTypeNodeManagementUseCaseData, data) } // Remove all subscriptions diff --git a/spine/entity_local_test.go b/spine/entity_local_test.go index 81f7af3..e28d62c 100644 --- a/spine/entity_local_test.go +++ b/spine/entity_local_test.go @@ -56,6 +56,12 @@ func (suite *EntityLocalTestSuite) Test_Entity() { entity.RemoveAllUseCaseSupports() + hasUC := entity.HasUseCaseSupport( + model.UseCaseActorTypeCEM, + model.UseCaseNameTypeEVSECommissioningAndConfiguration, + ) + assert.Equal(suite.T(), false, hasUC) + entity.AddUseCaseSupport( model.UseCaseActorTypeCEM, model.UseCaseNameTypeEVSECommissioningAndConfiguration, @@ -65,6 +71,38 @@ func (suite *EntityLocalTestSuite) Test_Entity() { []model.UseCaseScenarioSupportType{1, 2}, ) + hasUC = entity.HasUseCaseSupport( + model.UseCaseActorTypeCEM, + model.UseCaseNameTypeEVSECommissioningAndConfiguration, + ) + assert.Equal(suite.T(), true, hasUC) + + entity.AddUseCaseSupport( + model.UseCaseActorTypeCEM, + model.UseCaseNameTypeEVSECommissioningAndConfiguration, + model.SpecificationVersionType("1.0.0"), + "", + true, + []model.UseCaseScenarioSupportType{1, 2}, + ) + + hasUC = entity.HasUseCaseSupport( + model.UseCaseActorTypeCEM, + model.UseCaseNameTypeEVSECommissioningAndConfiguration, + ) + assert.Equal(suite.T(), true, hasUC) + + entity.RemoveUseCaseSupport( + model.UseCaseActorTypeCEM, + model.UseCaseNameTypeEVSECommissioningAndConfiguration, + ) + + hasUC = entity.HasUseCaseSupport( + model.UseCaseActorTypeCEM, + model.UseCaseNameTypeEVSECommissioningAndConfiguration, + ) + assert.Equal(suite.T(), false, hasUC) + entity.AddUseCaseSupport( model.UseCaseActorTypeCEM, model.UseCaseNameTypeEVSECommissioningAndConfiguration, @@ -74,7 +112,20 @@ func (suite *EntityLocalTestSuite) Test_Entity() { []model.UseCaseScenarioSupportType{1, 2}, ) + hasUC = entity.HasUseCaseSupport( + model.UseCaseActorTypeCEM, + model.UseCaseNameTypeEVSECommissioningAndConfiguration, + ) + assert.Equal(suite.T(), true, hasUC) + entity.RemoveAllUseCaseSupports() + + hasUC = entity.HasUseCaseSupport( + model.UseCaseActorTypeCEM, + model.UseCaseNameTypeEVSECommissioningAndConfiguration, + ) + assert.Equal(suite.T(), false, hasUC) + entity.RemoveAllBindings() entity.RemoveAllSubscriptions() }