github.com/enbility/spine-go@v0.7.0/spine/feature_local_test.go (about)

     1  package spine
     2  
     3  import (
     4  	"errors"
     5  	"reflect"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/enbility/spine-go/api"
    10  	"github.com/enbility/spine-go/mocks"
    11  	"github.com/enbility/spine-go/model"
    12  	"github.com/enbility/spine-go/util"
    13  	"github.com/stretchr/testify/assert"
    14  	"github.com/stretchr/testify/mock"
    15  	"github.com/stretchr/testify/suite"
    16  )
    17  
    18  func TestLocalFeatureTestSuite(t *testing.T) {
    19  	suite.Run(t, new(LocalFeatureTestSuite))
    20  }
    21  
    22  type LocalFeatureTestSuite struct {
    23  	suite.Suite
    24  	senderMock                    *mocks.SenderInterface
    25  	localDevice                   *DeviceLocal
    26  	localEntity                   *EntityLocal
    27  	function, serverWriteFunction model.FunctionType
    28  	featureType, subFeatureType   model.FeatureTypeType
    29  	msgCounter                    model.MsgCounterType
    30  	remoteFeature, remote2Feature,
    31  	remoteServerFeature, remoteSubFeature api.FeatureRemoteInterface
    32  	localFeature, localServerFeature, localServerFeatureWrite api.FeatureLocalInterface
    33  }
    34  
    35  func (s *LocalFeatureTestSuite) BeforeTest(suiteName, testName string) {
    36  	s.senderMock = mocks.NewSenderInterface(s.T())
    37  	s.function = model.FunctionTypeDeviceClassificationManufacturerData
    38  	s.featureType = model.FeatureTypeTypeDeviceClassification
    39  	s.subFeatureType = model.FeatureTypeTypeLoadControl
    40  	s.serverWriteFunction = model.FunctionTypeLoadControlLimitListData
    41  	s.msgCounter = model.MsgCounterType(1)
    42  
    43  	s.localDevice, s.localEntity = createLocalDeviceAndEntity(1)
    44  	s.localFeature, s.localServerFeature = createLocalFeatures(s.localEntity, s.featureType, "")
    45  	_, s.localServerFeatureWrite = createLocalFeatures(s.localEntity, s.subFeatureType, s.serverWriteFunction)
    46  
    47  	remoteDevice := createRemoteDevice(s.localDevice, "ski", s.senderMock)
    48  	remoteDevice2 := createRemoteDevice(s.localDevice, "iks", s.senderMock)
    49  	s.remoteFeature, s.remoteServerFeature = createRemoteEntityAndFeature(remoteDevice, 1, s.featureType, s.function)
    50  	s.remoteSubFeature, _ = createRemoteEntityAndFeature(remoteDevice, 2, s.subFeatureType, s.serverWriteFunction)
    51  	s.remote2Feature, _ = createRemoteEntityAndFeature(remoteDevice2, 1, s.featureType, s.function)
    52  }
    53  
    54  func (s *LocalFeatureTestSuite) TestDeviceClassification_Functions() {
    55  	fcts := s.localServerFeatureWrite.Functions()
    56  	assert.NotNil(s.T(), fcts)
    57  	assert.Equal(s.T(), 1, len(fcts))
    58  	assert.Equal(s.T(), s.serverWriteFunction, fcts[0])
    59  }
    60  
    61  func (s *LocalFeatureTestSuite) TestDeviceClassification_ResponseCB() {
    62  	testFct := func(msg api.ResponseMessage) {}
    63  	msgCounter := model.MsgCounterType(100)
    64  	err := s.localFeature.AddResponseCallback(msgCounter, testFct)
    65  	assert.Nil(s.T(), err)
    66  
    67  	err = s.localFeature.AddResponseCallback(msgCounter, testFct)
    68  	assert.NotNil(s.T(), err)
    69  
    70  	s.localFeature.AddResultCallback(testFct)
    71  }
    72  
    73  func (s *LocalFeatureTestSuite) TestDeviceClassification_Request_Reply() {
    74  	dummyAddress := &model.FeatureAddressType{
    75  		Device:  util.Ptr(model.AddressDeviceType("")),
    76  		Entity:  []model.AddressEntityType{2},
    77  		Feature: util.Ptr(model.AddressFeatureType(100)),
    78  	}
    79  
    80  	s.senderMock.EXPECT().Request(
    81  		model.CmdClassifierTypeRead,
    82  		s.localFeature.Address(),
    83  		s.remoteFeature.Address(),
    84  		false,
    85  		mock.AnythingOfType("[]model.CmdType")).Return(&s.msgCounter, nil).Maybe()
    86  	s.senderMock.EXPECT().Request(
    87  		model.CmdClassifierTypeRead,
    88  		s.localFeature.Address(),
    89  		dummyAddress,
    90  		false,
    91  		mock.AnythingOfType("[]model.CmdType")).Return(nil, errors.New("test"))
    92  
    93  	msgCounter, err := s.localFeature.RequestRemoteData(model.FunctionTypeBillListData, nil, nil, s.remoteFeature)
    94  	assert.NotNil(s.T(), err)
    95  	assert.Nil(s.T(), msgCounter)
    96  
    97  	msgCounter, err = s.localFeature.RequestRemoteDataBySenderAddress(model.CmdType{}, s.senderMock, "dummyfail", dummyAddress, 0)
    98  	assert.NotNil(s.T(), err)
    99  	assert.Nil(s.T(), msgCounter)
   100  
   101  	// send data request
   102  	msgCounter, err = s.localFeature.RequestRemoteData(s.function, nil, nil, s.remoteFeature)
   103  	assert.Nil(s.T(), err)
   104  	assert.NotNil(s.T(), msgCounter)
   105  
   106  	manufacturerData := &model.DeviceClassificationManufacturerDataType{
   107  		BrandName:    util.Ptr(model.DeviceClassificationStringType("brand name")),
   108  		VendorName:   util.Ptr(model.DeviceClassificationStringType("vendor name")),
   109  		DeviceName:   util.Ptr(model.DeviceClassificationStringType("device name")),
   110  		DeviceCode:   util.Ptr(model.DeviceClassificationStringType("device code")),
   111  		SerialNumber: util.Ptr(model.DeviceClassificationStringType("serial number")),
   112  	}
   113  
   114  	replyMsg := api.Message{
   115  		Cmd: model.CmdType{
   116  			DeviceClassificationManufacturerData: manufacturerData,
   117  		},
   118  		CmdClassifier: model.CmdClassifierTypeReply,
   119  		RequestHeader: &model.HeaderType{
   120  			MsgCounter:          util.Ptr(model.MsgCounterType(1)),
   121  			MsgCounterReference: &s.msgCounter,
   122  		},
   123  		FeatureRemote: s.remoteFeature,
   124  	}
   125  	// set response
   126  	msgErr := s.localFeature.HandleMessage(&replyMsg)
   127  	if assert.Nil(s.T(), msgErr) {
   128  		remoteData := s.remoteFeature.DataCopy(s.function)
   129  		assert.IsType(s.T(), &model.DeviceClassificationManufacturerDataType{}, remoteData, "Data has wrong type")
   130  	}
   131  }
   132  
   133  func (s *LocalFeatureTestSuite) TestDeviceClassification_Request_Error() {
   134  	s.senderMock.On("Request", model.CmdClassifierTypeRead, s.localFeature.Address(), s.remoteFeature.Address(), false, mock.AnythingOfType("[]model.CmdType")).Return(&s.msgCounter, nil)
   135  
   136  	const errorNumber = model.ErrorNumberTypeGeneralError
   137  	const errorDescription = "error occurred"
   138  
   139  	// send data request
   140  	msgCounter, err := s.localFeature.RequestRemoteData(s.function, nil, nil, s.remoteFeature)
   141  	assert.NotNil(s.T(), msgCounter)
   142  	assert.Nil(s.T(), err)
   143  
   144  	replyMsg := api.Message{
   145  		Cmd: model.CmdType{
   146  			ResultData: &model.ResultDataType{
   147  				ErrorNumber: util.Ptr(model.ErrorNumberType(errorNumber)),
   148  				Description: util.Ptr(model.DescriptionType(errorDescription)),
   149  			},
   150  		},
   151  		CmdClassifier: model.CmdClassifierTypeResult,
   152  		RequestHeader: &model.HeaderType{
   153  			MsgCounter:          util.Ptr(model.MsgCounterType(1)),
   154  			MsgCounterReference: &s.msgCounter,
   155  		},
   156  		FeatureRemote: s.remoteFeature,
   157  		EntityRemote:  s.remoteFeature.Entity(),
   158  		DeviceRemote:  s.remoteFeature.Device(),
   159  	}
   160  
   161  	// set response
   162  	msgErr := s.localFeature.HandleMessage(&replyMsg)
   163  	if assert.Nil(s.T(), msgErr) {
   164  		remoteData := s.remoteFeature.DataCopy(s.function)
   165  		assert.Nil(s.T(), remoteData)
   166  	}
   167  }
   168  
   169  func (s *LocalFeatureTestSuite) TestDeviceClassification_Subscriptions() {
   170  	s.senderMock.On("Subscribe", mock.Anything, mock.Anything, mock.Anything).Return(&s.msgCounter, nil)
   171  	s.senderMock.On("Unsubscribe", mock.Anything, mock.Anything, mock.Anything).Return(&s.msgCounter, nil)
   172  
   173  	msgCounter, err := s.localFeature.SubscribeToRemote(s.remoteFeature.Address())
   174  	assert.NotNil(s.T(), err)
   175  	assert.Nil(s.T(), msgCounter)
   176  
   177  	msgCounter, err = s.localFeature.RemoveRemoteSubscription(s.remoteFeature.Address())
   178  	assert.NotNil(s.T(), err)
   179  	assert.Nil(s.T(), msgCounter)
   180  
   181  	s.localFeature.Device().AddRemoteDeviceForSki(s.remoteFeature.Device().Ski(), s.remoteFeature.Device())
   182  
   183  	msgCounter, err = s.localServerFeature.SubscribeToRemote(s.remoteFeature.Address())
   184  	assert.NotNil(s.T(), err)
   185  	assert.Nil(s.T(), msgCounter)
   186  
   187  	msgCounter, err = s.localFeature.RemoveRemoteSubscription(s.remoteFeature.Address())
   188  	assert.Nil(s.T(), err)
   189  	assert.NotNil(s.T(), msgCounter)
   190  
   191  	subscribed := s.localFeature.HasSubscriptionToRemote(s.remoteFeature.Address())
   192  	assert.Equal(s.T(), false, subscribed)
   193  
   194  	msgCounter, err = s.localFeature.SubscribeToRemote(s.remoteFeature.Address())
   195  	assert.Nil(s.T(), err)
   196  	assert.NotNil(s.T(), msgCounter)
   197  
   198  	subscribed = s.localFeature.HasSubscriptionToRemote(s.remoteFeature.Address())
   199  	assert.Equal(s.T(), true, subscribed)
   200  
   201  	msgCounter, err = s.localFeature.SubscribeToRemote(s.remoteSubFeature.Address())
   202  	assert.Nil(s.T(), err)
   203  	assert.NotNil(s.T(), msgCounter)
   204  
   205  	msgCounter, err = s.localFeature.RemoveRemoteSubscription(s.remoteFeature.Address())
   206  	assert.Nil(s.T(), err)
   207  	assert.NotNil(s.T(), msgCounter)
   208  
   209  	s.localFeature.RemoveAllRemoteSubscriptions()
   210  }
   211  
   212  func (s *LocalFeatureTestSuite) TestDeviceClassification_Bindings() {
   213  	s.senderMock.On("Bind", mock.Anything, mock.Anything, mock.Anything).Return(&s.msgCounter, nil)
   214  	s.senderMock.On("Unbind", mock.Anything, mock.Anything, mock.Anything).Return(&s.msgCounter, nil)
   215  
   216  	msgCounter, err := s.localFeature.BindToRemote(s.remoteFeature.Address())
   217  	assert.NotNil(s.T(), err)
   218  	assert.Nil(s.T(), msgCounter)
   219  
   220  	msgCounter, err = s.localFeature.RemoveRemoteBinding(s.remoteFeature.Address())
   221  	assert.NotNil(s.T(), err)
   222  	assert.Nil(s.T(), msgCounter)
   223  
   224  	s.localFeature.Device().AddRemoteDeviceForSki(s.remoteFeature.Device().Ski(), s.remoteFeature.Device())
   225  
   226  	msgCounter, err = s.localServerFeature.BindToRemote(s.remoteFeature.Address())
   227  	assert.NotNil(s.T(), err)
   228  	assert.Nil(s.T(), msgCounter)
   229  
   230  	msgCounter, err = s.localFeature.RemoveRemoteBinding(s.remoteFeature.Address())
   231  	assert.Nil(s.T(), err)
   232  	assert.NotNil(s.T(), msgCounter)
   233  
   234  	binding := s.localFeature.HasBindingToRemote(s.remoteFeature.Address())
   235  	assert.Equal(s.T(), false, binding)
   236  
   237  	msgCounter, err = s.localFeature.BindToRemote(s.remoteFeature.Address())
   238  	assert.Nil(s.T(), err)
   239  	assert.NotNil(s.T(), msgCounter)
   240  
   241  	binding = s.localFeature.HasBindingToRemote(s.remoteFeature.Address())
   242  	assert.Equal(s.T(), true, binding)
   243  
   244  	msgCounter, err = s.localFeature.BindToRemote(s.remoteSubFeature.Address())
   245  	assert.Nil(s.T(), err)
   246  	assert.NotNil(s.T(), msgCounter)
   247  
   248  	msgCounter, err = s.localFeature.RemoveRemoteBinding(s.remoteFeature.Address())
   249  	assert.Nil(s.T(), err)
   250  	assert.NotNil(s.T(), msgCounter)
   251  
   252  	s.localFeature.RemoveAllRemoteBindings()
   253  }
   254  
   255  func (s *LocalFeatureTestSuite) Test_CleanRemoteDeviceCaches() {
   256  	s.senderMock.On("Subscribe", mock.Anything, mock.Anything, mock.Anything).Return(&s.msgCounter, nil)
   257  	s.senderMock.On("Bind", mock.Anything, mock.Anything, mock.Anything).Return(&s.msgCounter, nil)
   258  
   259  	s.localFeature.CleanWriteApprovalCaches("testdummytest")
   260  	s.localFeature.CleanRemoteDeviceCaches(nil)
   261  
   262  	address := &model.DeviceAddressType{}
   263  	s.localFeature.CleanRemoteDeviceCaches(address)
   264  
   265  	address.Device = util.Ptr(model.AddressDeviceType("dummy"))
   266  	s.localFeature.CleanRemoteDeviceCaches(address)
   267  
   268  	address.Device = s.remoteFeature.Address().Device
   269  	s.localFeature.CleanRemoteDeviceCaches(address)
   270  
   271  	s.localFeature.Device().AddRemoteDeviceForSki(s.remoteFeature.Device().Ski(), s.remoteFeature.Device())
   272  	s.localFeature.Device().AddRemoteDeviceForSki(s.remote2Feature.Device().Ski(), s.remote2Feature.Device())
   273  
   274  	msgCounter, err := s.localFeature.SubscribeToRemote(s.remote2Feature.Address())
   275  	assert.Nil(s.T(), err)
   276  	assert.NotNil(s.T(), msgCounter)
   277  
   278  	msgCounter, err = s.localFeature.SubscribeToRemote(s.remoteFeature.Address())
   279  	assert.Nil(s.T(), err)
   280  	assert.NotNil(s.T(), msgCounter)
   281  
   282  	msgCounter, err = s.localFeature.SubscribeToRemote(s.remoteSubFeature.Address())
   283  	assert.Nil(s.T(), err)
   284  	assert.NotNil(s.T(), msgCounter)
   285  
   286  	value := s.localFeature.HasSubscriptionToRemote(s.remote2Feature.Address())
   287  	assert.True(s.T(), value)
   288  
   289  	value = s.localFeature.HasSubscriptionToRemote(s.remoteFeature.Address())
   290  	assert.True(s.T(), value)
   291  
   292  	value = s.localFeature.HasSubscriptionToRemote(s.remoteSubFeature.Address())
   293  	assert.True(s.T(), value)
   294  
   295  	msgCounter, err = s.localFeature.BindToRemote(s.remote2Feature.Address())
   296  	assert.Nil(s.T(), err)
   297  	assert.NotNil(s.T(), msgCounter)
   298  
   299  	msgCounter, err = s.localFeature.BindToRemote(s.remoteFeature.Address())
   300  	assert.Nil(s.T(), err)
   301  	assert.NotNil(s.T(), msgCounter)
   302  
   303  	msgCounter, err = s.localFeature.BindToRemote(s.remoteSubFeature.Address())
   304  	assert.Nil(s.T(), err)
   305  	assert.NotNil(s.T(), msgCounter)
   306  
   307  	value = s.localFeature.HasBindingToRemote(s.remoteFeature.Address())
   308  	assert.True(s.T(), value)
   309  
   310  	value = s.localFeature.HasBindingToRemote(s.remoteSubFeature.Address())
   311  	assert.True(s.T(), value)
   312  
   313  	s.localFeature.CleanRemoteDeviceCaches(address)
   314  
   315  	value = s.localFeature.HasSubscriptionToRemote(s.remote2Feature.Address())
   316  	assert.True(s.T(), value)
   317  
   318  	value = s.localFeature.HasSubscriptionToRemote(s.remoteFeature.Address())
   319  	assert.False(s.T(), value)
   320  
   321  	value = s.localFeature.HasSubscriptionToRemote(s.remoteSubFeature.Address())
   322  	assert.False(s.T(), value)
   323  
   324  	value = s.localFeature.HasBindingToRemote(s.remote2Feature.Address())
   325  	assert.True(s.T(), value)
   326  
   327  	value = s.localFeature.HasBindingToRemote(s.remoteFeature.Address())
   328  	assert.False(s.T(), value)
   329  
   330  	value = s.localFeature.HasBindingToRemote(s.remoteSubFeature.Address())
   331  	assert.False(s.T(), value)
   332  }
   333  
   334  func (s *LocalFeatureTestSuite) Test_CleanRemoteEntityCaches() {
   335  	s.senderMock.On("Subscribe", mock.Anything, mock.Anything, mock.Anything).Return(&s.msgCounter, nil)
   336  	s.senderMock.On("Bind", mock.Anything, mock.Anything, mock.Anything).Return(&s.msgCounter, nil)
   337  
   338  	s.localFeature.CleanWriteApprovalCaches("testdummytest")
   339  	s.localFeature.CleanRemoteEntityCaches(nil)
   340  
   341  	address := &model.EntityAddressType{}
   342  	s.localFeature.CleanRemoteEntityCaches(address)
   343  
   344  	address.Device = util.Ptr(model.AddressDeviceType("dummy"))
   345  	s.localFeature.CleanRemoteEntityCaches(address)
   346  
   347  	address.Entity = []model.AddressEntityType{10}
   348  	s.localFeature.CleanRemoteEntityCaches(address)
   349  
   350  	address.Device = s.remoteFeature.Address().Device
   351  	s.localFeature.CleanRemoteEntityCaches(address)
   352  
   353  	address.Entity = s.remoteFeature.Address().Entity
   354  	s.localFeature.CleanRemoteEntityCaches(address)
   355  
   356  	s.localFeature.Device().AddRemoteDeviceForSki(s.remoteFeature.Device().Ski(), s.remoteFeature.Device())
   357  
   358  	msgCounter, err := s.localFeature.SubscribeToRemote(s.remoteFeature.Address())
   359  	assert.Nil(s.T(), err)
   360  	assert.NotNil(s.T(), msgCounter)
   361  
   362  	msgCounter, err = s.localFeature.SubscribeToRemote(s.remoteSubFeature.Address())
   363  	assert.Nil(s.T(), err)
   364  	assert.NotNil(s.T(), msgCounter)
   365  
   366  	binding := s.localFeature.HasSubscriptionToRemote(s.remoteFeature.Address())
   367  	assert.True(s.T(), binding)
   368  
   369  	binding = s.localFeature.HasSubscriptionToRemote(s.remoteSubFeature.Address())
   370  	assert.True(s.T(), binding)
   371  
   372  	msgCounter, err = s.localFeature.BindToRemote(s.remoteFeature.Address())
   373  	assert.Nil(s.T(), err)
   374  	assert.NotNil(s.T(), msgCounter)
   375  
   376  	msgCounter, err = s.localFeature.BindToRemote(s.remoteSubFeature.Address())
   377  	assert.Nil(s.T(), err)
   378  	assert.NotNil(s.T(), msgCounter)
   379  
   380  	binding = s.localFeature.HasBindingToRemote(s.remoteFeature.Address())
   381  	assert.True(s.T(), binding)
   382  
   383  	binding = s.localFeature.HasBindingToRemote(s.remoteSubFeature.Address())
   384  	assert.True(s.T(), binding)
   385  
   386  	s.localFeature.CleanRemoteEntityCaches(address)
   387  
   388  	binding = s.localFeature.HasSubscriptionToRemote(s.remoteFeature.Address())
   389  	assert.False(s.T(), binding)
   390  
   391  	binding = s.localFeature.HasSubscriptionToRemote(s.remoteSubFeature.Address())
   392  	assert.True(s.T(), binding)
   393  
   394  	binding = s.localFeature.HasBindingToRemote(s.remoteFeature.Address())
   395  	assert.False(s.T(), binding)
   396  
   397  	binding = s.localFeature.HasBindingToRemote(s.remoteSubFeature.Address())
   398  	assert.True(s.T(), binding)
   399  }
   400  
   401  func (s *LocalFeatureTestSuite) Test_HandleMessage() {
   402  	msg := &api.Message{
   403  		FeatureRemote: s.remoteServerFeature,
   404  		CmdClassifier: model.CmdClassifierType("buggy"),
   405  		Cmd:           model.CmdType{},
   406  	}
   407  
   408  	err := s.localFeature.HandleMessage(msg)
   409  	assert.NotNil(s.T(), err)
   410  
   411  	msg = &api.Message{
   412  		FeatureRemote: s.remoteServerFeature,
   413  		CmdClassifier: model.CmdClassifierType("buggy"),
   414  		Cmd: model.CmdType{
   415  			ResultData: &model.ResultDataType{},
   416  		},
   417  	}
   418  
   419  	err = s.localFeature.HandleMessage(msg)
   420  	assert.NotNil(s.T(), err)
   421  }
   422  
   423  func (s *LocalFeatureTestSuite) Test_Result() {
   424  	msg := &api.Message{
   425  		FeatureRemote: s.remoteServerFeature,
   426  		CmdClassifier: model.CmdClassifierTypeResult,
   427  		Cmd: model.CmdType{
   428  			ResultData: &model.ResultDataType{},
   429  		},
   430  	}
   431  
   432  	err := s.localFeature.HandleMessage(msg)
   433  	assert.NotNil(s.T(), err)
   434  
   435  	msg.RequestHeader = &model.HeaderType{
   436  		MsgCounterReference: util.Ptr(model.MsgCounterType(100)),
   437  	}
   438  	msg.Cmd.ResultData = &model.ResultDataType{
   439  		ErrorNumber: util.Ptr(model.ErrorNumberType(1)),
   440  		Description: util.Ptr(model.DescriptionType("test")),
   441  	}
   442  	err = s.localFeature.HandleMessage(msg)
   443  	assert.Nil(s.T(), err)
   444  }
   445  
   446  func (s *LocalFeatureTestSuite) Test_Read() {
   447  	msg := &api.Message{
   448  		FeatureRemote: s.remoteFeature,
   449  		CmdClassifier: model.CmdClassifierTypeRead,
   450  		Cmd: model.CmdType{
   451  			LoadControlLimitListData: &model.LoadControlLimitListDataType{},
   452  		},
   453  	}
   454  
   455  	err := s.localFeature.HandleMessage(msg)
   456  	assert.NotNil(s.T(), err)
   457  
   458  	s.senderMock.EXPECT().Reply(mock.Anything, mock.Anything, mock.Anything).Return(errors.New("test")).Once()
   459  	err = s.localServerFeature.HandleMessage(msg)
   460  	assert.NotNil(s.T(), err)
   461  
   462  	msg = &api.Message{
   463  		FeatureRemote: s.remoteFeature,
   464  		CmdClassifier: model.CmdClassifierTypeRead,
   465  		Cmd: model.CmdType{
   466  			DeviceClassificationManufacturerData: &model.DeviceClassificationManufacturerDataType{},
   467  		},
   468  	}
   469  	err = s.localFeature.HandleMessage(msg)
   470  	assert.NotNil(s.T(), err)
   471  
   472  	s.senderMock.EXPECT().Reply(mock.Anything, mock.Anything, mock.Anything).Return(errors.New("test"))
   473  	err = s.localServerFeature.HandleMessage(msg)
   474  	assert.NotNil(s.T(), err)
   475  }
   476  
   477  func (s *LocalFeatureTestSuite) Test_Reply() {
   478  	msg := &api.Message{
   479  		FeatureRemote: s.remoteServerFeature,
   480  		CmdClassifier: model.CmdClassifierTypeReply,
   481  		Cmd: model.CmdType{
   482  			DeviceClassificationManufacturerData: &model.DeviceClassificationManufacturerDataType{},
   483  		},
   484  	}
   485  
   486  	err := s.localFeature.HandleMessage(msg)
   487  	assert.Nil(s.T(), err)
   488  
   489  	msg.RequestHeader = &model.HeaderType{
   490  		MsgCounterReference: util.Ptr(model.MsgCounterType(100)),
   491  	}
   492  	err = s.localFeature.HandleMessage(msg)
   493  	assert.Nil(s.T(), err)
   494  }
   495  
   496  func (s *LocalFeatureTestSuite) Test_Notify() {
   497  	msg := &api.Message{
   498  		FeatureRemote: s.remoteServerFeature,
   499  		CmdClassifier: model.CmdClassifierTypeNotify,
   500  		Cmd: model.CmdType{
   501  			DeviceClassificationManufacturerData: &model.DeviceClassificationManufacturerDataType{},
   502  		},
   503  	}
   504  
   505  	err := s.localFeature.HandleMessage(msg)
   506  	assert.Nil(s.T(), err)
   507  }
   508  
   509  func (s *LocalFeatureTestSuite) Test_Write() {
   510  	s.senderMock.EXPECT().ResultSuccess(mock.Anything, mock.Anything).Return(nil).Once()
   511  
   512  	msg := &api.Message{
   513  		RequestHeader: &model.HeaderType{
   514  			MsgCounter: util.Ptr(model.MsgCounterType(1)),
   515  			AckRequest: util.Ptr(true),
   516  		},
   517  		CmdClassifier: model.CmdClassifierTypeWrite,
   518  		FeatureRemote: s.remoteSubFeature,
   519  		Cmd: model.CmdType{
   520  			LoadControlLimitListData: &model.LoadControlLimitListDataType{},
   521  		},
   522  	}
   523  
   524  	err := s.localServerFeatureWrite.HandleMessage(msg)
   525  	assert.Nil(s.T(), err)
   526  }
   527  
   528  func (s *LocalFeatureTestSuite) Test_SetWriteApprovalCallback_Invalid() {
   529  	cb := func(msg *api.Message) {}
   530  	err := s.localFeature.AddWriteApprovalCallback(cb)
   531  	assert.NotNil(s.T(), err)
   532  	result := model.ErrorType{
   533  		ErrorNumber: 0,
   534  	}
   535  	s.localFeature.ApproveOrDenyWrite(&api.Message{}, result)
   536  }
   537  
   538  func (s *LocalFeatureTestSuite) Test_AddPendingApproval_Invalid() {
   539  	cb := func(msg *api.Message) {}
   540  	err := s.localServerFeatureWrite.AddWriteApprovalCallback(cb)
   541  	assert.Nil(s.T(), err)
   542  
   543  	msg := &api.Message{
   544  		CmdClassifier: model.CmdClassifierTypeWrite,
   545  		FeatureRemote: s.remoteSubFeature,
   546  		Cmd: model.CmdType{
   547  			LoadControlLimitListData: &model.LoadControlLimitListDataType{},
   548  		},
   549  	}
   550  
   551  	err1 := s.localServerFeatureWrite.HandleMessage(msg)
   552  	assert.Nil(s.T(), err1)
   553  }
   554  
   555  func (s *LocalFeatureTestSuite) Test_Write_Callback_One() {
   556  	counter := model.MsgCounterType(1)
   557  	msg := &api.Message{
   558  		RequestHeader: &model.HeaderType{
   559  			MsgCounter: util.Ptr(counter),
   560  			AckRequest: util.Ptr(true),
   561  		},
   562  		CmdClassifier: model.CmdClassifierTypeWrite,
   563  		FeatureRemote: s.remoteSubFeature,
   564  		DeviceRemote:  s.remoteSubFeature.Device(),
   565  		Cmd: model.CmdType{
   566  			LoadControlLimitListData: &model.LoadControlLimitListDataType{},
   567  		},
   568  	}
   569  
   570  	tempLSFWrite := s.localServerFeatureWrite
   571  
   572  	cb1 := func(msg *api.Message) {
   573  		result := model.ErrorType{
   574  			ErrorNumber: 0,
   575  		}
   576  		tempLSFWrite.ApproveOrDenyWrite(msg, result)
   577  	}
   578  	tempLSFWrite.AddWriteApprovalCallback(cb1)
   579  
   580  	s.senderMock.EXPECT().ResultSuccess(mock.Anything, mock.Anything).Return(nil).Once()
   581  	err := tempLSFWrite.HandleMessage(msg)
   582  	assert.Nil(s.T(), err)
   583  
   584  	// callback is called asynchronously
   585  	time.Sleep(time.Millisecond * 200)
   586  }
   587  
   588  func (s *LocalFeatureTestSuite) Test_Write_Callback_One_Fail() {
   589  	counter := model.MsgCounterType(1)
   590  	msg := &api.Message{
   591  		RequestHeader: &model.HeaderType{
   592  			MsgCounter: util.Ptr(counter),
   593  			AckRequest: util.Ptr(true),
   594  		},
   595  		CmdClassifier: model.CmdClassifierTypeWrite,
   596  		FeatureRemote: s.remoteSubFeature,
   597  		DeviceRemote:  s.remoteSubFeature.Device(),
   598  		Cmd: model.CmdType{
   599  			LoadControlLimitListData: &model.LoadControlLimitListDataType{},
   600  		},
   601  	}
   602  
   603  	tempLSFWrite := s.localServerFeatureWrite
   604  
   605  	cb1 := func(msg *api.Message) {
   606  		result := model.ErrorType{
   607  			ErrorNumber: 7,
   608  			Description: util.Ptr(model.DescriptionType("not allowed by application")),
   609  		}
   610  		tempLSFWrite.ApproveOrDenyWrite(msg, result)
   611  	}
   612  	tempLSFWrite.AddWriteApprovalCallback(cb1)
   613  
   614  	s.senderMock.EXPECT().ResultError(mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
   615  	err := tempLSFWrite.HandleMessage(msg)
   616  	assert.Nil(s.T(), err)
   617  
   618  	// callback is called asynchronously
   619  	time.Sleep(time.Millisecond * 200)
   620  }
   621  
   622  func (s *LocalFeatureTestSuite) Test_Write_Callback_Two() {
   623  	msg := &api.Message{
   624  		RequestHeader: &model.HeaderType{
   625  			MsgCounter: util.Ptr(model.MsgCounterType(1)),
   626  			AckRequest: util.Ptr(true),
   627  		},
   628  		CmdClassifier: model.CmdClassifierTypeWrite,
   629  		FeatureRemote: s.remoteSubFeature,
   630  		DeviceRemote:  s.remoteSubFeature.Device(),
   631  		Cmd: model.CmdType{
   632  			LoadControlLimitListData: &model.LoadControlLimitListDataType{},
   633  		},
   634  	}
   635  
   636  	tempLSFWrite := s.localServerFeatureWrite
   637  
   638  	cb1 := func(msg *api.Message) {
   639  		result := model.ErrorType{
   640  			ErrorNumber: 0,
   641  		}
   642  		tempLSFWrite.ApproveOrDenyWrite(msg, result)
   643  	}
   644  	tempLSFWrite.AddWriteApprovalCallback(cb1)
   645  
   646  	cb2 := func(msg *api.Message) {
   647  		result := model.ErrorType{
   648  			ErrorNumber: 0,
   649  		}
   650  		tempLSFWrite.ApproveOrDenyWrite(msg, result)
   651  	}
   652  	tempLSFWrite.AddWriteApprovalCallback(cb2)
   653  
   654  	s.senderMock.EXPECT().ResultSuccess(mock.Anything, mock.Anything).Return(nil).Once()
   655  	err := tempLSFWrite.HandleMessage(msg)
   656  	assert.Nil(s.T(), err)
   657  
   658  	// callback is called asynchronously
   659  	time.Sleep(time.Millisecond * 200)
   660  }
   661  
   662  func (s *LocalFeatureTestSuite) Test_Write_Callback_Two_Fail() {
   663  	msg := &api.Message{
   664  		RequestHeader: &model.HeaderType{
   665  			MsgCounter: util.Ptr(model.MsgCounterType(1)),
   666  			AckRequest: util.Ptr(true),
   667  		},
   668  		CmdClassifier: model.CmdClassifierTypeWrite,
   669  		FeatureRemote: s.remoteSubFeature,
   670  		DeviceRemote:  s.remoteSubFeature.Device(),
   671  		Cmd: model.CmdType{
   672  			LoadControlLimitListData: &model.LoadControlLimitListDataType{},
   673  		},
   674  	}
   675  
   676  	tempLSFWrite := s.localServerFeatureWrite
   677  
   678  	cb1 := func(msg *api.Message) {
   679  		result := model.ErrorType{
   680  			ErrorNumber: 0,
   681  		}
   682  		tempLSFWrite.ApproveOrDenyWrite(msg, result)
   683  	}
   684  	tempLSFWrite.AddWriteApprovalCallback(cb1)
   685  
   686  	cb2 := func(msg *api.Message) {
   687  		result := model.ErrorType{
   688  			ErrorNumber: 7,
   689  			Description: util.Ptr(model.DescriptionType("not allowed by application")),
   690  		}
   691  		tempLSFWrite.ApproveOrDenyWrite(msg, result)
   692  	}
   693  	tempLSFWrite.AddWriteApprovalCallback(cb2)
   694  
   695  	s.senderMock.EXPECT().ResultError(mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
   696  
   697  	err := tempLSFWrite.HandleMessage(msg)
   698  	assert.Nil(s.T(), err)
   699  
   700  	// callback is called asynchronously
   701  	time.Sleep(time.Millisecond * 200)
   702  }
   703  
   704  func (s *LocalFeatureTestSuite) Test_Write_Callback_Timeout() {
   705  	s.localServerFeatureWrite.SetWriteApprovalTimeout(time.Millisecond * 500)
   706  
   707  	s.senderMock.EXPECT().ResultError(mock.Anything, mock.Anything, mock.Anything).Return(nil).Once()
   708  
   709  	msg := &api.Message{
   710  		RequestHeader: &model.HeaderType{
   711  			MsgCounter: util.Ptr(model.MsgCounterType(1)),
   712  			AckRequest: util.Ptr(true),
   713  		},
   714  		CmdClassifier: model.CmdClassifierTypeWrite,
   715  		FeatureRemote: s.remoteSubFeature,
   716  		DeviceRemote:  s.remoteSubFeature.Device(),
   717  		Cmd: model.CmdType{
   718  			LoadControlLimitListData: &model.LoadControlLimitListDataType{},
   719  		},
   720  	}
   721  
   722  	tempLSFWrite := s.localServerFeatureWrite
   723  
   724  	cb := func(msg *api.Message) {
   725  		time.Sleep(time.Second * 1)
   726  		result := model.ErrorType{
   727  			ErrorNumber: 0,
   728  		}
   729  		tempLSFWrite.ApproveOrDenyWrite(msg, result)
   730  	}
   731  
   732  	tempLSFWrite.AddWriteApprovalCallback(cb)
   733  	err := tempLSFWrite.HandleMessage(msg)
   734  	assert.Nil(s.T(), err)
   735  
   736  	// callback is called asynchronously
   737  	time.Sleep(time.Second * 1)
   738  }
   739  
   740  func (s *LocalFeatureTestSuite) Test_Set_Update() {
   741  	partial := model.NewFilterTypePartial()
   742  
   743  	noData := s.localServerFeatureWrite.DataCopy("dummy")
   744  	assert.Nil(s.T(), noData)
   745  
   746  	data := &model.LoadControlLimitListDataType{
   747  		LoadControlLimitData: []model.LoadControlLimitDataType{
   748  			{
   749  				LimitId:       util.Ptr(model.LoadControlLimitIdType(1)),
   750  				IsLimitActive: util.Ptr(false),
   751  			},
   752  		},
   753  	}
   754  
   755  	s.localServerFeatureWrite.SetData(s.serverWriteFunction, data)
   756  
   757  	dataCopy := s.localServerFeatureWrite.DataCopy(s.serverWriteFunction)
   758  	equal := reflect.DeepEqual(data, dataCopy)
   759  	assert.True(s.T(), equal)
   760  
   761  	newData := &model.LoadControlLimitListDataType{
   762  		LoadControlLimitData: []model.LoadControlLimitDataType{
   763  			{
   764  				LimitId:       util.Ptr(model.LoadControlLimitIdType(1)),
   765  				IsLimitActive: util.Ptr(true),
   766  			},
   767  		},
   768  	}
   769  
   770  	err := s.localServerFeatureWrite.UpdateData(s.serverWriteFunction, newData, nil, nil)
   771  	assert.Nil(s.T(), err)
   772  
   773  	dataCopy = s.localServerFeatureWrite.DataCopy(s.serverWriteFunction)
   774  	equal = reflect.DeepEqual(data, dataCopy)
   775  	assert.False(s.T(), equal)
   776  
   777  	newData = &model.LoadControlLimitListDataType{
   778  		LoadControlLimitData: []model.LoadControlLimitDataType{
   779  			{
   780  				LimitId:           util.Ptr(model.LoadControlLimitIdType(1)),
   781  				IsLimitActive:     util.Ptr(true),
   782  				IsLimitChangeable: util.Ptr(true),
   783  			},
   784  		},
   785  	}
   786  	err = s.localServerFeatureWrite.UpdateData(s.serverWriteFunction, newData, partial, nil)
   787  	assert.Nil(s.T(), err)
   788  
   789  	dataCopy = s.localServerFeatureWrite.DataCopy(s.serverWriteFunction)
   790  	modelData, ok := dataCopy.(*model.LoadControlLimitListDataType)
   791  	assert.True(s.T(), ok)
   792  	assert.Equal(s.T(), 1, len(modelData.LoadControlLimitData))
   793  	assert.Equal(s.T(), model.LoadControlLimitIdType(1), *modelData.LoadControlLimitData[0].LimitId)
   794  	assert.True(s.T(), *modelData.LoadControlLimitData[0].IsLimitActive)
   795  	assert.True(s.T(), *modelData.LoadControlLimitData[0].IsLimitChangeable)
   796  
   797  	moreData := &model.LoadControlLimitListDataType{
   798  		LoadControlLimitData: []model.LoadControlLimitDataType{
   799  			{
   800  				LimitId:           util.Ptr(model.LoadControlLimitIdType(2)),
   801  				IsLimitActive:     util.Ptr(false),
   802  				IsLimitChangeable: util.Ptr(false),
   803  			},
   804  		},
   805  	}
   806  	err = s.localServerFeatureWrite.UpdateData(s.serverWriteFunction, moreData, partial, nil)
   807  	assert.Nil(s.T(), err)
   808  
   809  	dataCopy = s.localServerFeatureWrite.DataCopy(s.serverWriteFunction)
   810  	modelData, ok = dataCopy.(*model.LoadControlLimitListDataType)
   811  	assert.True(s.T(), ok)
   812  	assert.Equal(s.T(), 2, len(modelData.LoadControlLimitData))
   813  	assert.Equal(s.T(), model.LoadControlLimitIdType(2), *modelData.LoadControlLimitData[1].LimitId)
   814  	assert.False(s.T(), *modelData.LoadControlLimitData[1].IsLimitActive)
   815  	assert.False(s.T(), *modelData.LoadControlLimitData[1].IsLimitChangeable)
   816  
   817  	updateData := &model.LoadControlLimitListDataType{
   818  		LoadControlLimitData: []model.LoadControlLimitDataType{
   819  			{
   820  				LimitId:           util.Ptr(model.LoadControlLimitIdType(2)),
   821  				IsLimitChangeable: util.Ptr(true),
   822  				TimePeriod:        model.NewTimePeriodTypeWithRelativeEndTime(time.Minute * 2),
   823  			},
   824  		},
   825  	}
   826  	err = s.localServerFeatureWrite.UpdateData(s.serverWriteFunction, updateData, partial, nil)
   827  	assert.Nil(s.T(), err)
   828  
   829  	dataCopy = s.localServerFeatureWrite.DataCopy(s.serverWriteFunction)
   830  	modelData, ok = dataCopy.(*model.LoadControlLimitListDataType)
   831  	assert.True(s.T(), ok)
   832  	assert.Equal(s.T(), 2, len(modelData.LoadControlLimitData))
   833  	assert.Equal(s.T(), model.LoadControlLimitIdType(2), *modelData.LoadControlLimitData[1].LimitId)
   834  	assert.False(s.T(), *modelData.LoadControlLimitData[1].IsLimitActive)
   835  	assert.True(s.T(), *modelData.LoadControlLimitData[1].IsLimitChangeable)
   836  	assert.NotNil(s.T(), modelData.LoadControlLimitData[1].TimePeriod)
   837  
   838  	deleteFilter := &model.FilterType{
   839  		LoadControlLimitListDataSelectors: &model.LoadControlLimitListDataSelectorsType{
   840  			LimitId: util.Ptr(model.LoadControlLimitIdType(2)),
   841  		},
   842  		LoadControlLimitDataElements: &model.LoadControlLimitDataElementsType{
   843  			TimePeriod: &model.TimePeriodElementsType{},
   844  		},
   845  	}
   846  	updateData = &model.LoadControlLimitListDataType{
   847  		LoadControlLimitData: []model.LoadControlLimitDataType{
   848  			{
   849  				LimitId:           util.Ptr(model.LoadControlLimitIdType(2)),
   850  				IsLimitChangeable: util.Ptr(false),
   851  			},
   852  		},
   853  	}
   854  	err = s.localServerFeatureWrite.UpdateData(s.serverWriteFunction, updateData, partial, deleteFilter)
   855  	assert.Nil(s.T(), err)
   856  
   857  	dataCopy = s.localServerFeatureWrite.DataCopy(s.serverWriteFunction)
   858  	modelData, ok = dataCopy.(*model.LoadControlLimitListDataType)
   859  	assert.True(s.T(), ok)
   860  	assert.Equal(s.T(), 2, len(modelData.LoadControlLimitData))
   861  	assert.False(s.T(), *modelData.LoadControlLimitData[1].IsLimitChangeable)
   862  	assert.Nil(s.T(), modelData.LoadControlLimitData[1].TimePeriod)
   863  }