Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Support object value type in Set Command #1038

Merged
merged 2 commits into from
Oct 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
"description": "Counter data",
"properties": {
"valueType": "Object",
"readWrite": "R"
"readWrite": "RW"
}
}
],
Expand Down
2 changes: 1 addition & 1 deletion example/cmd/device-simple/res/profiles/Simple-Driver.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ deviceResources:
description: "Counter data"
properties:
valueType: "Object"
readWrite: "R"
readWrite: "RW"

deviceCommands:
-
Expand Down
5 changes: 5 additions & 0 deletions example/driver/simpledriver.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,11 @@ func (s *SimpleDriver) HandleWriteCommands(deviceName string, protocols map[stri
} else {
return err
}
case "Counter":
if s.counter, err = params[i].ObjectValue(); err != nil {
err := fmt.Errorf("SimpleDriver.HandleWriteCommands; the data type of parameter should be Object, parameter: %s", params[i].String())
return err
}
}
}

Expand Down
14 changes: 9 additions & 5 deletions internal/application/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@ type CommandProcessor struct {
device models.Device
sourceName string
correlationID string
setParamsMap map[string]string
setParamsMap map[string]interface{}
attributes string
dic *di.Container
}

func NewCommandProcessor(device models.Device, sourceName string, correlationID string, setParamsMap map[string]string, attributes string, dic *di.Container) *CommandProcessor {
func NewCommandProcessor(device models.Device, sourceName string, correlationID string, setParamsMap map[string]interface{}, attributes string, dic *di.Container) *CommandProcessor {
if setParamsMap == nil {
setParamsMap = make(map[string]string)
setParamsMap = make(map[string]interface{})
}
return &CommandProcessor{
device: device,
Expand All @@ -53,7 +53,7 @@ func NewCommandProcessor(device models.Device, sourceName string, correlationID
}
}

func CommandHandler(isRead bool, sendEvent bool, correlationID string, vars map[string]string, setParamsMap map[string]string, attributes string, dic *di.Container) (res *dtos.Event, err errors.EdgeX) {
func CommandHandler(isRead bool, sendEvent bool, correlationID string, vars map[string]string, setParamsMap map[string]interface{}, attributes string, dic *di.Container) (res *dtos.Event, err errors.EdgeX) {
// check device service AdminState
ds := container.DeviceServiceFrom(dic.Get)
if ds.AdminState == models.Locked {
Expand Down Expand Up @@ -382,10 +382,12 @@ func (c *CommandProcessor) WriteDeviceCommand() errors.EdgeX {
return nil
}

func createCommandValueFromDeviceResource(dr models.DeviceResource, v string) (*sdkModels.CommandValue, errors.EdgeX) {
func createCommandValueFromDeviceResource(dr models.DeviceResource, value interface{}) (*sdkModels.CommandValue, errors.EdgeX) {
var err error
var result *sdkModels.CommandValue

v := fmt.Sprint(value)

switch dr.Properties.ValueType {
case common.ValueTypeString:
result, err = sdkModels.NewCommandValue(dr.Name, common.ValueTypeString, v)
Expand Down Expand Up @@ -616,6 +618,8 @@ func createCommandValueFromDeviceResource(dr models.DeviceResource, v string) (*
return result, errors.NewCommonEdgeX(errors.KindServerError, errMsg, err)
}
result, err = sdkModels.NewCommandValue(dr.Name, common.ValueTypeFloat64Array, arr)
case common.ValueTypeObject:
result, err = sdkModels.NewCommandValue(dr.Name, common.ValueTypeObject, value)
default:
err = errors.NewCommonEdgeX(errors.KindServerError, "unrecognized value type", nil)
}
Expand Down
36 changes: 29 additions & 7 deletions internal/application/command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ import (
"github.com/edgexfoundry/go-mod-bootstrap/v2/di"
clientMocks "github.com/edgexfoundry/go-mod-core-contracts/v2/clients/interfaces/mocks"
"github.com/edgexfoundry/go-mod-core-contracts/v2/clients/logger"
"github.com/edgexfoundry/go-mod-core-contracts/v2/common"
"github.com/edgexfoundry/go-mod-core-contracts/v2/dtos"
"github.com/edgexfoundry/go-mod-core-contracts/v2/dtos/common"
dtoCommon "github.com/edgexfoundry/go-mod-core-contracts/v2/dtos/common"
"github.com/edgexfoundry/go-mod-core-contracts/v2/dtos/responses"
"github.com/edgexfoundry/go-mod-core-contracts/v2/models"
"github.com/google/uuid"
Expand Down Expand Up @@ -51,11 +52,23 @@ func mockDic() *di.Container {
Value: "test-value",
Tags: make(map[string]string),
}
objectRequest := sdkModels.CommandRequest{
DeviceResourceName: "rw-object",
Attributes: nil,
Type: common.ValueTypeObject,
}
objectValue := &sdkModels.CommandValue{
DeviceResourceName: "rw-object",
Type: common.ValueTypeObject,
Value: map[string]interface{}{"foo": "bar"},
Tags: make(map[string]string),
}
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)
driverMock.On("HandleWriteCommands", "test-device", testProtocols, []sdkModels.CommandRequest{objectRequest}, []*sdkModels.CommandValue{objectValue}).Return(nil)

devices := responses.MultiDevicesResponse{
BaseResponse: common.BaseResponse{},
BaseResponse: dtoCommon.BaseResponse{},
Devices: []dtos.Device{
dtos.FromDeviceModelToDTO(testDevice),
},
Expand All @@ -64,7 +77,7 @@ func mockDic() *di.Container {
dcMock.On("DevicesByServiceName", context.Background(), "test-service", 0, -1).Return(devices, nil)

profile := responses.DeviceProfileResponse{
BaseResponse: common.BaseResponse{},
BaseResponse: dtoCommon.BaseResponse{},
Profile: dtos.DeviceProfile{
Name: "test-profile",
DeviceResources: []dtos.DeviceResource{
Expand All @@ -90,6 +103,13 @@ func mockDic() *di.Container {
ReadWrite: "W",
},
},
dtos.DeviceResource{
Name: "rw-object",
Properties: dtos.ResourceProperties{
ValueType: common.ValueTypeObject,
ReadWrite: "RW",
},
},
},
DeviceCommands: []dtos.DeviceCommand{
dtos.DeviceCommand{
Expand Down Expand Up @@ -222,18 +242,20 @@ func TestCommandProcessor_WriteDeviceResource(t *testing.T) {
err := cache.InitCache("test-service", dic)
require.NoError(t, err)

valid := NewCommandProcessor(testDevice, "test-resource", uuid.NewString(), map[string]string{"test-resource": "test-value"}, "", dic)
valid := NewCommandProcessor(testDevice, "test-resource", uuid.NewString(), map[string]interface{}{"test-resource": "test-value"}, "", dic)
validObjectValue := NewCommandProcessor(testDevice, "rw-object", uuid.NewString(), map[string]interface{}{"rw-object": map[string]interface{}{"foo": "bar"}}, "", dic)
invalidDeviceResource := NewCommandProcessor(testDevice, "invalid", uuid.NewString(), nil, "", dic)
readOnlyDeviceResource := NewCommandProcessor(testDevice, "ro-resource", uuid.NewString(), nil, "", dic)
noRequestBody := NewCommandProcessor(testDevice, "test-resource", uuid.NewString(), nil, "", dic)
invalidRequestBody := NewCommandProcessor(testDevice, "test-resource", uuid.NewString(), map[string]string{"wrong-resource": "wrong-value"}, "", dic)
invalidRequestBody := NewCommandProcessor(testDevice, "test-resource", uuid.NewString(), map[string]interface{}{"wrong-resource": "wrong-value"}, "", dic)

tests := []struct {
name string
commandProcessor *CommandProcessor
expectedErr bool
}{
{"valid", valid, false},
{"valid object value", validObjectValue, false},
{"invalid - DeviceResource name not found", invalidDeviceResource, true},
{"invalid - writing read-only DeviceResource", readOnlyDeviceResource, true},
{"valid - no set parameter specified but default value exists", noRequestBody, false},
Expand All @@ -257,12 +279,12 @@ func TestCommandProcessor_WriteDeviceCommand(t *testing.T) {
err := cache.InitCache("test-service", dic)
require.NoError(t, err)

valid := NewCommandProcessor(testDevice, "test-command", uuid.NewString(), map[string]string{"test-resource": "test-value"}, "", dic)
valid := NewCommandProcessor(testDevice, "test-command", uuid.NewString(), map[string]interface{}{"test-resource": "test-value"}, "", dic)
invalidDeviceCommand := NewCommandProcessor(testDevice, "invalid", uuid.NewString(), nil, "", dic)
readOnlyDeviceCommand := NewCommandProcessor(testDevice, "ro-command", uuid.NewString(), nil, "", dic)
outOfRangeResourceOperation := NewCommandProcessor(testDevice, "exceed-command", uuid.NewString(), nil, "", dic)
noRequestBody := NewCommandProcessor(testDevice, "test-command", uuid.NewString(), nil, "", dic)
invalidRequestBody := NewCommandProcessor(testDevice, "test-command", uuid.NewString(), map[string]string{"wrong-resource": "wrong-value"}, "", dic)
invalidRequestBody := NewCommandProcessor(testDevice, "test-command", uuid.NewString(), map[string]interface{}{"wrong-resource": "wrong-value"}, "", dic)

tests := []struct {
name string
Expand Down
6 changes: 3 additions & 3 deletions internal/controller/http/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import (
func (c *RestController) Command(writer http.ResponseWriter, request *http.Request) {
defer request.Body.Close()

var requestParamsMap map[string]string
var requestParamsMap map[string]interface{}
var queryParams string
var err errors.EdgeX
var reserved url.Values
Expand Down Expand Up @@ -77,7 +77,7 @@ func (c *RestController) Command(writer http.ResponseWriter, request *http.Reque
}
}

func parseRequestBody(req *http.Request, maxRequestSize int64) (map[string]string, errors.EdgeX) {
func parseRequestBody(req *http.Request, maxRequestSize int64) (map[string]interface{}, errors.EdgeX) {
defer req.Body.Close()
body, err := io.ReadAll(req.Body)
if err != nil {
Expand All @@ -88,7 +88,7 @@ func parseRequestBody(req *http.Request, maxRequestSize int64) (map[string]strin
return nil, errors.NewCommonEdgeX(errors.KindServerError, "failed to read request body", err)
}

var paramMap = make(map[string]string)
var paramMap = make(map[string]interface{})
if len(body) == 0 {
return paramMap, nil
}
Expand Down