From cb8495e54c79a324a2824a1387fede99b7131453 Mon Sep 17 00:00:00 2001 From: Chris Hung Date: Tue, 27 Apr 2021 15:53:06 +0800 Subject: [PATCH 1/4] refactor: remove v2 naming Signed-off-by: Chris Hung --- internal/cache/init.go | 4 ++-- pkg/service/init.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/cache/init.go b/internal/cache/init.go index cd4580915..7539b5820 100644 --- a/internal/cache/init.go +++ b/internal/cache/init.go @@ -17,8 +17,8 @@ import ( "github.com/edgexfoundry/device-sdk-go/v2/internal/container" ) -// Init basic state for cache -func InitV2Cache(name string, dic *di.Container) errors.EdgeX { +// InitCache Init basic state for cache +func InitCache(name string, dic *di.Container) errors.EdgeX { dc := container.MetadataDeviceClientFrom(dic.Get) dpc := container.MetadataDeviceProfileClientFrom(dic.Get) pwc := container.MetadataProvisionWatcherClientFrom(dic.Get) diff --git a/pkg/service/init.go b/pkg/service/init.go index bc95637ba..f15a6566a 100644 --- a/pkg/service/init.go +++ b/pkg/service/init.go @@ -37,7 +37,7 @@ func (b *Bootstrap) BootstrapHandler(ctx context.Context, wg *sync.WaitGroup, st ds.wg = wg ds.controller.InitRestRoutes() - err := cache.InitV2Cache(ds.ServiceName, dic) + err := cache.InitCache(ds.ServiceName, dic) if err != nil { ds.LoggingClient.Errorf("Failed to init cache: %v", err) return false From c70a8bb10cb4393cef03f61de88657b7cff20aea Mon Sep 17 00:00:00 2001 From: Chris Hung Date: Tue, 27 Apr 2021 16:08:10 +0800 Subject: [PATCH 2/4] test: add unit tests for application package Signed-off-by: Chris Hung --- internal/application/command_test.go | 289 +++++++++++++++++++++++++++ pkg/models/mocks/ProtocolDriver.go | 124 ++++++++++++ 2 files changed, 413 insertions(+) create mode 100644 internal/application/command_test.go create mode 100644 pkg/models/mocks/ProtocolDriver.go diff --git a/internal/application/command_test.go b/internal/application/command_test.go new file mode 100644 index 000000000..fb88d1412 --- /dev/null +++ b/internal/application/command_test.go @@ -0,0 +1,289 @@ +// +// Copyright (C) 2021 IOTech Ltd +// +// SPDX-License-Identifier: Apache-2.0 + +package application + +import ( + "context" + "testing" + + bootstrapContainer "github.com/edgexfoundry/go-mod-bootstrap/v2/bootstrap/container" + "github.com/edgexfoundry/go-mod-bootstrap/v2/di" + "github.com/edgexfoundry/go-mod-core-contracts/v2/clients/logger" + clientMocks "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/clients/interfaces/mocks" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos/common" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos/responses" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/models" + "github.com/google/uuid" + "github.com/stretchr/testify/require" + + "github.com/edgexfoundry/device-sdk-go/v2/internal/cache" + "github.com/edgexfoundry/device-sdk-go/v2/internal/config" + "github.com/edgexfoundry/device-sdk-go/v2/internal/container" + sdkModels "github.com/edgexfoundry/device-sdk-go/v2/pkg/models" + "github.com/edgexfoundry/device-sdk-go/v2/pkg/models/mocks" +) + +var testProtocols map[string]models.ProtocolProperties + +var testDevice = models.Device{ + Name: "test-device", + AdminState: models.Unlocked, + OperatingState: models.Up, + Protocols: testProtocols, + ServiceName: "test-service", + ProfileName: "test-profile", +} + +func mockDic() *di.Container { + driverMock := &mocks.ProtocolDriver{} + cr := sdkModels.CommandRequest{ + DeviceResourceName: "test-resource", + Attributes: nil, + Type: "String", + } + cv := &sdkModels.CommandValue{ + DeviceResourceName: "test-resource", + Type: "String", + Value: "test-value", + } + driverMock.On("HandleReadCommands", "test-device", testProtocols, []sdkModels.CommandRequest{cr}).Return(nil, nil) + driverMock.On("HandleWriteCommands", "test-device", testProtocols, []sdkModels.CommandRequest{cr}, []*sdkModels.CommandValue{cv}).Return(nil) + + devices := responses.MultiDevicesResponse{ + BaseResponse: common.BaseResponse{}, + Devices: []dtos.Device{ + dtos.FromDeviceModelToDTO(testDevice), + }, + } + dcMock := &clientMocks.DeviceClient{} + dcMock.On("DevicesByServiceName", context.Background(), "test-service", 0, -1).Return(devices, nil) + + profile := responses.DeviceProfileResponse{ + BaseResponse: common.BaseResponse{}, + Profile: dtos.DeviceProfile{ + Name: "test-profile", + DeviceResources: []dtos.DeviceResource{ + dtos.DeviceResource{ + Name: "test-resource", + Properties: dtos.ResourceProperties{ + ValueType: "String", + ReadWrite: "RW", + DefaultValue: "test-value", + }, + }, + dtos.DeviceResource{ + Name: "ro-resource", + Properties: dtos.ResourceProperties{ + ValueType: "String", + ReadWrite: "R", + }, + }, + dtos.DeviceResource{ + Name: "wo-resource", + Properties: dtos.ResourceProperties{ + ValueType: "String", + ReadWrite: "W", + }, + }, + }, + DeviceCommands: []dtos.DeviceCommand{ + dtos.DeviceCommand{ + Name: "test-command", + IsHidden: false, + ReadWrite: "RW", + ResourceOperations: []dtos.ResourceOperation{{DeviceResource: "test-resource"}}, + }, + dtos.DeviceCommand{ + Name: "ro-command", + IsHidden: false, + ReadWrite: "R", + ResourceOperations: []dtos.ResourceOperation{{DeviceResource: "ro-resource"}}, + }, + dtos.DeviceCommand{ + Name: "wo-command", + IsHidden: false, + ReadWrite: "W", + ResourceOperations: []dtos.ResourceOperation{{DeviceResource: "wo-resource"}}, + }, + dtos.DeviceCommand{ + Name: "exceed-command", + IsHidden: false, + ReadWrite: "R", + ResourceOperations: []dtos.ResourceOperation{{DeviceResource: "test-resource"}, {DeviceResource: "ro-resource"}}, + }, + }, + }, + } + dpcMock := &clientMocks.DeviceProfileClient{} + dpcMock.On("DeviceProfileByName", context.Background(), "test-profile").Return(profile, nil) + + pwcMock := &clientMocks.ProvisionWatcherClient{} + pwcMock.On("ProvisionWatchersByServiceName", context.Background(), "test-service", 0, -1).Return(responses.MultiProvisionWatchersResponse{}, nil) + + configuration := &config.ConfigurationStruct{ + Device: config.DeviceInfo{MaxCmdOps: 1}, + } + + dic := di.NewContainer(di.ServiceConstructorMap{ + bootstrapContainer.LoggingClientInterfaceName: func(get di.Get) interface{} { + return logger.NewMockClient() + }, + container.ProtocolDriverName: func(get di.Get) interface{} { + return driverMock + }, + container.MetadataDeviceClientName: func(get di.Get) interface{} { + return dcMock + }, + container.MetadataDeviceProfileClientName: func(get di.Get) interface{} { + return dpcMock + }, + container.MetadataProvisionWatcherClientName: func(get di.Get) interface{} { + return pwcMock + }, + container.ConfigurationName: func(get di.Get) interface{} { + return configuration + }, + }) + + return dic +} + +func TestCommandProcessor_ReadDeviceResource(t *testing.T) { + dic := mockDic() + err := cache.InitCache("test-service", dic) + require.NoError(t, err) + + valid := NewCommandProcessor(testDevice, "test-resource", uuid.NewString(), "", "", dic) + invalidDeviceResource := NewCommandProcessor(testDevice, "invalid", uuid.NewString(), "", "", dic) + writeOnlyDeviceResource := NewCommandProcessor(testDevice, "wo-resource", uuid.NewString(), "", "", dic) + + tests := []struct { + name string + commandProcessor *CommandProcessor + expectedErr bool + }{ + {"valid", valid, false}, + {"invalid - DeviceResource name not found", invalidDeviceResource, true}, + {"invalid - reading write-only DeviceResource", writeOnlyDeviceResource, true}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := tt.commandProcessor.ReadDeviceResource() + if tt.expectedErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + }) + } +} + +func TestCommandProcessor_ReadDeviceCommand(t *testing.T) { + dic := mockDic() + err := cache.InitCache("test-service", dic) + require.NoError(t, err) + + valid := NewCommandProcessor(testDevice, "test-command", uuid.NewString(), "", "", dic) + invalidDeviceCommand := NewCommandProcessor(testDevice, "invalid", uuid.NewString(), "", "", dic) + writeOnlyDeviceCommand := NewCommandProcessor(testDevice, "wo-command", uuid.NewString(), "", "", dic) + outOfRangeResourceOperation := NewCommandProcessor(testDevice, "exceed-command", uuid.NewString(), "", "", dic) + + tests := []struct { + name string + commandProcessor *CommandProcessor + expectedErr bool + }{ + {"valid", valid, false}, + {"invalid - DeviceCommand name not found", invalidDeviceCommand, true}, + {"invalid - reading write-only DeviceCommand", writeOnlyDeviceCommand, true}, + {"invalid - RO exceed MaxCmdOps count", outOfRangeResourceOperation, true}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := tt.commandProcessor.ReadDeviceCommand() + if tt.expectedErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + }) + } +} + +func TestCommandProcessor_WriteDeviceResource(t *testing.T) { + dic := mockDic() + err := cache.InitCache("test-service", dic) + require.NoError(t, err) + + valid := NewCommandProcessor(testDevice, "test-resource", uuid.NewString(), "{\"test-resource\":\"test-value\"}", "", dic) + invalidDeviceResource := NewCommandProcessor(testDevice, "invalid", uuid.NewString(), "", "", dic) + readOnlyDeviceResource := NewCommandProcessor(testDevice, "ro-resource", uuid.NewString(), "", "", dic) + noRequestBody := NewCommandProcessor(testDevice, "test-resource", uuid.NewString(), "", "", dic) + invalidRequestBody := NewCommandProcessor(testDevice, "test-resource", uuid.NewString(), "{\"wrong-resource\":\"wrong-value\"}", "", dic) + + tests := []struct { + name string + commandProcessor *CommandProcessor + expectedErr bool + }{ + {"valid", valid, false}, + {"invalid - DeviceResource name not found", invalidDeviceResource, true}, + {"invalid - writing read-only DeviceResource", readOnlyDeviceResource, true}, + {"invalid - no set parameter(body) specified", noRequestBody, true}, + {"valid - parameter(body) doesn't match requested command, using DefaultValue in DeviceResource.Properties", invalidRequestBody, false}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err = tt.commandProcessor.WriteDeviceResource() + if tt.expectedErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + }) + } +} + +func TestCommandProcessor_WriteDeviceCommand(t *testing.T) { + dic := mockDic() + err := cache.InitCache("test-service", dic) + require.NoError(t, err) + + valid := NewCommandProcessor(testDevice, "test-command", uuid.NewString(), "{\"test-resource\":\"test-value\"}", "", dic) + invalidDeviceCommand := NewCommandProcessor(testDevice, "invalid", uuid.NewString(), "", "", dic) + readOnlyDeviceCommand := NewCommandProcessor(testDevice, "ro-command", uuid.NewString(), "", "", dic) + outOfRangeResourceOperation := NewCommandProcessor(testDevice, "exceed-command", uuid.NewString(), "", "", dic) + noRequestBody := NewCommandProcessor(testDevice, "test-command", uuid.NewString(), "", "", dic) + invalidRequestBody := NewCommandProcessor(testDevice, "test-command", uuid.NewString(), "{\"wrong-resource\":\"wrong-value\"}", "", dic) + + tests := []struct { + name string + commandProcessor *CommandProcessor + expectedErr bool + }{ + {"valid", valid, false}, + {"invalid - DeviceCommand name not found", invalidDeviceCommand, true}, + {"invalid - writing read-only DeviceCommand", readOnlyDeviceCommand, true}, + {"invalid - RO exceed MaxCmdOps count", outOfRangeResourceOperation, true}, + {"invalid - no set parameter(body) specified", noRequestBody, true}, + {"valid - parameter(body) doesn't match requested command, using DefaultValue in DeviceResource.Properties", invalidRequestBody, false}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err = tt.commandProcessor.WriteDeviceCommand() + if tt.expectedErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + }) + } +} diff --git a/pkg/models/mocks/ProtocolDriver.go b/pkg/models/mocks/ProtocolDriver.go new file mode 100644 index 000000000..3402844dd --- /dev/null +++ b/pkg/models/mocks/ProtocolDriver.go @@ -0,0 +1,124 @@ +// Code generated by mockery v0.0.0-dev. DO NOT EDIT. + +package mocks + +import ( + logger "github.com/edgexfoundry/go-mod-core-contracts/v2/clients/logger" + mock "github.com/stretchr/testify/mock" + + models "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/models" + + pkgmodels "github.com/edgexfoundry/device-sdk-go/v2/pkg/models" +) + +// ProtocolDriver is an autogenerated mock type for the ProtocolDriver type +type ProtocolDriver struct { + mock.Mock +} + +// AddDevice provides a mock function with given fields: deviceName, protocols, adminState +func (_m *ProtocolDriver) AddDevice(deviceName string, protocols map[string]models.ProtocolProperties, adminState models.AdminState) error { + ret := _m.Called(deviceName, protocols, adminState) + + var r0 error + if rf, ok := ret.Get(0).(func(string, map[string]models.ProtocolProperties, models.AdminState) error); ok { + r0 = rf(deviceName, protocols, adminState) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// HandleReadCommands provides a mock function with given fields: deviceName, protocols, reqs +func (_m *ProtocolDriver) HandleReadCommands(deviceName string, protocols map[string]models.ProtocolProperties, reqs []pkgmodels.CommandRequest) ([]*pkgmodels.CommandValue, error) { + ret := _m.Called(deviceName, protocols, reqs) + + var r0 []*pkgmodels.CommandValue + if rf, ok := ret.Get(0).(func(string, map[string]models.ProtocolProperties, []pkgmodels.CommandRequest) []*pkgmodels.CommandValue); ok { + r0 = rf(deviceName, protocols, reqs) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*pkgmodels.CommandValue) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(string, map[string]models.ProtocolProperties, []pkgmodels.CommandRequest) error); ok { + r1 = rf(deviceName, protocols, reqs) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// HandleWriteCommands provides a mock function with given fields: deviceName, protocols, reqs, params +func (_m *ProtocolDriver) HandleWriteCommands(deviceName string, protocols map[string]models.ProtocolProperties, reqs []pkgmodels.CommandRequest, params []*pkgmodels.CommandValue) error { + ret := _m.Called(deviceName, protocols, reqs, params) + + var r0 error + if rf, ok := ret.Get(0).(func(string, map[string]models.ProtocolProperties, []pkgmodels.CommandRequest, []*pkgmodels.CommandValue) error); ok { + r0 = rf(deviceName, protocols, reqs, params) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Initialize provides a mock function with given fields: lc, asyncCh, deviceCh +func (_m *ProtocolDriver) Initialize(lc logger.LoggingClient, asyncCh chan<- *pkgmodels.AsyncValues, deviceCh chan<- []pkgmodels.DiscoveredDevice) error { + ret := _m.Called(lc, asyncCh, deviceCh) + + var r0 error + if rf, ok := ret.Get(0).(func(logger.LoggingClient, chan<- *pkgmodels.AsyncValues, chan<- []pkgmodels.DiscoveredDevice) error); ok { + r0 = rf(lc, asyncCh, deviceCh) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// RemoveDevice provides a mock function with given fields: deviceName, protocols +func (_m *ProtocolDriver) RemoveDevice(deviceName string, protocols map[string]models.ProtocolProperties) error { + ret := _m.Called(deviceName, protocols) + + var r0 error + if rf, ok := ret.Get(0).(func(string, map[string]models.ProtocolProperties) error); ok { + r0 = rf(deviceName, protocols) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Stop provides a mock function with given fields: force +func (_m *ProtocolDriver) Stop(force bool) error { + ret := _m.Called(force) + + var r0 error + if rf, ok := ret.Get(0).(func(bool) error); ok { + r0 = rf(force) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// UpdateDevice provides a mock function with given fields: deviceName, protocols, adminState +func (_m *ProtocolDriver) UpdateDevice(deviceName string, protocols map[string]models.ProtocolProperties, adminState models.AdminState) error { + ret := _m.Called(deviceName, protocols, adminState) + + var r0 error + if rf, ok := ret.Get(0).(func(string, map[string]models.ProtocolProperties, models.AdminState) error); ok { + r0 = rf(deviceName, protocols, adminState) + } else { + r0 = ret.Error(0) + } + + return r0 +} From cfe61811f85c2f943cd98406491d5528ce573e40 Mon Sep 17 00:00:00 2001 From: Chris Hung Date: Wed, 28 Apr 2021 11:40:45 +0800 Subject: [PATCH 3/4] test: complement unit tests for CommandValue Signed-off-by: Chris Hung --- pkg/models/commandvalue_test.go | 685 +++++++++++++++++++++++++++++++- 1 file changed, 682 insertions(+), 3 deletions(-) diff --git a/pkg/models/commandvalue_test.go b/pkg/models/commandvalue_test.go index 15199f1ef..a80dbd440 100644 --- a/pkg/models/commandvalue_test.go +++ b/pkg/models/commandvalue_test.go @@ -8,14 +8,16 @@ package models import ( + "fmt" "math/rand" "testing" "github.com/edgexfoundry/go-mod-core-contracts/v2/v2" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) -func TestNewCommandValue(t *testing.T) { +func Test_validate(t *testing.T) { exceedBinary := make([]byte, MaxBinaryBytes+1) rand.Read(exceedBinary) tests := []struct { @@ -32,11 +34,688 @@ func TestNewCommandValue(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - _, err := NewCommandValue("test-resource", tt.valueType, tt.value) + err := validate(tt.valueType, tt.value) if tt.expectedErr { assert.Error(t, err) } else { - assert.Nil(t, err) + assert.NoError(t, err) + } + }) + } +} + +func TestCommandValue_ValueToString(t *testing.T) { + uintCommandValue, err := NewCommandValue("test-resource", v2.ValueTypeUint8, uint8(1)) + require.NoError(t, err) + intCommandValue, err := NewCommandValue("test-resource", v2.ValueTypeInt8, int8(-1)) + require.NoError(t, err) + floatCommandValue, err := NewCommandValue("test-resource", v2.ValueTypeFloat64, float64(123.456)) + require.NoError(t, err) + stringCommandValue, err := NewCommandValue("test-resource", v2.ValueTypeString, "string") + require.NoError(t, err) + boolCommandValue, err := NewCommandValue("test-resource", v2.ValueTypeBool, true) + require.NoError(t, err) + binaryValue := make([]byte, 100) + rand.Read(binaryValue) + binaryCommandValue, err := NewCommandValue("test-resource", v2.ValueTypeBinary, binaryValue) + require.NoError(t, err) + + tests := []struct { + name string + cv *CommandValue + expected string + }{ + {"valid - CommandValue with uint Value", uintCommandValue, "1"}, + {"valid - CommandValue with int Value", intCommandValue, "-1"}, + {"valid - CommandValue with float Value", floatCommandValue, "123.456"}, + {"valid - CommandValue with string Value", stringCommandValue, "string"}, + {"valid - CommandValue with boolean Value", boolCommandValue, "true"}, + {"valid - CommandValue with binary Value", binaryCommandValue, fmt.Sprintf("Binary: [%v...]", string(binaryValue[:20]))}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res := tt.cv.ValueToString() + assert.Equal(t, res, tt.expected) + }) + } +} + +func TestCommandValue_BoolValue(t *testing.T) { + valid := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeBool, Value: true} + invalidType := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeBinary, Value: true} + invalidValue := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeBool, Value: "true"} + + tests := []struct { + name string + cv *CommandValue + expected bool + expectedErr bool + }{ + {"valid - CommandValue with bool Value", valid, true, false}, + {"invalid - ValueType is not Bool", invalidType, true, true}, + {"invalid - Value is not boolean", invalidValue, true, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res, err := tt.cv.BoolValue() + if tt.expectedErr { + require.Error(t, err) + } else { + require.Equal(t, res, tt.expected) + } + }) + } +} + +func TestCommandValue_BoolArrayValue(t *testing.T) { + valid := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeBoolArray, Value: []bool{true, false, true}} + invalidType := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeBinary, Value: true} + invalidValue := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeBoolArray, Value: "true"} + + tests := []struct { + name string + cv *CommandValue + expected []bool + expectedErr bool + }{ + {"valid - CommandValue with []bool Value", valid, []bool{true, false, true}, false}, + {"invalid - ValueType is not BoolArray", invalidType, nil, true}, + {"invalid - Value is not []bool", invalidValue, nil, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res, err := tt.cv.BoolArrayValue() + if tt.expectedErr { + require.Error(t, err) + } else { + require.Equal(t, res, tt.expected) + } + }) + } +} + +func TestCommandValue_StringValue(t *testing.T) { + valid := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeString, Value: "test"} + invalidType := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeBinary, Value: "test"} + invalidValue := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeString, Value: true} + + tests := []struct { + name string + cv *CommandValue + expected string + expectedErr bool + }{ + {"valid - CommandValue with string Value", valid, "test", false}, + {"invalid - ValueType is not String", invalidType, "test", true}, + {"invalid - Value is not string", invalidValue, "test", true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res, err := tt.cv.StringValue() + if tt.expectedErr { + require.Error(t, err) + } else { + require.Equal(t, res, tt.expected) + } + }) + } +} + +func TestCommandValue_Uint8Value(t *testing.T) { + value := uint8(1) + valid := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeUint8, Value: value} + invalidType := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeBinary, Value: value} + invalidValue := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeUint8, Value: true} + + tests := []struct { + name string + cv *CommandValue + expected uint8 + expectedErr bool + }{ + {"valid - CommandValue with uint8 Value", valid, value, false}, + {"invalid - ValueType is not Uint8", invalidType, value, true}, + {"invalid - Value is not uint8", invalidValue, value, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res, err := tt.cv.Uint8Value() + if tt.expectedErr { + require.Error(t, err) + } else { + require.Equal(t, res, tt.expected) + } + }) + } +} + +func TestCommandValue_Uint8ArrayValue(t *testing.T) { + value := []uint8{1} + valid := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeUint8Array, Value: value} + invalidType := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeBinary, Value: value} + invalidValue := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeUint8Array, Value: true} + + tests := []struct { + name string + cv *CommandValue + expected []uint8 + expectedErr bool + }{ + {"valid - CommandValue with []uint8 Value", valid, value, false}, + {"invalid - ValueType is not Uint8Array", invalidType, value, true}, + {"invalid - Value is not []uint8", invalidValue, value, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res, err := tt.cv.Uint8ArrayValue() + if tt.expectedErr { + require.Error(t, err) + } else { + require.Equal(t, res, tt.expected) + } + }) + } +} + +func TestCommandValue_Uint16Value(t *testing.T) { + value := uint16(1) + valid := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeUint16, Value: value} + invalidType := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeBinary, Value: value} + invalidValue := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeUint16, Value: true} + + tests := []struct { + name string + cv *CommandValue + expected uint16 + expectedErr bool + }{ + {"valid - CommandValue with uint16 Value", valid, value, false}, + {"invalid - ValueType is not Uint16", invalidType, value, true}, + {"invalid - Value is not uint16", invalidValue, value, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res, err := tt.cv.Uint16Value() + if tt.expectedErr { + require.Error(t, err) + } else { + require.Equal(t, res, tt.expected) + } + }) + } +} + +func TestCommandValue_Uint16ArrayValue(t *testing.T) { + value := []uint16{1} + valid := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeUint16Array, Value: value} + invalidType := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeBinary, Value: value} + invalidValue := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeUint16Array, Value: true} + + tests := []struct { + name string + cv *CommandValue + expected []uint16 + expectedErr bool + }{ + {"valid - CommandValue with []uint16 Value", valid, value, false}, + {"invalid - ValueType is not Uint16Array", invalidType, value, true}, + {"invalid - Value is not []uint16", invalidValue, value, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res, err := tt.cv.Uint16ArrayValue() + if tt.expectedErr { + require.Error(t, err) + } else { + require.Equal(t, res, tt.expected) + } + }) + } +} + +func TestCommandValue_Uint32Value(t *testing.T) { + value := uint32(1) + valid := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeUint32, Value: value} + invalidType := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeBinary, Value: value} + invalidValue := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeUint32, Value: true} + + tests := []struct { + name string + cv *CommandValue + expected uint32 + expectedErr bool + }{ + {"valid - CommandValue with uint32 Value", valid, value, false}, + {"invalid - ValueType is not Uint32", invalidType, value, true}, + {"invalid - Value is not uint32", invalidValue, value, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res, err := tt.cv.Uint32Value() + if tt.expectedErr { + require.Error(t, err) + } else { + require.Equal(t, res, tt.expected) + } + }) + } +} + +func TestCommandValue_Uint32ArrayValue(t *testing.T) { + value := []uint32{1} + valid := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeUint32Array, Value: value} + invalidType := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeBinary, Value: value} + invalidValue := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeUint32Array, Value: true} + + tests := []struct { + name string + cv *CommandValue + expected []uint32 + expectedErr bool + }{ + {"valid - CommandValue with []uint32 Value", valid, value, false}, + {"invalid - ValueType is not Uint32Array", invalidType, value, true}, + {"invalid - Value is not []uint32", invalidValue, value, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res, err := tt.cv.Uint32ArrayValue() + if tt.expectedErr { + require.Error(t, err) + } else { + require.Equal(t, res, tt.expected) + } + }) + } +} + +func TestCommandValue_Uint64Value(t *testing.T) { + value := uint64(1) + valid := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeUint64, Value: value} + invalidType := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeBinary, Value: value} + invalidValue := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeUint64, Value: true} + + tests := []struct { + name string + cv *CommandValue + expected uint64 + expectedErr bool + }{ + {"valid - CommandValue with uint64 Value", valid, value, false}, + {"invalid - ValueType is not Uint64", invalidType, value, true}, + {"invalid - Value is not uint64", invalidValue, value, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res, err := tt.cv.Uint64Value() + if tt.expectedErr { + require.Error(t, err) + } else { + require.Equal(t, res, tt.expected) + } + }) + } +} + +func TestCommandValue_Uint64ArrayValue(t *testing.T) { + value := []uint64{1} + valid := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeUint64Array, Value: value} + invalidType := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeBinary, Value: value} + invalidValue := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeUint64Array, Value: true} + + tests := []struct { + name string + cv *CommandValue + expected []uint64 + expectedErr bool + }{ + {"valid - CommandValue with []uint64 Value", valid, value, false}, + {"invalid - ValueType is not Uint64Array", invalidType, value, true}, + {"invalid - Value is not []uint64", invalidValue, value, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res, err := tt.cv.Uint64ArrayValue() + if tt.expectedErr { + require.Error(t, err) + } else { + require.Equal(t, res, tt.expected) + } + }) + } +} + +func TestCommandValue_Int8Value(t *testing.T) { + value := int8(-1) + valid := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeInt8, Value: value} + invalidType := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeBinary, Value: value} + invalidValue := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeInt8, Value: true} + + tests := []struct { + name string + cv *CommandValue + expected int8 + expectedErr bool + }{ + {"valid - CommandValue with int8 Value", valid, value, false}, + {"invalid - ValueType is not Int8", invalidType, value, true}, + {"invalid - Value is not int8", invalidValue, value, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res, err := tt.cv.Int8Value() + if tt.expectedErr { + require.Error(t, err) + } else { + require.Equal(t, res, tt.expected) + } + }) + } +} + +func TestCommandValue_Int8ArrayValue(t *testing.T) { + value := []int8{-1} + valid := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeInt8Array, Value: value} + invalidType := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeBinary, Value: value} + invalidValue := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeInt8Array, Value: true} + + tests := []struct { + name string + cv *CommandValue + expected []int8 + expectedErr bool + }{ + {"valid - CommandValue with []int8 Value", valid, value, false}, + {"invalid - ValueType is not Int8Array", invalidType, value, true}, + {"invalid - Value is not []int8", invalidValue, value, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res, err := tt.cv.Int8ArrayValue() + if tt.expectedErr { + require.Error(t, err) + } else { + require.Equal(t, res, tt.expected) + } + }) + } +} + +func TestCommandValue_Int16Value(t *testing.T) { + value := int16(-1) + valid := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeInt16, Value: value} + invalidType := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeBinary, Value: value} + invalidValue := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeInt16, Value: true} + + tests := []struct { + name string + cv *CommandValue + expected int16 + expectedErr bool + }{ + {"valid - CommandValue with int16 Value", valid, value, false}, + {"invalid - ValueType is not Int16", invalidType, value, true}, + {"invalid - Value is not int16", invalidValue, value, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res, err := tt.cv.Int16Value() + if tt.expectedErr { + require.Error(t, err) + } else { + require.Equal(t, res, tt.expected) + } + }) + } +} + +func TestCommandValue_Int16ArrayValue(t *testing.T) { + value := []int16{-1} + valid := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeInt16Array, Value: value} + invalidType := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeBinary, Value: value} + invalidValue := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeInt16Array, Value: true} + + tests := []struct { + name string + cv *CommandValue + expected []int16 + expectedErr bool + }{ + {"valid - CommandValue with []int16 Value", valid, value, false}, + {"invalid - ValueType is not Int16Array", invalidType, value, true}, + {"invalid - Value is not []int16", invalidValue, value, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res, err := tt.cv.Int16ArrayValue() + if tt.expectedErr { + require.Error(t, err) + } else { + require.Equal(t, res, tt.expected) + } + }) + } +} + +func TestCommandValue_Int32Value(t *testing.T) { + value := int32(-1) + valid := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeInt32, Value: value} + invalidType := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeBinary, Value: value} + invalidValue := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeInt32, Value: true} + + tests := []struct { + name string + cv *CommandValue + expected int32 + expectedErr bool + }{ + {"valid - CommandValue with int32 Value", valid, value, false}, + {"invalid - ValueType is not Int32", invalidType, value, true}, + {"invalid - Value is not int32", invalidValue, value, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res, err := tt.cv.Int32Value() + if tt.expectedErr { + require.Error(t, err) + } else { + require.Equal(t, res, tt.expected) + } + }) + } +} + +func TestCommandValue_Int32ArrayValue(t *testing.T) { + value := []int32{-1} + valid := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeInt32Array, Value: value} + invalidType := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeBinary, Value: value} + invalidValue := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeInt32Array, Value: true} + + tests := []struct { + name string + cv *CommandValue + expected []int32 + expectedErr bool + }{ + {"valid - CommandValue with []int32 Value", valid, value, false}, + {"invalid - ValueType is not Int32Array", invalidType, value, true}, + {"invalid - Value is not []int32", invalidValue, value, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res, err := tt.cv.Int32ArrayValue() + if tt.expectedErr { + require.Error(t, err) + } else { + require.Equal(t, res, tt.expected) + } + }) + } +} + +func TestCommandValue_Int64Value(t *testing.T) { + value := int64(-1) + valid := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeInt64, Value: value} + invalidType := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeBinary, Value: value} + invalidValue := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeInt64, Value: true} + + tests := []struct { + name string + cv *CommandValue + expected int64 + expectedErr bool + }{ + {"valid - CommandValue with int64 Value", valid, value, false}, + {"invalid - ValueType is not Int64", invalidType, value, true}, + {"invalid - Value is not int64", invalidValue, value, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res, err := tt.cv.Int64Value() + if tt.expectedErr { + require.Error(t, err) + } else { + require.Equal(t, res, tt.expected) + } + }) + } +} + +func TestCommandValue_Int64ArrayValue(t *testing.T) { + value := []int64{-1} + valid := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeInt64Array, Value: value} + invalidType := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeBinary, Value: value} + invalidValue := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeInt64Array, Value: true} + + tests := []struct { + name string + cv *CommandValue + expected []int64 + expectedErr bool + }{ + {"valid - CommandValue with []int64 Value", valid, value, false}, + {"invalid - ValueType is not Int64Array", invalidType, value, true}, + {"invalid - Value is not []int64", invalidValue, value, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res, err := tt.cv.Int64ArrayValue() + if tt.expectedErr { + require.Error(t, err) + } else { + require.Equal(t, res, tt.expected) + } + }) + } +} + +func TestCommandValue_Float32Value(t *testing.T) { + value := float32(13.456) + valid := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeFloat32, Value: value} + invalidType := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeBinary, Value: value} + invalidValue := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeFloat32, Value: true} + + tests := []struct { + name string + cv *CommandValue + expected float32 + expectedErr bool + }{ + {"valid - CommandValue with float32 Value", valid, value, false}, + {"invalid - ValueType is not Float32", invalidType, value, true}, + {"invalid - Value is not float32", invalidValue, value, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res, err := tt.cv.Float32Value() + if tt.expectedErr { + require.Error(t, err) + } else { + require.Equal(t, res, tt.expected) + } + }) + } +} + +func TestCommandValue_Float32ArrayValue(t *testing.T) { + value := []float32{12.345} + valid := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeFloat32Array, Value: value} + invalidType := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeBinary, Value: value} + invalidValue := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeFloat32Array, Value: true} + + tests := []struct { + name string + cv *CommandValue + expected []float32 + expectedErr bool + }{ + {"valid - CommandValue with []float32 Value", valid, value, false}, + {"invalid - ValueType is not Float32Array", invalidType, value, true}, + {"invalid - Value is not []float32", invalidValue, value, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res, err := tt.cv.Float32ArrayValue() + if tt.expectedErr { + require.Error(t, err) + } else { + require.Equal(t, res, tt.expected) + } + }) + } +} + +func TestCommandValue_Float64Value(t *testing.T) { + value := float64(13.456) + valid := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeFloat64, Value: value} + invalidType := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeBinary, Value: value} + invalidValue := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeFloat64, Value: true} + + tests := []struct { + name string + cv *CommandValue + expected float64 + expectedErr bool + }{ + {"valid - CommandValue with float64 Value", valid, value, false}, + {"invalid - ValueType is not Float64", invalidType, value, true}, + {"invalid - Value is not float64", invalidValue, value, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res, err := tt.cv.Float64Value() + if tt.expectedErr { + require.Error(t, err) + } else { + require.Equal(t, res, tt.expected) + } + }) + } +} + +func TestCommandValue_Float64ArrayValue(t *testing.T) { + value := []float64{12.345} + valid := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeFloat64Array, Value: value} + invalidType := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeBinary, Value: value} + invalidValue := &CommandValue{DeviceResourceName: "test-resource", Type: v2.ValueTypeFloat64Array, Value: true} + + tests := []struct { + name string + cv *CommandValue + expected []float64 + expectedErr bool + }{ + {"valid - CommandValue with []float64 Value", valid, value, false}, + {"invalid - ValueType is not Float64Array", invalidType, value, true}, + {"invalid - Value is not []float64", invalidValue, value, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res, err := tt.cv.Float64ArrayValue() + if tt.expectedErr { + require.Error(t, err) + } else { + require.Equal(t, res, tt.expected) } }) } From 44e422c5aebbc746276f514c8f0709a2f5b68208 Mon Sep 17 00:00:00 2001 From: Chris Hung Date: Wed, 28 Apr 2021 12:34:44 +0800 Subject: [PATCH 4/4] test: complement unit tests for transformer package Signed-off-by: Chris Hung --- internal/transformer/transformresult_test.go | 37 ++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/internal/transformer/transformresult_test.go b/internal/transformer/transformresult_test.go index a60ee21dc..a895922ba 100644 --- a/internal/transformer/transformresult_test.go +++ b/internal/transformer/transformresult_test.go @@ -255,3 +255,40 @@ func Test_commandValueForTransform(t *testing.T) { }) } } + +func Test_mapCommandValue(t *testing.T) { + numericValue, err := models.NewCommandValue("test-resource", v2.ValueTypeFloat32, float32(123.456)) + require.NoError(t, err) + stringValue, err := models.NewCommandValue("test-resource", v2.ValueTypeString, "key") + require.NoError(t, err) + arrayValue, err := models.NewCommandValue("test-resource", v2.ValueTypeInt8Array, []int8{1, 2, 3}) + require.NoError(t, err) + invalid, err := models.NewCommandValue("test-resource", v2.ValueTypeString, "invalid") + require.NoError(t, err) + + mappings := map[string]string{ + "123.456": "value", + "key": "value", + "[1 2 3]": "value", + } + + tests := []struct { + name string + cv *models.CommandValue + success bool + }{ + {"valid - CommandValue with numeric mapping", numericValue, true}, + {"valid - CommandValue with string mapping", stringValue, true}, + {"valid - CommandValue with array mapping", arrayValue, true}, + {"invalid - mapping not found", invalid, false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + res, ok := mapCommandValue(tt.cv, mappings) + require.Equal(t, ok, tt.success) + if ok { + assert.Equal(t, res.Value, "value") + } + }) + } +}