diff --git a/clients/http/deviceservicecommand.go b/clients/http/deviceservicecommand.go index 631df7a5..0d445288 100644 --- a/clients/http/deviceservicecommand.go +++ b/clients/http/deviceservicecommand.go @@ -97,10 +97,52 @@ func (client *deviceServiceCommandClient) SetCommandWithObject(ctx context.Conte return response, nil } +func (client *deviceServiceCommandClient) Discovery(ctx context.Context, baseUrl string) (dtoCommon.BaseResponse, errors.EdgeX) { + var response dtoCommon.BaseResponse + err := utils.PostRequest(ctx, &response, baseUrl, common.ApiDiscoveryRoute, nil, "", client.authInjector) + if err != nil { + return response, errors.NewCommonEdgeXWrapper(err) + } + return response, nil +} + // ProfileScan sends an HTTP POST request to the device service's profile scan API endpoint. func (client *deviceServiceCommandClient) ProfileScan(ctx context.Context, baseUrl string, req requests.ProfileScanRequest) (dtoCommon.BaseResponse, errors.EdgeX) { var response dtoCommon.BaseResponse - err := utils.PostRequestWithRawData(ctx, &response, baseUrl, common.ApiProfileScan, nil, req, client.authInjector) + err := utils.PostRequestWithRawData(ctx, &response, baseUrl, common.ApiProfileScanRoute, nil, req, client.authInjector) + if err != nil { + return response, errors.NewCommonEdgeXWrapper(err) + } + return response, nil +} + +func (client *deviceServiceCommandClient) StopDeviceDiscovery(ctx context.Context, baseUrl string, requestId string, queryParams map[string]string) (dtoCommon.BaseResponse, errors.EdgeX) { + requestPath := common.ApiDiscoveryRoute + if len(requestId) != 0 { + requestPath = common.NewPathBuilder().EnableNameFieldEscape(client.enableNameFieldEscape). + SetPath(common.ApiDiscoveryRoute).SetPath(common.RequestId).SetNameFieldPath(requestId).BuildPath() + } + response := dtoCommon.BaseResponse{} + params := url.Values{} + for k, v := range queryParams { + params.Set(k, v) + } + err := utils.DeleteRequestWithParams(ctx, &response, baseUrl, requestPath, params, client.authInjector) + if err != nil { + return response, errors.NewCommonEdgeXWrapper(err) + } + return response, nil +} + +func (client *deviceServiceCommandClient) StopProfileScan(ctx context.Context, baseUrl string, deviceName string, queryParams map[string]string) (dtoCommon.BaseResponse, errors.EdgeX) { + requestPath := common.NewPathBuilder().EnableNameFieldEscape(client.enableNameFieldEscape). + SetPath(common.ApiProfileScanRoute).SetPath(common.Device).SetPath(common.Name).SetNameFieldPath(deviceName).BuildPath() + response := dtoCommon.BaseResponse{} + params := url.Values{} + for k, v := range queryParams { + params.Set(k, v) + } + err := utils.DeleteRequestWithParams(ctx, &response, baseUrl, requestPath, params, client.authInjector) if err != nil { return response, errors.NewCommonEdgeXWrapper(err) } diff --git a/clients/http/deviceservicecommand_test.go b/clients/http/deviceservicecommand_test.go index 87ce6dec..4d891506 100644 --- a/clients/http/deviceservicecommand_test.go +++ b/clients/http/deviceservicecommand_test.go @@ -9,6 +9,7 @@ package http import ( "context" "net/http" + "path" "testing" "github.com/edgexfoundry/go-mod-core-contracts/v3/common" @@ -91,7 +92,7 @@ func TestSetCommandWithObject(t *testing.T) { func TestProfileScan(t *testing.T) { requestId := uuid.New().String() expectedResponse := dtoCommon.NewBaseResponse(requestId, "", http.StatusAccepted) - ts := newTestServer(http.MethodPost, common.ApiProfileScan, expectedResponse) + ts := newTestServer(http.MethodPost, common.ApiProfileScanRoute, expectedResponse) defer ts.Close() client := NewDeviceServiceCommandClient(NewNullAuthenticationInjector(), false) @@ -99,5 +100,43 @@ func TestProfileScan(t *testing.T) { require.NoError(t, err) assert.Equal(t, requestId, res.RequestId) +} + +func TestStopDeviceDiscovery(t *testing.T) { + id := uuid.New().String() + requestRoute := path.Join(common.ApiDiscoveryRoute, common.RequestId, id) + + tests := []struct { + name string + requestId string + route string + }{ + {"stop device discovery", "", common.ApiDiscoveryRoute}, + {"stop device discovery with request id", id, requestRoute}, + } + for _, testCase := range tests { + t.Run(testCase.name, func(t *testing.T) { + ts := newTestServer(http.MethodDelete, testCase.route, dtoCommon.BaseResponse{}) + //defer ts.Close() + + client := NewDeviceServiceCommandClient(NewNullAuthenticationInjector(), false) + res, err := client.StopDeviceDiscovery(context.Background(), ts.URL, testCase.requestId, nil) + + require.NoError(t, err) + assert.IsType(t, dtoCommon.BaseResponse{}, res) + ts.Close() + }) + } +} + +func TestStopProfileScan(t *testing.T) { + route := path.Join(common.ApiProfileScanRoute, common.Device, common.Name, TestDeviceName) + ts := newTestServer(http.MethodDelete, route, dtoCommon.BaseResponse{}) + defer ts.Close() + + client := NewDeviceServiceCommandClient(NewNullAuthenticationInjector(), false) + res, err := client.StopProfileScan(context.Background(), ts.URL, TestDeviceName, nil) + require.NoError(t, err) + assert.IsType(t, dtoCommon.BaseResponse{}, res) } diff --git a/clients/interfaces/deviceservicecommand.go b/clients/interfaces/deviceservicecommand.go index e6fe8d05..d0e1270a 100644 --- a/clients/interfaces/deviceservicecommand.go +++ b/clients/interfaces/deviceservicecommand.go @@ -22,6 +22,12 @@ type DeviceServiceCommandClient interface { 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) + // Discovery invokes device service's discovery API + Discovery(ctx context.Context, baseUrl string) (common.BaseResponse, errors.EdgeX) // ProfileScan sends an HTTP POST request to the device service's profile scan API endpoint. ProfileScan(ctx context.Context, baseUrl string, req requests.ProfileScanRequest) (common.BaseResponse, errors.EdgeX) + // StopDeviceDiscovery invokes device service's stop device discovery API + StopDeviceDiscovery(ctx context.Context, baseUrl string, requestId string, queryParams map[string]string) (common.BaseResponse, errors.EdgeX) + // StopProfileScan invokes device service's stop profile scan API + StopProfileScan(ctx context.Context, baseUrl string, deviceName string, queryParams map[string]string) (common.BaseResponse, errors.EdgeX) } diff --git a/clients/interfaces/mocks/DeviceServiceCommandClient.go b/clients/interfaces/mocks/DeviceServiceCommandClient.go index ff238357..2d4744d6 100644 --- a/clients/interfaces/mocks/DeviceServiceCommandClient.go +++ b/clients/interfaces/mocks/DeviceServiceCommandClient.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.42.3. DO NOT EDIT. +// Code generated by mockery v2.45.0. DO NOT EDIT. package mocks @@ -21,6 +21,36 @@ type DeviceServiceCommandClient struct { mock.Mock } +// Discovery provides a mock function with given fields: ctx, baseUrl +func (_m *DeviceServiceCommandClient) Discovery(ctx context.Context, baseUrl string) (common.BaseResponse, errors.EdgeX) { + ret := _m.Called(ctx, baseUrl) + + if len(ret) == 0 { + panic("no return value specified for Discovery") + } + + var r0 common.BaseResponse + var r1 errors.EdgeX + if rf, ok := ret.Get(0).(func(context.Context, string) (common.BaseResponse, errors.EdgeX)); ok { + return rf(ctx, baseUrl) + } + if rf, ok := ret.Get(0).(func(context.Context, string) common.BaseResponse); ok { + r0 = rf(ctx, baseUrl) + } else { + r0 = ret.Get(0).(common.BaseResponse) + } + + if rf, ok := ret.Get(1).(func(context.Context, string) errors.EdgeX); ok { + r1 = rf(ctx, baseUrl) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(errors.EdgeX) + } + } + + return r0, r1 +} + // GetCommand provides a mock function with given fields: ctx, baseUrl, deviceName, commandName, queryParams func (_m *DeviceServiceCommandClient) GetCommand(ctx context.Context, baseUrl string, deviceName string, commandName string, queryParams string) (*responses.EventResponse, errors.EdgeX) { ret := _m.Called(ctx, baseUrl, deviceName, commandName, queryParams) @@ -143,6 +173,66 @@ func (_m *DeviceServiceCommandClient) SetCommandWithObject(ctx context.Context, return r0, r1 } +// StopDeviceDiscovery provides a mock function with given fields: ctx, baseUrl, requestId, queryParams +func (_m *DeviceServiceCommandClient) StopDeviceDiscovery(ctx context.Context, baseUrl string, requestId string, queryParams map[string]string) (common.BaseResponse, errors.EdgeX) { + ret := _m.Called(ctx, baseUrl, requestId, queryParams) + + if len(ret) == 0 { + panic("no return value specified for StopDeviceDiscovery") + } + + var r0 common.BaseResponse + var r1 errors.EdgeX + if rf, ok := ret.Get(0).(func(context.Context, string, string, map[string]string) (common.BaseResponse, errors.EdgeX)); ok { + return rf(ctx, baseUrl, requestId, queryParams) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string, map[string]string) common.BaseResponse); ok { + r0 = rf(ctx, baseUrl, requestId, queryParams) + } else { + r0 = ret.Get(0).(common.BaseResponse) + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string, map[string]string) errors.EdgeX); ok { + r1 = rf(ctx, baseUrl, requestId, queryParams) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(errors.EdgeX) + } + } + + return r0, r1 +} + +// StopProfileScan provides a mock function with given fields: ctx, baseUrl, deviceName, queryParams +func (_m *DeviceServiceCommandClient) StopProfileScan(ctx context.Context, baseUrl string, deviceName string, queryParams map[string]string) (common.BaseResponse, errors.EdgeX) { + ret := _m.Called(ctx, baseUrl, deviceName, queryParams) + + if len(ret) == 0 { + panic("no return value specified for StopProfileScan") + } + + var r0 common.BaseResponse + var r1 errors.EdgeX + if rf, ok := ret.Get(0).(func(context.Context, string, string, map[string]string) (common.BaseResponse, errors.EdgeX)); ok { + return rf(ctx, baseUrl, deviceName, queryParams) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string, map[string]string) common.BaseResponse); ok { + r0 = rf(ctx, baseUrl, deviceName, queryParams) + } else { + r0 = ret.Get(0).(common.BaseResponse) + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string, map[string]string) errors.EdgeX); ok { + r1 = rf(ctx, baseUrl, deviceName, queryParams) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(errors.EdgeX) + } + } + + return r0, r1 +} + // NewDeviceServiceCommandClient creates a new instance of DeviceServiceCommandClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewDeviceServiceCommandClient(t interface { diff --git a/common/constants.go b/common/constants.go index 18d4e8fd..fbc4b7e7 100644 --- a/common/constants.go +++ b/common/constants.go @@ -121,16 +121,18 @@ const ( ApiSecretRoute = ApiBase + "/secret" ApiUnitsOfMeasureRoute = ApiBase + "/uom" - ApiDeviceCallbackRoute = ApiBase + "/callback/device" - ApiDeviceCallbackNameRoute = ApiBase + "/callback/device/name/{name}" - ApiProfileCallbackRoute = ApiBase + "/callback/profile" - ApiProfileCallbackNameRoute = ApiBase + "/callback/profile/name/{name}" - ApiWatcherCallbackRoute = ApiBase + "/callback/watcher" - ApiWatcherCallbackNameRoute = ApiBase + "/callback/watcher/name/{name}" - ApiServiceCallbackRoute = ApiBase + "/callback/service" - ApiDiscoveryRoute = ApiBase + "/discovery" - ApiDeviceValidationRoute = ApiBase + "/validate/device" - ApiProfileScan = ApiBase + "/profilescan" + ApiDeviceCallbackRoute = ApiBase + "/callback/device" + ApiDeviceCallbackNameRoute = ApiBase + "/callback/device/name/{name}" + ApiProfileCallbackRoute = ApiBase + "/callback/profile" + ApiProfileCallbackNameRoute = ApiBase + "/callback/profile/name/{name}" + ApiWatcherCallbackRoute = ApiBase + "/callback/watcher" + ApiWatcherCallbackNameRoute = ApiBase + "/callback/watcher/name/{name}" + ApiServiceCallbackRoute = ApiBase + "/callback/service" + ApiDiscoveryRoute = ApiBase + "/discovery" + ApiDeviceValidationRoute = ApiBase + "/validate/device" + ApiProfileScanRoute = ApiBase + "/profilescan" + ApiDiscoveryByIdRoute = ApiDiscoveryRoute + "/" + RequestId + "/{" + RequestId + "}" + ApiProfileScanByDeviceNameRoute = ApiProfileScanRoute + "/" + Device + "/" + Name + "/{" + Name + "}" ApiIntervalRoute = ApiBase + "/interval" ApiAllIntervalRoute = ApiIntervalRoute + "/" + All @@ -168,6 +170,7 @@ const ( Check = "check" Profile = "profile" Resource = "resource" + RequestId = "requestId" Service = "service" Services = "services" Command = "command" @@ -350,6 +353,8 @@ const ( SystemEventActionAdd = "add" SystemEventActionUpdate = "update" SystemEventActionDelete = "delete" + SystemEventActionDiscovery = "discovery" + SystemEventActionProfileScan = "profilescan" ) const ( diff --git a/common/echo_api_constants.go b/common/echo_api_constants.go index 65461034..e7e66c68 100644 --- a/common/echo_api_constants.go +++ b/common/echo_api_constants.go @@ -37,15 +37,17 @@ const ( ApiDeviceServiceByNameEchoRoute = ApiDeviceServiceRoute + "/" + Name + "/:" + Name ApiDeviceServiceByIdEchoRoute = ApiDeviceServiceRoute + "/" + Id + "/:" + Id - ApiDeviceIdExistsEchoRoute = ApiDeviceRoute + "/" + Check + "/" + Id + "/:" + Id - ApiDeviceNameExistsEchoRoute = ApiDeviceRoute + "/" + Check + "/" + Name + "/:" + Name - ApiDeviceByIdEchoRoute = ApiDeviceRoute + "/" + Id + "/:" + Id - ApiDeviceByNameEchoRoute = ApiDeviceRoute + "/" + Name + "/:" + Name - ApiDeviceByProfileIdEchoRoute = ApiDeviceRoute + "/" + Profile + "/" + Id + "/:" + Id - ApiDeviceByProfileNameEchoRoute = ApiDeviceRoute + "/" + Profile + "/" + Name + "/:" + Name - ApiDeviceByServiceIdEchoRoute = ApiDeviceRoute + "/" + Service + "/" + Id + "/:" + Id - ApiDeviceByServiceNameEchoRoute = ApiDeviceRoute + "/" + Service + "/" + Name + "/:" + Name - ApiDeviceNameCommandNameEchoRoute = ApiDeviceByNameEchoRoute + "/:" + Command + ApiDeviceIdExistsEchoRoute = ApiDeviceRoute + "/" + Check + "/" + Id + "/:" + Id + ApiDeviceNameExistsEchoRoute = ApiDeviceRoute + "/" + Check + "/" + Name + "/:" + Name + ApiDeviceByIdEchoRoute = ApiDeviceRoute + "/" + Id + "/:" + Id + ApiDeviceByNameEchoRoute = ApiDeviceRoute + "/" + Name + "/:" + Name + ApiDeviceByProfileIdEchoRoute = ApiDeviceRoute + "/" + Profile + "/" + Id + "/:" + Id + ApiDeviceByProfileNameEchoRoute = ApiDeviceRoute + "/" + Profile + "/" + Name + "/:" + Name + ApiDeviceByServiceIdEchoRoute = ApiDeviceRoute + "/" + Service + "/" + Id + "/:" + Id + ApiDeviceByServiceNameEchoRoute = ApiDeviceRoute + "/" + Service + "/" + Name + "/:" + Name + ApiDeviceNameCommandNameEchoRoute = ApiDeviceByNameEchoRoute + "/:" + Command + ApiDiscoveryByIdEchoRoute = ApiDiscoveryRoute + "/" + RequestId + "/:" + RequestId + ApiProfileScanByDeviceNameEchoRoute = ApiProfileScanRoute + "/" + Device + "/" + Name + "/:" + Name ApiProvisionWatcherByIdEchoRoute = ApiProvisionWatcherRoute + "/" + Id + "/:" + Id ApiProvisionWatcherByNameEchoRoute = ApiProvisionWatcherRoute + "/" + Name + "/:" + Name