From f86128568345ecc8a6a3639276ca5b33426633a0 Mon Sep 17 00:00:00 2001 From: bruce Date: Tue, 19 Oct 2021 14:26:06 +0800 Subject: [PATCH] feat: Add Client API to Support object value type in Set Command Make the Set Command payload to allow object value type parameters. Closes #675 Signed-off-by: bruce --- clients/http/command.go | 10 ++++++++ clients/http/command_test.go | 18 +++++++++++++ clients/http/deviceservicecommand.go | 11 ++++++++ clients/http/deviceservicecommand_test.go | 19 ++++++++++++++ clients/interfaces/command.go | 2 ++ clients/interfaces/deviceservicecommand.go | 2 ++ .../mocks/DeviceServiceCommandClient.go | 25 ++++++++++++++++++- dtos/deviceprofile.go | 4 +-- dtos/deviceprofile_test.go | 4 --- 9 files changed, 88 insertions(+), 7 deletions(-) diff --git a/clients/http/command.go b/clients/http/command.go index 53530ee2..dfa03900 100644 --- a/clients/http/command.go +++ b/clients/http/command.go @@ -76,3 +76,13 @@ func (client *CommandClient) IssueSetCommandByName(ctx context.Context, deviceNa } return res, nil } + +// IssueSetCommandByNameWithObject issues the specified write command and the settings supports object value type +func (client *CommandClient) IssueSetCommandByNameWithObject(ctx context.Context, deviceName string, commandName string, settings map[string]interface{}) (res dtoCommon.BaseResponse, err errors.EdgeX) { + requestPath := path.Join(common.ApiDeviceRoute, common.Name, url.QueryEscape(deviceName), url.QueryEscape(commandName)) + err = utils.PutRequest(ctx, &res, client.baseUrl+requestPath, settings) + if err != nil { + return res, errors.NewCommonEdgeXWrapper(err) + } + return res, nil +} diff --git a/clients/http/command_test.go b/clients/http/command_test.go index e14adeb0..ac4e7f7d 100644 --- a/clients/http/command_test.go +++ b/clients/http/command_test.go @@ -64,3 +64,21 @@ func TestIssueIssueSetCommandByName(t *testing.T) { require.NoError(t, err) require.IsType(t, dtoCommon.BaseResponse{}, res) } + +func TestIssueIssueSetCommandByNameWithObject(t *testing.T) { + deviceName := "Simple-Device01" + cmdName := "SwitchButton" + settings := map[string]interface{}{ + "SwitchButton": map[string]interface{}{ + "kind": "button", + "value": "on", + }, + } + path := path.Join(common.ApiDeviceRoute, common.Name, deviceName, cmdName) + ts := newTestServer(http.MethodPut, path, dtoCommon.BaseResponse{}) + defer ts.Close() + client := NewCommandClient(ts.URL) + res, err := client.IssueSetCommandByNameWithObject(context.Background(), deviceName, cmdName, settings) + require.NoError(t, err) + require.IsType(t, dtoCommon.BaseResponse{}, res) +} diff --git a/clients/http/deviceservicecommand.go b/clients/http/deviceservicecommand.go index a927bdba..7d3a991d 100644 --- a/clients/http/deviceservicecommand.go +++ b/clients/http/deviceservicecommand.go @@ -67,3 +67,14 @@ func (client *deviceServiceCommandClient) SetCommand(ctx context.Context, baseUr } return response, nil } + +// SetCommandWithObject invokes device service's set command API and the settings supports object value type +func (client *deviceServiceCommandClient) SetCommandWithObject(ctx context.Context, baseUrl string, deviceName string, commandName string, queryParams string, settings map[string]interface{}) (dtoCommon.BaseResponse, errors.EdgeX) { + var response dtoCommon.BaseResponse + requestPath := path.Join(common.ApiDeviceRoute, common.Name, url.QueryEscape(deviceName), url.QueryEscape(commandName)) + err := utils.PutRequest(ctx, &response, baseUrl+requestPath+"?"+queryParams, settings) + if err != nil { + return response, errors.NewCommonEdgeXWrapper(err) + } + return response, nil +} diff --git a/clients/http/deviceservicecommand_test.go b/clients/http/deviceservicecommand_test.go index e68cd859..5d6aa52c 100644 --- a/clients/http/deviceservicecommand_test.go +++ b/clients/http/deviceservicecommand_test.go @@ -66,3 +66,22 @@ func TestSetCommand(t *testing.T) { require.NoError(t, err) assert.Equal(t, requestId, res.RequestId) } + +func TestSetCommandWithObject(t *testing.T) { + requestId := uuid.New().String() + expectedResponse := dtoCommon.NewBaseResponse(requestId, "", http.StatusOK) + ts := newTestServer(http.MethodPut, common.ApiDeviceRoute+"/"+common.Name+"/"+TestDeviceName+"/"+TestCommandName, expectedResponse) + defer ts.Close() + settings := map[string]interface{}{ + "SwitchButton": map[string]interface{}{ + "kind": "button", + "value": "on", + }, + } + + client := NewDeviceServiceCommandClient() + res, err := client.SetCommandWithObject(context.Background(), ts.URL, TestDeviceName, TestCommandName, "", settings) + + require.NoError(t, err) + assert.Equal(t, requestId, res.RequestId) +} diff --git a/clients/interfaces/command.go b/clients/interfaces/command.go index 4b201b16..7b44303e 100644 --- a/clients/interfaces/command.go +++ b/clients/interfaces/command.go @@ -28,4 +28,6 @@ type CommandClient interface { IssueGetCommandByName(ctx context.Context, deviceName string, commandName string, dsPushEvent string, dsReturnEvent string) (*responses.EventResponse, errors.EdgeX) // IssueSetCommandByName issues the specified write command referenced by the command name to the device/sensor that is also referenced by name. IssueSetCommandByName(ctx context.Context, deviceName string, commandName string, settings map[string]string) (common.BaseResponse, errors.EdgeX) + // IssueSetCommandByNameWithObject issues the specified write command and the settings supports object value type + IssueSetCommandByNameWithObject(ctx context.Context, deviceName string, commandName string, settings map[string]interface{}) (common.BaseResponse, errors.EdgeX) } diff --git a/clients/interfaces/deviceservicecommand.go b/clients/interfaces/deviceservicecommand.go index 7204f82e..20f96508 100644 --- a/clients/interfaces/deviceservicecommand.go +++ b/clients/interfaces/deviceservicecommand.go @@ -19,4 +19,6 @@ type DeviceServiceCommandClient interface { GetCommand(ctx context.Context, baseUrl string, deviceName string, commandName string, queryParams string) (*responses.EventResponse, errors.EdgeX) // SetCommand invokes device service's command API for issuing set(write) command SetCommand(ctx context.Context, baseUrl string, deviceName string, commandName string, queryParams string, settings map[string]string) (common.BaseResponse, errors.EdgeX) + // SetCommandWithObject invokes device service's set command API and the settings supports object value type + SetCommandWithObject(ctx context.Context, baseUrl string, deviceName string, commandName string, queryParams string, settings map[string]interface{}) (common.BaseResponse, errors.EdgeX) } diff --git a/clients/interfaces/mocks/DeviceServiceCommandClient.go b/clients/interfaces/mocks/DeviceServiceCommandClient.go index 9cb310e0..42aac5f2 100644 --- a/clients/interfaces/mocks/DeviceServiceCommandClient.go +++ b/clients/interfaces/mocks/DeviceServiceCommandClient.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.7.4. DO NOT EDIT. +// Code generated by mockery 2.9.4. DO NOT EDIT. package mocks @@ -66,3 +66,26 @@ func (_m *DeviceServiceCommandClient) SetCommand(ctx context.Context, baseUrl st return r0, r1 } + +// SetCommandWithObject provides a mock function with given fields: ctx, baseUrl, deviceName, commandName, queryParams, settings +func (_m *DeviceServiceCommandClient) SetCommandWithObject(ctx context.Context, baseUrl string, deviceName string, commandName string, queryParams string, settings map[string]interface{}) (common.BaseResponse, errors.EdgeX) { + ret := _m.Called(ctx, baseUrl, deviceName, commandName, queryParams, settings) + + var r0 common.BaseResponse + if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string, map[string]interface{}) common.BaseResponse); ok { + r0 = rf(ctx, baseUrl, deviceName, commandName, queryParams, settings) + } else { + r0 = ret.Get(0).(common.BaseResponse) + } + + var r1 errors.EdgeX + if rf, ok := ret.Get(1).(func(context.Context, string, string, string, string, map[string]interface{}) errors.EdgeX); ok { + r1 = rf(ctx, baseUrl, deviceName, commandName, queryParams, settings) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(errors.EdgeX) + } + } + + return r0, r1 +} diff --git a/dtos/deviceprofile.go b/dtos/deviceprofile.go index 5438ea9d..dab146c0 100644 --- a/dtos/deviceprofile.go +++ b/dtos/deviceprofile.go @@ -104,9 +104,9 @@ func ValidateDeviceProfileDTO(profile DeviceProfile) error { // deviceResources validation dupCheck := make(map[string]bool) for _, resource := range profile.DeviceResources { - if (resource.Properties.ValueType == common.ValueTypeBinary || resource.Properties.ValueType == common.ValueTypeObject) && + if resource.Properties.ValueType == common.ValueTypeBinary && strings.Contains(resource.Properties.ReadWrite, common.ReadWrite_W) { - return errors.NewCommonEdgeX(errors.KindContractInvalid, fmt.Sprintf("write permission not support %s and %s value type for resource '%s'", common.ValueTypeBinary, common.ValueTypeObject, resource.Name), nil) + return errors.NewCommonEdgeX(errors.KindContractInvalid, fmt.Sprintf("write permission not support %s value type for resource '%s'", common.ValueTypeBinary, resource.Name), nil) } // deviceResource name should not duplicated if dupCheck[resource.Name] { diff --git a/dtos/deviceprofile_test.go b/dtos/deviceprofile_test.go index bbebb211..53552d8a 100644 --- a/dtos/deviceprofile_test.go +++ b/dtos/deviceprofile_test.go @@ -97,9 +97,6 @@ func TestDeviceProfileDTOValidation(t *testing.T) { binaryWithWritePermission := profileData() binaryWithWritePermission.DeviceResources[0].Properties.ValueType = common.ValueTypeBinary binaryWithWritePermission.DeviceResources[0].Properties.ReadWrite = common.ReadWrite_RW - objectWithWritePermission := profileData() - objectWithWritePermission.DeviceResources[0].Properties.ValueType = common.ValueTypeObject - objectWithWritePermission.DeviceResources[0].Properties.ReadWrite = common.ReadWrite_W tests := []struct { name string @@ -112,7 +109,6 @@ func TestDeviceProfileDTOValidation(t *testing.T) { {"mismatched resource", mismatchedResource, true}, {"invalid ReadWrite permission", invalidReadWrite, true}, {"write permission not support Binary value type", binaryWithWritePermission, true}, - {"write permission not support Object value type", objectWithWritePermission, true}, } for _, tt := range tests {