From ce5fc9ebcb332eda6c3ed7649f5d6c543f1922dd Mon Sep 17 00:00:00 2001 From: weichou Date: Thu, 27 May 2021 16:59:47 +0800 Subject: [PATCH] feat: Create client library for support-notifications Create clients for Subscription, Notification, and Transmission APIs Close #573 Signed-off-by: weichou --- v2/clients/http/const_test.go | 6 + v2/clients/http/notification.go | 158 ++++++++++ v2/clients/http/notification_test.go | 153 ++++++++++ v2/clients/http/subscription.go | 121 ++++++++ v2/clients/http/subscription_test.go | 128 ++++++++ v2/clients/http/transmission.go | 102 +++++++ v2/clients/http/transmission_test.go | 86 ++++++ .../interfaces/mocks/NotificationClient.go | 277 ++++++++++++++++++ .../interfaces/mocks/SubscriptionClient.go | 210 +++++++++++++ .../interfaces/mocks/TransmissionClient.go | 158 ++++++++++ v2/clients/interfaces/notification.go | 44 +++ v2/clients/interfaces/subscription.go | 35 +++ v2/clients/interfaces/transmission.go | 30 ++ 13 files changed, 1508 insertions(+) create mode 100644 v2/clients/http/notification.go create mode 100644 v2/clients/http/notification_test.go create mode 100644 v2/clients/http/subscription.go create mode 100644 v2/clients/http/subscription_test.go create mode 100644 v2/clients/http/transmission.go create mode 100644 v2/clients/http/transmission_test.go create mode 100644 v2/clients/interfaces/mocks/NotificationClient.go create mode 100644 v2/clients/interfaces/mocks/SubscriptionClient.go create mode 100644 v2/clients/interfaces/mocks/TransmissionClient.go create mode 100644 v2/clients/interfaces/notification.go create mode 100644 v2/clients/interfaces/subscription.go create mode 100644 v2/clients/interfaces/transmission.go diff --git a/v2/clients/http/const_test.go b/v2/clients/http/const_test.go index 0e0ab1d5..e51174bc 100644 --- a/v2/clients/http/const_test.go +++ b/v2/clients/http/const_test.go @@ -12,4 +12,10 @@ const ( TestHost = "localhost" TestPort = 48089 TestHTTPMethod = "GET" + + TestSubscriptionName = "TestSubscriptionName" + TestReceiver = "user" + TestCategory = "health-check" + TestLabel = "rest" + ExampleUUID = "82eb2e26-0f24-48aa-ae4c-de9dac3fb9bc" ) diff --git a/v2/clients/http/notification.go b/v2/clients/http/notification.go new file mode 100644 index 00000000..73df4125 --- /dev/null +++ b/v2/clients/http/notification.go @@ -0,0 +1,158 @@ +// +// Copyright (C) 2021 IOTech Ltd +// +// SPDX-License-Identifier: Apache-2.0 + +package http + +import ( + "context" + "net/url" + "path" + "strconv" + + "github.com/edgexfoundry/go-mod-core-contracts/v2/errors" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/clients/http/utils" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/clients/interfaces" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos/common" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos/requests" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos/responses" +) + +type NotificationClient struct { + baseUrl string +} + +// NewNotificationClient creates an instance of NotificationClient +func NewNotificationClient(baseUrl string) interfaces.NotificationClient { + return &NotificationClient{ + baseUrl: baseUrl, + } +} + +// Add adds new notifications. +func (client *NotificationClient) Add(ctx context.Context, reqs []requests.AddNotificationRequest) (res []common.BaseWithIdResponse, err errors.EdgeX) { + err = utils.PostRequestWithRawData(ctx, &res, client.baseUrl+v2.ApiNotificationRoute, reqs) + if err != nil { + return res, errors.NewCommonEdgeXWrapper(err) + } + return res, nil +} + +// NotificationById query notification by id. +func (client *NotificationClient) NotificationById(ctx context.Context, id string) (res responses.NotificationResponse, err errors.EdgeX) { + path := path.Join(v2.ApiNotificationRoute, v2.Id, url.QueryEscape(id)) + err = utils.GetRequest(ctx, &res, client.baseUrl, path, nil) + if err != nil { + return res, errors.NewCommonEdgeXWrapper(err) + } + return res, nil +} + +// DeleteNotificationById deletes a notification by id. +func (client *NotificationClient) DeleteNotificationById(ctx context.Context, id string) (res common.BaseResponse, err errors.EdgeX) { + path := path.Join(v2.ApiNotificationRoute, v2.Id, url.QueryEscape(id)) + err = utils.DeleteRequest(ctx, &res, client.baseUrl, path) + if err != nil { + return res, errors.NewCommonEdgeXWrapper(err) + } + return res, nil +} + +// NotificationsByCategory queries notifications with category, offset and limit +func (client *NotificationClient) NotificationsByCategory(ctx context.Context, category string, offset int, limit int) (res responses.MultiNotificationsResponse, err errors.EdgeX) { + requestPath := path.Join(v2.ApiNotificationRoute, v2.Category, url.QueryEscape(category)) + requestParams := url.Values{} + requestParams.Set(v2.Offset, strconv.Itoa(offset)) + requestParams.Set(v2.Limit, strconv.Itoa(limit)) + err = utils.GetRequest(ctx, &res, client.baseUrl, requestPath, requestParams) + if err != nil { + return res, errors.NewCommonEdgeXWrapper(err) + } + return res, nil +} + +// NotificationsByLabel queries notifications with label, offset and limit +func (client *NotificationClient) NotificationsByLabel(ctx context.Context, label string, offset int, limit int) (res responses.MultiNotificationsResponse, err errors.EdgeX) { + requestPath := path.Join(v2.ApiNotificationRoute, v2.Label, url.QueryEscape(label)) + requestParams := url.Values{} + requestParams.Set(v2.Offset, strconv.Itoa(offset)) + requestParams.Set(v2.Limit, strconv.Itoa(limit)) + err = utils.GetRequest(ctx, &res, client.baseUrl, requestPath, requestParams) + if err != nil { + return res, errors.NewCommonEdgeXWrapper(err) + } + return res, nil +} + +// NotificationsByStatus queries notifications with status, offset and limit +func (client *NotificationClient) NotificationsByStatus(ctx context.Context, status string, offset int, limit int) (res responses.MultiNotificationsResponse, err errors.EdgeX) { + requestPath := path.Join(v2.ApiNotificationRoute, v2.Status, url.QueryEscape(status)) + requestParams := url.Values{} + requestParams.Set(v2.Offset, strconv.Itoa(offset)) + requestParams.Set(v2.Limit, strconv.Itoa(limit)) + err = utils.GetRequest(ctx, &res, client.baseUrl, requestPath, requestParams) + if err != nil { + return res, errors.NewCommonEdgeXWrapper(err) + } + return res, nil +} + +// NotificationsByTimeRange query notifications with time range, offset and limit +func (client *NotificationClient) NotificationsByTimeRange(ctx context.Context, start int, end int, offset int, limit int) (res responses.MultiNotificationsResponse, err errors.EdgeX) { + requestPath := path.Join(v2.ApiNotificationRoute, v2.Start, strconv.Itoa(start), v2.End, strconv.Itoa(end)) + requestParams := url.Values{} + requestParams.Set(v2.Offset, strconv.Itoa(offset)) + requestParams.Set(v2.Limit, strconv.Itoa(limit)) + err = utils.GetRequest(ctx, &res, client.baseUrl, requestPath, requestParams) + if err != nil { + return res, errors.NewCommonEdgeXWrapper(err) + } + return res, nil +} + +// NotificationsBySubscriptionName query notifications with subscriptionName, offset and limit +func (client *NotificationClient) NotificationsBySubscriptionName(ctx context.Context, subscriptionName string, offset int, limit int) (res responses.MultiNotificationsResponse, err errors.EdgeX) { + requestPath := path.Join(v2.ApiNotificationRoute, v2.Subscription, v2.Name, url.QueryEscape(subscriptionName)) + requestParams := url.Values{} + requestParams.Set(v2.Offset, strconv.Itoa(offset)) + requestParams.Set(v2.Limit, strconv.Itoa(limit)) + err = utils.GetRequest(ctx, &res, client.baseUrl, requestPath, requestParams) + if err != nil { + return res, errors.NewCommonEdgeXWrapper(err) + } + return res, nil +} + +// CleanupNotificationsByAge removes notifications that are older than age. And the corresponding transmissions will also be deleted. +// Age is supposed in milliseconds since modified timestamp +func (client *NotificationClient) CleanupNotificationsByAge(ctx context.Context, age int) (res common.BaseResponse, err errors.EdgeX) { + path := path.Join(v2.ApiNotificationCleanupRoute, v2.Age, strconv.Itoa(age)) + err = utils.DeleteRequest(ctx, &res, client.baseUrl, path) + if err != nil { + return res, errors.NewCommonEdgeXWrapper(err) + } + return res, nil +} + +// CleanupNotifications removes notifications and the corresponding transmissions. +func (client *NotificationClient) CleanupNotifications(ctx context.Context) (res common.BaseResponse, err errors.EdgeX) { + err = utils.DeleteRequest(ctx, &res, client.baseUrl, v2.ApiNotificationCleanupRoute) + if err != nil { + return res, errors.NewCommonEdgeXWrapper(err) + } + return res, nil +} + +// DeleteProcessedNotificationsByAge removes processed notifications that are older than age. And the corresponding transmissions will also be deleted. +// Age is supposed in milliseconds since modified timestamp +// Please notice that this API is only for processed notifications (status = PROCESSED). If the deletion purpose includes each kind of notifications, please refer to cleanup API. +func (client *NotificationClient) DeleteProcessedNotificationsByAge(ctx context.Context, age int) (res common.BaseResponse, err errors.EdgeX) { + path := path.Join(v2.ApiNotificationRoute, v2.Age, strconv.Itoa(age)) + err = utils.DeleteRequest(ctx, &res, client.baseUrl, path) + if err != nil { + return res, errors.NewCommonEdgeXWrapper(err) + } + return res, nil +} diff --git a/v2/clients/http/notification_test.go b/v2/clients/http/notification_test.go new file mode 100644 index 00000000..616c8f56 --- /dev/null +++ b/v2/clients/http/notification_test.go @@ -0,0 +1,153 @@ +// +// Copyright (C) 2021 IOTech Ltd +// +// SPDX-License-Identifier: Apache-2.0 + +package http + +import ( + "context" + "net/http" + "path" + "strconv" + "testing" + + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2" + "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/requests" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos/responses" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/models" + + "github.com/stretchr/testify/require" +) + +func addNotificationRequest() requests.AddNotificationRequest { + return requests.NewAddNotificationRequest( + dtos.Notification{ + Id: ExampleUUID, + Content: "testContent", + Sender: "testSender", + Labels: []string{TestLabel}, + Severity: models.Critical, + }, + ) +} + +func TestNotificationClient_Add(t *testing.T) { + ts := newTestServer(http.MethodPost, v2.ApiNotificationRoute, []common.BaseWithIdResponse{}) + defer ts.Close() + client := NewNotificationClient(ts.URL) + res, err := client.Add(context.Background(), []requests.AddNotificationRequest{addNotificationRequest()}) + require.NoError(t, err) + require.IsType(t, []common.BaseWithIdResponse{}, res) +} + +func TestNotificationClient_NotificationById(t *testing.T) { + testId := ExampleUUID + path := path.Join(v2.ApiNotificationRoute, v2.Id, testId) + ts := newTestServer(http.MethodGet, path, responses.NotificationResponse{}) + defer ts.Close() + client := NewNotificationClient(ts.URL) + res, err := client.NotificationById(context.Background(), testId) + require.NoError(t, err) + require.IsType(t, responses.NotificationResponse{}, res) +} + +func TestNotificationClient_NotificationsByCategory(t *testing.T) { + category := TestCategory + urlPath := path.Join(v2.ApiNotificationRoute, v2.Category, category) + ts := newTestServer(http.MethodGet, urlPath, responses.MultiNotificationsResponse{}) + defer ts.Close() + client := NewNotificationClient(ts.URL) + res, err := client.NotificationsByCategory(context.Background(), category, 0, 10) + require.NoError(t, err) + require.IsType(t, responses.MultiNotificationsResponse{}, res) +} + +func TestNotificationClient_NotificationsByLabel(t *testing.T) { + label := TestLabel + urlPath := path.Join(v2.ApiNotificationRoute, v2.Label, label) + ts := newTestServer(http.MethodGet, urlPath, responses.MultiNotificationsResponse{}) + defer ts.Close() + client := NewNotificationClient(ts.URL) + res, err := client.NotificationsByLabel(context.Background(), label, 0, 10) + require.NoError(t, err) + require.IsType(t, responses.MultiNotificationsResponse{}, res) +} + +func TestNotificationClient_NotificationsByStatus(t *testing.T) { + status := models.Processed + urlPath := path.Join(v2.ApiNotificationRoute, v2.Status, status) + ts := newTestServer(http.MethodGet, urlPath, responses.MultiNotificationsResponse{}) + defer ts.Close() + client := NewNotificationClient(ts.URL) + res, err := client.NotificationsByStatus(context.Background(), status, 0, 10) + require.NoError(t, err) + require.IsType(t, responses.MultiNotificationsResponse{}, res) +} + +func TestNotificationClient_NotificationsBySubscriptionName(t *testing.T) { + subscriptionName := TestSubscriptionName + urlPath := path.Join(v2.ApiNotificationRoute, v2.Subscription, v2.Name, subscriptionName) + ts := newTestServer(http.MethodGet, urlPath, responses.MultiNotificationsResponse{}) + defer ts.Close() + client := NewNotificationClient(ts.URL) + res, err := client.NotificationsBySubscriptionName(context.Background(), subscriptionName, 0, 10) + require.NoError(t, err) + require.IsType(t, responses.MultiNotificationsResponse{}, res) +} + +func TestNotificationClient_NotificationsByTimeRange(t *testing.T) { + start := 1 + end := 10 + urlPath := path.Join(v2.ApiNotificationRoute, v2.Start, strconv.Itoa(start), v2.End, strconv.Itoa(end)) + ts := newTestServer(http.MethodGet, urlPath, responses.MultiNotificationsResponse{}) + defer ts.Close() + client := NewNotificationClient(ts.URL) + res, err := client.NotificationsByTimeRange(context.Background(), start, end, 0, 10) + require.NoError(t, err) + require.IsType(t, responses.MultiNotificationsResponse{}, res) +} + +func TestNotificationClient_CleanupNotifications(t *testing.T) { + ts := newTestServer(http.MethodDelete, v2.ApiNotificationCleanupRoute, common.BaseResponse{}) + defer ts.Close() + client := NewNotificationClient(ts.URL) + res, err := client.CleanupNotifications(context.Background()) + require.NoError(t, err) + require.IsType(t, common.BaseResponse{}, res) +} + +func TestNotificationClient_CleanupNotificationsByAge(t *testing.T) { + age := 0 + path := path.Join(v2.ApiNotificationCleanupRoute, v2.Age, strconv.Itoa(age)) + ts := newTestServer(http.MethodDelete, path, common.BaseResponse{}) + defer ts.Close() + client := NewNotificationClient(ts.URL) + res, err := client.CleanupNotificationsByAge(context.Background(), age) + require.NoError(t, err) + require.IsType(t, common.BaseResponse{}, res) +} + +func TestNotificationClient_DeleteNotificationById(t *testing.T) { + id := ExampleUUID + path := path.Join(v2.ApiNotificationRoute, v2.Id, id) + ts := newTestServer(http.MethodDelete, path, common.BaseResponse{}) + defer ts.Close() + client := NewNotificationClient(ts.URL) + res, err := client.DeleteNotificationById(context.Background(), id) + require.NoError(t, err) + require.IsType(t, common.BaseResponse{}, res) +} + +func TestNotificationClient_DeleteProcessedNotificationsByAge(t *testing.T) { + age := 0 + path := path.Join(v2.ApiNotificationRoute, v2.Age, strconv.Itoa(age)) + ts := newTestServer(http.MethodDelete, path, common.BaseResponse{}) + defer ts.Close() + client := NewNotificationClient(ts.URL) + res, err := client.DeleteProcessedNotificationsByAge(context.Background(), age) + require.NoError(t, err) + require.IsType(t, common.BaseResponse{}, res) +} diff --git a/v2/clients/http/subscription.go b/v2/clients/http/subscription.go new file mode 100644 index 00000000..83803125 --- /dev/null +++ b/v2/clients/http/subscription.go @@ -0,0 +1,121 @@ +// +// Copyright (C) 2021 IOTech Ltd +// +// SPDX-License-Identifier: Apache-2.0 + +package http + +import ( + "context" + "net/url" + "path" + "strconv" + + "github.com/edgexfoundry/go-mod-core-contracts/v2/errors" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/clients/http/utils" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/clients/interfaces" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos/common" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos/requests" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos/responses" +) + +type SubscriptionClient struct { + baseUrl string +} + +// NewSubscriptionClient creates an instance of SubscriptionClient +func NewSubscriptionClient(baseUrl string) interfaces.SubscriptionClient { + return &SubscriptionClient{ + baseUrl: baseUrl, + } +} + +// Add adds new subscriptions. +func (client *SubscriptionClient) Add(ctx context.Context, reqs []requests.AddSubscriptionRequest) (res []common.BaseWithIdResponse, err errors.EdgeX) { + err = utils.PostRequestWithRawData(ctx, &res, client.baseUrl+v2.ApiSubscriptionRoute, reqs) + if err != nil { + return res, errors.NewCommonEdgeXWrapper(err) + } + return res, nil +} + +// Update updates subscriptions. +func (client *SubscriptionClient) Update(ctx context.Context, reqs []requests.UpdateSubscriptionRequest) (res []common.BaseResponse, err errors.EdgeX) { + err = utils.PatchRequest(ctx, &res, client.baseUrl+v2.ApiSubscriptionRoute, reqs) + if err != nil { + return res, errors.NewCommonEdgeXWrapper(err) + } + return res, nil +} + +// AllSubscriptions queries subscriptions with offset and limit +func (client *SubscriptionClient) AllSubscriptions(ctx context.Context, offset int, limit int) (res responses.MultiSubscriptionsResponse, err errors.EdgeX) { + requestParams := url.Values{} + requestParams.Set(v2.Offset, strconv.Itoa(offset)) + requestParams.Set(v2.Limit, strconv.Itoa(limit)) + err = utils.GetRequest(ctx, &res, client.baseUrl, v2.ApiAllSubscriptionRoute, requestParams) + if err != nil { + return res, errors.NewCommonEdgeXWrapper(err) + } + return res, nil +} + +// SubscriptionsByCategory queries subscriptions with category, offset and limit +func (client *SubscriptionClient) SubscriptionsByCategory(ctx context.Context, category string, offset int, limit int) (res responses.MultiSubscriptionsResponse, err errors.EdgeX) { + requestPath := path.Join(v2.ApiSubscriptionRoute, v2.Category, url.QueryEscape(category)) + requestParams := url.Values{} + requestParams.Set(v2.Offset, strconv.Itoa(offset)) + requestParams.Set(v2.Limit, strconv.Itoa(limit)) + err = utils.GetRequest(ctx, &res, client.baseUrl, requestPath, requestParams) + if err != nil { + return res, errors.NewCommonEdgeXWrapper(err) + } + return res, nil +} + +// SubscriptionsByLabel queries subscriptions with label, offset and limit +func (client *SubscriptionClient) SubscriptionsByLabel(ctx context.Context, label string, offset int, limit int) (res responses.MultiSubscriptionsResponse, err errors.EdgeX) { + requestPath := path.Join(v2.ApiSubscriptionRoute, v2.Label, url.QueryEscape(label)) + requestParams := url.Values{} + requestParams.Set(v2.Offset, strconv.Itoa(offset)) + requestParams.Set(v2.Limit, strconv.Itoa(limit)) + err = utils.GetRequest(ctx, &res, client.baseUrl, requestPath, requestParams) + if err != nil { + return res, errors.NewCommonEdgeXWrapper(err) + } + return res, nil +} + +// SubscriptionsByReceiver queries subscriptions with receiver, offset and limit +func (client *SubscriptionClient) SubscriptionsByReceiver(ctx context.Context, receiver string, offset int, limit int) (res responses.MultiSubscriptionsResponse, err errors.EdgeX) { + requestPath := path.Join(v2.ApiSubscriptionRoute, v2.Receiver, url.QueryEscape(receiver)) + requestParams := url.Values{} + requestParams.Set(v2.Offset, strconv.Itoa(offset)) + requestParams.Set(v2.Limit, strconv.Itoa(limit)) + err = utils.GetRequest(ctx, &res, client.baseUrl, requestPath, requestParams) + if err != nil { + return res, errors.NewCommonEdgeXWrapper(err) + } + return res, nil +} + +// SubscriptionByName query subscription by name. +func (client *SubscriptionClient) SubscriptionByName(ctx context.Context, name string) (res responses.SubscriptionResponse, err errors.EdgeX) { + path := path.Join(v2.ApiSubscriptionRoute, v2.Name, url.QueryEscape(name)) + err = utils.GetRequest(ctx, &res, client.baseUrl, path, nil) + if err != nil { + return res, errors.NewCommonEdgeXWrapper(err) + } + return res, nil +} + +// DeleteSubscriptionByName deletes a subscription by name. +func (client *SubscriptionClient) DeleteSubscriptionByName(ctx context.Context, name string) (res common.BaseResponse, err errors.EdgeX) { + path := path.Join(v2.ApiSubscriptionRoute, v2.Name, url.QueryEscape(name)) + err = utils.DeleteRequest(ctx, &res, client.baseUrl, path) + if err != nil { + return res, errors.NewCommonEdgeXWrapper(err) + } + return res, nil +} diff --git a/v2/clients/http/subscription_test.go b/v2/clients/http/subscription_test.go new file mode 100644 index 00000000..d64a8727 --- /dev/null +++ b/v2/clients/http/subscription_test.go @@ -0,0 +1,128 @@ +// +// Copyright (C) 2021 IOTech Ltd +// +// SPDX-License-Identifier: Apache-2.0 + +package http + +import ( + "context" + "net/http" + "path" + "testing" + + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2" + "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/requests" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos/responses" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/models" + + "github.com/stretchr/testify/require" +) + +func addSubscriptionRequest() requests.AddSubscriptionRequest { + return requests.NewAddSubscriptionRequest( + dtos.Subscription{ + Name: TestSubscriptionName, + Channels: []dtos.Address{dtos.NewRESTAddress(TestHost, TestPort, http.MethodGet)}, + Receiver: TestReceiver, + Categories: []string{TestCategory}, + Labels: []string{TestLabel}, + Description: "Test data for subscription", + AdminState: models.Unlocked, + }, + ) +} + +func updateSubscriptionRequest() requests.UpdateSubscriptionRequest { + name := TestSubscriptionName + return requests.NewUpdateSubscriptionRequest( + dtos.UpdateSubscription{ + Name: &name, + Channels: []dtos.Address{dtos.NewRESTAddress(TestHost, TestPort, http.MethodPut)}, + }, + ) +} + +func TestSubscriptionClient_Add(t *testing.T) { + ts := newTestServer(http.MethodPost, v2.ApiSubscriptionRoute, []common.BaseWithIdResponse{}) + defer ts.Close() + client := NewSubscriptionClient(ts.URL) + res, err := client.Add(context.Background(), []requests.AddSubscriptionRequest{addSubscriptionRequest()}) + require.NoError(t, err) + require.IsType(t, []common.BaseWithIdResponse{}, res) +} + +func TestSubscriptionClient_Update(t *testing.T) { + ts := newTestServer(http.MethodPatch, v2.ApiSubscriptionRoute, []common.BaseResponse{}) + defer ts.Close() + client := NewSubscriptionClient(ts.URL) + res, err := client.Update(context.Background(), []requests.UpdateSubscriptionRequest{updateSubscriptionRequest()}) + require.NoError(t, err) + require.IsType(t, []common.BaseResponse{}, res) +} + +func TestSubscriptionClient_AllSubscriptions(t *testing.T) { + ts := newTestServer(http.MethodGet, v2.ApiAllSubscriptionRoute, responses.MultiSubscriptionsResponse{}) + defer ts.Close() + client := NewSubscriptionClient(ts.URL) + res, err := client.AllSubscriptions(context.Background(), 0, 10) + require.NoError(t, err) + require.IsType(t, responses.MultiSubscriptionsResponse{}, res) +} + +func TestSubscriptionClient_DeleteSubscriptionByName(t *testing.T) { + subscriptionName := TestSubscriptionName + path := path.Join(v2.ApiSubscriptionRoute, v2.Name, subscriptionName) + ts := newTestServer(http.MethodDelete, path, common.BaseResponse{}) + defer ts.Close() + client := NewSubscriptionClient(ts.URL) + res, err := client.DeleteSubscriptionByName(context.Background(), subscriptionName) + require.NoError(t, err) + require.IsType(t, common.BaseResponse{}, res) +} + +func TestSubscriptionClient_SubscriptionByName(t *testing.T) { + subscriptionName := TestSubscriptionName + path := path.Join(v2.ApiSubscriptionRoute, v2.Name, subscriptionName) + ts := newTestServer(http.MethodGet, path, responses.SubscriptionResponse{}) + defer ts.Close() + client := NewSubscriptionClient(ts.URL) + res, err := client.SubscriptionByName(context.Background(), subscriptionName) + require.NoError(t, err) + require.IsType(t, responses.SubscriptionResponse{}, res) +} + +func TestSubscriptionClient_SubscriptionsByCategory(t *testing.T) { + category := TestCategory + urlPath := path.Join(v2.ApiSubscriptionRoute, v2.Category, category) + ts := newTestServer(http.MethodGet, urlPath, responses.MultiSubscriptionsResponse{}) + defer ts.Close() + client := NewSubscriptionClient(ts.URL) + res, err := client.SubscriptionsByCategory(context.Background(), category, 0, 10) + require.NoError(t, err) + require.IsType(t, responses.MultiSubscriptionsResponse{}, res) +} + +func TestSubscriptionClient_SubscriptionsByLabel(t *testing.T) { + label := TestLabel + urlPath := path.Join(v2.ApiSubscriptionRoute, v2.Label, label) + ts := newTestServer(http.MethodGet, urlPath, responses.MultiSubscriptionsResponse{}) + defer ts.Close() + client := NewSubscriptionClient(ts.URL) + res, err := client.SubscriptionsByLabel(context.Background(), label, 0, 10) + require.NoError(t, err) + require.IsType(t, responses.MultiSubscriptionsResponse{}, res) +} + +func TestSubscriptionClient_SubscriptionsByReceiver(t *testing.T) { + receiver := TestReceiver + urlPath := path.Join(v2.ApiSubscriptionRoute, v2.Receiver, receiver) + ts := newTestServer(http.MethodGet, urlPath, responses.MultiSubscriptionsResponse{}) + defer ts.Close() + client := NewSubscriptionClient(ts.URL) + res, err := client.SubscriptionsByReceiver(context.Background(), receiver, 0, 10) + require.NoError(t, err) + require.IsType(t, responses.MultiSubscriptionsResponse{}, res) +} diff --git a/v2/clients/http/transmission.go b/v2/clients/http/transmission.go new file mode 100644 index 00000000..332b06f7 --- /dev/null +++ b/v2/clients/http/transmission.go @@ -0,0 +1,102 @@ +// +// Copyright (C) 2021 IOTech Ltd +// +// SPDX-License-Identifier: Apache-2.0 + +package http + +import ( + "context" + "net/url" + "path" + "strconv" + + "github.com/edgexfoundry/go-mod-core-contracts/v2/errors" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/clients/http/utils" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/clients/interfaces" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos/common" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos/responses" +) + +type TransmissionClient struct { + baseUrl string +} + +// NewTransmissionClient creates an instance of TransmissionClient +func NewTransmissionClient(baseUrl string) interfaces.TransmissionClient { + return &TransmissionClient{ + baseUrl: baseUrl, + } +} + +// TransmissionById query transmission by id. +func (client *TransmissionClient) TransmissionById(ctx context.Context, id string) (res responses.TransmissionResponse, err errors.EdgeX) { + path := path.Join(v2.ApiTransmissionRoute, v2.Id, url.QueryEscape(id)) + err = utils.GetRequest(ctx, &res, client.baseUrl, path, nil) + if err != nil { + return res, errors.NewCommonEdgeXWrapper(err) + } + return res, nil +} + +// TransmissionsByTimeRange query transmissions with time range, offset and limit +func (client *TransmissionClient) TransmissionsByTimeRange(ctx context.Context, start int, end int, offset int, limit int) (res responses.MultiTransmissionsResponse, err errors.EdgeX) { + requestPath := path.Join(v2.ApiTransmissionRoute, v2.Start, strconv.Itoa(start), v2.End, strconv.Itoa(end)) + requestParams := url.Values{} + requestParams.Set(v2.Offset, strconv.Itoa(offset)) + requestParams.Set(v2.Limit, strconv.Itoa(limit)) + err = utils.GetRequest(ctx, &res, client.baseUrl, requestPath, requestParams) + if err != nil { + return res, errors.NewCommonEdgeXWrapper(err) + } + return res, nil +} + +// AllTransmissions query transmissions with offset and limit +func (client *TransmissionClient) AllTransmissions(ctx context.Context, offset int, limit int) (res responses.MultiTransmissionsResponse, err errors.EdgeX) { + requestParams := url.Values{} + requestParams.Set(v2.Offset, strconv.Itoa(offset)) + requestParams.Set(v2.Limit, strconv.Itoa(limit)) + err = utils.GetRequest(ctx, &res, client.baseUrl, v2.ApiAllTransmissionRoute, requestParams) + if err != nil { + return res, errors.NewCommonEdgeXWrapper(err) + } + return res, nil +} + +// TransmissionsByStatus queries transmissions with status, offset and limit +func (client *TransmissionClient) TransmissionsByStatus(ctx context.Context, status string, offset int, limit int) (res responses.MultiTransmissionsResponse, err errors.EdgeX) { + requestPath := path.Join(v2.ApiTransmissionRoute, v2.Status, url.QueryEscape(status)) + requestParams := url.Values{} + requestParams.Set(v2.Offset, strconv.Itoa(offset)) + requestParams.Set(v2.Limit, strconv.Itoa(limit)) + err = utils.GetRequest(ctx, &res, client.baseUrl, requestPath, requestParams) + if err != nil { + return res, errors.NewCommonEdgeXWrapper(err) + } + return res, nil +} + +// DeleteProcessedTransmissionsByAge deletes the processed transmissions if the current timestamp minus their created timestamp is less than the age parameter. +func (client *TransmissionClient) DeleteProcessedTransmissionsByAge(ctx context.Context, age int) (res common.BaseResponse, err errors.EdgeX) { + path := path.Join(v2.ApiTransmissionRoute, v2.Age, strconv.Itoa(age)) + err = utils.DeleteRequest(ctx, &res, client.baseUrl, path) + if err != nil { + return res, errors.NewCommonEdgeXWrapper(err) + } + return res, nil +} + +// TransmissionsBySubscriptionName query transmissions with subscriptionName, offset and limit +func (client *TransmissionClient) TransmissionsBySubscriptionName(ctx context.Context, subscriptionName string, offset int, limit int) (res responses.MultiTransmissionsResponse, err errors.EdgeX) { + requestPath := path.Join(v2.ApiTransmissionRoute, v2.Subscription, v2.Name, url.QueryEscape(subscriptionName)) + requestParams := url.Values{} + requestParams.Set(v2.Offset, strconv.Itoa(offset)) + requestParams.Set(v2.Limit, strconv.Itoa(limit)) + err = utils.GetRequest(ctx, &res, client.baseUrl, requestPath, requestParams) + if err != nil { + return res, errors.NewCommonEdgeXWrapper(err) + } + return res, nil +} diff --git a/v2/clients/http/transmission_test.go b/v2/clients/http/transmission_test.go new file mode 100644 index 00000000..dccad0a7 --- /dev/null +++ b/v2/clients/http/transmission_test.go @@ -0,0 +1,86 @@ +// +// Copyright (C) 2021 IOTech Ltd +// +// SPDX-License-Identifier: Apache-2.0 + +package http + +import ( + "context" + "net/http" + "path" + "strconv" + "testing" + + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2" + "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/stretchr/testify/require" +) + +func TestTransmissionClient_AllTransmissions(t *testing.T) { + ts := newTestServer(http.MethodGet, v2.ApiAllTransmissionRoute, responses.MultiTransmissionsResponse{}) + defer ts.Close() + client := NewTransmissionClient(ts.URL) + res, err := client.AllTransmissions(context.Background(), 0, 10) + require.NoError(t, err) + require.IsType(t, responses.MultiTransmissionsResponse{}, res) +} + +func TestTransmissionClient_DeleteProcessedTransmissionsByAge(t *testing.T) { + age := 0 + path := path.Join(v2.ApiTransmissionRoute, v2.Age, strconv.Itoa(age)) + ts := newTestServer(http.MethodDelete, path, common.BaseResponse{}) + defer ts.Close() + client := NewTransmissionClient(ts.URL) + res, err := client.DeleteProcessedTransmissionsByAge(context.Background(), age) + require.NoError(t, err) + require.IsType(t, common.BaseResponse{}, res) +} + +func TestTransmissionClient_TransmissionById(t *testing.T) { + testId := ExampleUUID + path := path.Join(v2.ApiTransmissionRoute, v2.Id, testId) + ts := newTestServer(http.MethodGet, path, responses.TransmissionResponse{}) + defer ts.Close() + client := NewTransmissionClient(ts.URL) + res, err := client.TransmissionById(context.Background(), testId) + require.NoError(t, err) + require.IsType(t, responses.TransmissionResponse{}, res) +} + +func TestTransmissionClient_TransmissionsByStatus(t *testing.T) { + status := models.Escalated + urlPath := path.Join(v2.ApiTransmissionRoute, v2.Status, status) + ts := newTestServer(http.MethodGet, urlPath, responses.MultiTransmissionsResponse{}) + defer ts.Close() + client := NewTransmissionClient(ts.URL) + res, err := client.TransmissionsByStatus(context.Background(), status, 0, 10) + require.NoError(t, err) + require.IsType(t, responses.MultiTransmissionsResponse{}, res) +} + +func TestTransmissionClient_TransmissionsBySubscriptionName(t *testing.T) { + subscriptionName := TestSubscriptionName + urlPath := path.Join(v2.ApiTransmissionRoute, v2.Subscription, v2.Name, subscriptionName) + ts := newTestServer(http.MethodGet, urlPath, responses.MultiTransmissionsResponse{}) + defer ts.Close() + client := NewTransmissionClient(ts.URL) + res, err := client.TransmissionsBySubscriptionName(context.Background(), subscriptionName, 0, 10) + require.NoError(t, err) + require.IsType(t, responses.MultiTransmissionsResponse{}, res) +} + +func TestTransmissionClient_TransmissionsByTimeRange(t *testing.T) { + start := 1 + end := 10 + urlPath := path.Join(v2.ApiTransmissionRoute, v2.Start, strconv.Itoa(start), v2.End, strconv.Itoa(end)) + ts := newTestServer(http.MethodGet, urlPath, responses.MultiTransmissionsResponse{}) + defer ts.Close() + client := NewTransmissionClient(ts.URL) + res, err := client.TransmissionsByTimeRange(context.Background(), start, end, 0, 10) + require.NoError(t, err) + require.IsType(t, responses.MultiTransmissionsResponse{}, res) +} diff --git a/v2/clients/interfaces/mocks/NotificationClient.go b/v2/clients/interfaces/mocks/NotificationClient.go new file mode 100644 index 00000000..1b5f970d --- /dev/null +++ b/v2/clients/interfaces/mocks/NotificationClient.go @@ -0,0 +1,277 @@ +// Code generated by mockery v2.7.4. DO NOT EDIT. + +package mocks + +import ( + context "context" + + common "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos/common" + + errors "github.com/edgexfoundry/go-mod-core-contracts/v2/errors" + + mock "github.com/stretchr/testify/mock" + + requests "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos/requests" + + responses "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos/responses" +) + +// NotificationClient is an autogenerated mock type for the NotificationClient type +type NotificationClient struct { + mock.Mock +} + +// Add provides a mock function with given fields: ctx, reqs +func (_m *NotificationClient) Add(ctx context.Context, reqs []requests.AddNotificationRequest) ([]common.BaseWithIdResponse, errors.EdgeX) { + ret := _m.Called(ctx, reqs) + + var r0 []common.BaseWithIdResponse + if rf, ok := ret.Get(0).(func(context.Context, []requests.AddNotificationRequest) []common.BaseWithIdResponse); ok { + r0 = rf(ctx, reqs) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]common.BaseWithIdResponse) + } + } + + var r1 errors.EdgeX + if rf, ok := ret.Get(1).(func(context.Context, []requests.AddNotificationRequest) errors.EdgeX); ok { + r1 = rf(ctx, reqs) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(errors.EdgeX) + } + } + + return r0, r1 +} + +// CleanupNotifications provides a mock function with given fields: ctx +func (_m *NotificationClient) CleanupNotifications(ctx context.Context) (common.BaseResponse, errors.EdgeX) { + ret := _m.Called(ctx) + + var r0 common.BaseResponse + if rf, ok := ret.Get(0).(func(context.Context) common.BaseResponse); ok { + r0 = rf(ctx) + } else { + r0 = ret.Get(0).(common.BaseResponse) + } + + var r1 errors.EdgeX + if rf, ok := ret.Get(1).(func(context.Context) errors.EdgeX); ok { + r1 = rf(ctx) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(errors.EdgeX) + } + } + + return r0, r1 +} + +// CleanupNotificationsByAge provides a mock function with given fields: ctx, age +func (_m *NotificationClient) CleanupNotificationsByAge(ctx context.Context, age int) (common.BaseResponse, errors.EdgeX) { + ret := _m.Called(ctx, age) + + var r0 common.BaseResponse + if rf, ok := ret.Get(0).(func(context.Context, int) common.BaseResponse); ok { + r0 = rf(ctx, age) + } else { + r0 = ret.Get(0).(common.BaseResponse) + } + + var r1 errors.EdgeX + if rf, ok := ret.Get(1).(func(context.Context, int) errors.EdgeX); ok { + r1 = rf(ctx, age) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(errors.EdgeX) + } + } + + return r0, r1 +} + +// DeleteNotificationById provides a mock function with given fields: ctx, id +func (_m *NotificationClient) DeleteNotificationById(ctx context.Context, id string) (common.BaseResponse, errors.EdgeX) { + ret := _m.Called(ctx, id) + + var r0 common.BaseResponse + if rf, ok := ret.Get(0).(func(context.Context, string) common.BaseResponse); ok { + r0 = rf(ctx, id) + } else { + r0 = ret.Get(0).(common.BaseResponse) + } + + var r1 errors.EdgeX + if rf, ok := ret.Get(1).(func(context.Context, string) errors.EdgeX); ok { + r1 = rf(ctx, id) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(errors.EdgeX) + } + } + + return r0, r1 +} + +// DeleteProcessedNotificationsByAge provides a mock function with given fields: ctx, age +func (_m *NotificationClient) DeleteProcessedNotificationsByAge(ctx context.Context, age int) (common.BaseResponse, errors.EdgeX) { + ret := _m.Called(ctx, age) + + var r0 common.BaseResponse + if rf, ok := ret.Get(0).(func(context.Context, int) common.BaseResponse); ok { + r0 = rf(ctx, age) + } else { + r0 = ret.Get(0).(common.BaseResponse) + } + + var r1 errors.EdgeX + if rf, ok := ret.Get(1).(func(context.Context, int) errors.EdgeX); ok { + r1 = rf(ctx, age) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(errors.EdgeX) + } + } + + return r0, r1 +} + +// NotificationById provides a mock function with given fields: ctx, id +func (_m *NotificationClient) NotificationById(ctx context.Context, id string) (responses.NotificationResponse, errors.EdgeX) { + ret := _m.Called(ctx, id) + + var r0 responses.NotificationResponse + if rf, ok := ret.Get(0).(func(context.Context, string) responses.NotificationResponse); ok { + r0 = rf(ctx, id) + } else { + r0 = ret.Get(0).(responses.NotificationResponse) + } + + var r1 errors.EdgeX + if rf, ok := ret.Get(1).(func(context.Context, string) errors.EdgeX); ok { + r1 = rf(ctx, id) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(errors.EdgeX) + } + } + + return r0, r1 +} + +// NotificationsByCategory provides a mock function with given fields: ctx, category, offset, limit +func (_m *NotificationClient) NotificationsByCategory(ctx context.Context, category string, offset int, limit int) (responses.MultiNotificationsResponse, errors.EdgeX) { + ret := _m.Called(ctx, category, offset, limit) + + var r0 responses.MultiNotificationsResponse + if rf, ok := ret.Get(0).(func(context.Context, string, int, int) responses.MultiNotificationsResponse); ok { + r0 = rf(ctx, category, offset, limit) + } else { + r0 = ret.Get(0).(responses.MultiNotificationsResponse) + } + + var r1 errors.EdgeX + if rf, ok := ret.Get(1).(func(context.Context, string, int, int) errors.EdgeX); ok { + r1 = rf(ctx, category, offset, limit) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(errors.EdgeX) + } + } + + return r0, r1 +} + +// NotificationsByLabel provides a mock function with given fields: ctx, label, offset, limit +func (_m *NotificationClient) NotificationsByLabel(ctx context.Context, label string, offset int, limit int) (responses.MultiNotificationsResponse, errors.EdgeX) { + ret := _m.Called(ctx, label, offset, limit) + + var r0 responses.MultiNotificationsResponse + if rf, ok := ret.Get(0).(func(context.Context, string, int, int) responses.MultiNotificationsResponse); ok { + r0 = rf(ctx, label, offset, limit) + } else { + r0 = ret.Get(0).(responses.MultiNotificationsResponse) + } + + var r1 errors.EdgeX + if rf, ok := ret.Get(1).(func(context.Context, string, int, int) errors.EdgeX); ok { + r1 = rf(ctx, label, offset, limit) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(errors.EdgeX) + } + } + + return r0, r1 +} + +// NotificationsByStatus provides a mock function with given fields: ctx, status, offset, limit +func (_m *NotificationClient) NotificationsByStatus(ctx context.Context, status string, offset int, limit int) (responses.MultiNotificationsResponse, errors.EdgeX) { + ret := _m.Called(ctx, status, offset, limit) + + var r0 responses.MultiNotificationsResponse + if rf, ok := ret.Get(0).(func(context.Context, string, int, int) responses.MultiNotificationsResponse); ok { + r0 = rf(ctx, status, offset, limit) + } else { + r0 = ret.Get(0).(responses.MultiNotificationsResponse) + } + + var r1 errors.EdgeX + if rf, ok := ret.Get(1).(func(context.Context, string, int, int) errors.EdgeX); ok { + r1 = rf(ctx, status, offset, limit) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(errors.EdgeX) + } + } + + return r0, r1 +} + +// NotificationsBySubscriptionName provides a mock function with given fields: ctx, subscriptionName, offset, limit +func (_m *NotificationClient) NotificationsBySubscriptionName(ctx context.Context, subscriptionName string, offset int, limit int) (responses.MultiNotificationsResponse, errors.EdgeX) { + ret := _m.Called(ctx, subscriptionName, offset, limit) + + var r0 responses.MultiNotificationsResponse + if rf, ok := ret.Get(0).(func(context.Context, string, int, int) responses.MultiNotificationsResponse); ok { + r0 = rf(ctx, subscriptionName, offset, limit) + } else { + r0 = ret.Get(0).(responses.MultiNotificationsResponse) + } + + var r1 errors.EdgeX + if rf, ok := ret.Get(1).(func(context.Context, string, int, int) errors.EdgeX); ok { + r1 = rf(ctx, subscriptionName, offset, limit) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(errors.EdgeX) + } + } + + return r0, r1 +} + +// NotificationsByTimeRange provides a mock function with given fields: ctx, start, end, offset, limit +func (_m *NotificationClient) NotificationsByTimeRange(ctx context.Context, start int, end int, offset int, limit int) (responses.MultiNotificationsResponse, errors.EdgeX) { + ret := _m.Called(ctx, start, end, offset, limit) + + var r0 responses.MultiNotificationsResponse + if rf, ok := ret.Get(0).(func(context.Context, int, int, int, int) responses.MultiNotificationsResponse); ok { + r0 = rf(ctx, start, end, offset, limit) + } else { + r0 = ret.Get(0).(responses.MultiNotificationsResponse) + } + + var r1 errors.EdgeX + if rf, ok := ret.Get(1).(func(context.Context, int, int, int, int) errors.EdgeX); ok { + r1 = rf(ctx, start, end, offset, limit) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(errors.EdgeX) + } + } + + return r0, r1 +} diff --git a/v2/clients/interfaces/mocks/SubscriptionClient.go b/v2/clients/interfaces/mocks/SubscriptionClient.go new file mode 100644 index 00000000..f3d61179 --- /dev/null +++ b/v2/clients/interfaces/mocks/SubscriptionClient.go @@ -0,0 +1,210 @@ +// Code generated by mockery v2.7.4. DO NOT EDIT. + +package mocks + +import ( + context "context" + + common "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos/common" + + errors "github.com/edgexfoundry/go-mod-core-contracts/v2/errors" + + mock "github.com/stretchr/testify/mock" + + requests "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos/requests" + + responses "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos/responses" +) + +// SubscriptionClient is an autogenerated mock type for the SubscriptionClient type +type SubscriptionClient struct { + mock.Mock +} + +// Add provides a mock function with given fields: ctx, reqs +func (_m *SubscriptionClient) Add(ctx context.Context, reqs []requests.AddSubscriptionRequest) ([]common.BaseWithIdResponse, errors.EdgeX) { + ret := _m.Called(ctx, reqs) + + var r0 []common.BaseWithIdResponse + if rf, ok := ret.Get(0).(func(context.Context, []requests.AddSubscriptionRequest) []common.BaseWithIdResponse); ok { + r0 = rf(ctx, reqs) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]common.BaseWithIdResponse) + } + } + + var r1 errors.EdgeX + if rf, ok := ret.Get(1).(func(context.Context, []requests.AddSubscriptionRequest) errors.EdgeX); ok { + r1 = rf(ctx, reqs) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(errors.EdgeX) + } + } + + return r0, r1 +} + +// AllSubscriptions provides a mock function with given fields: ctx, offset, limit +func (_m *SubscriptionClient) AllSubscriptions(ctx context.Context, offset int, limit int) (responses.MultiSubscriptionsResponse, errors.EdgeX) { + ret := _m.Called(ctx, offset, limit) + + var r0 responses.MultiSubscriptionsResponse + if rf, ok := ret.Get(0).(func(context.Context, int, int) responses.MultiSubscriptionsResponse); ok { + r0 = rf(ctx, offset, limit) + } else { + r0 = ret.Get(0).(responses.MultiSubscriptionsResponse) + } + + var r1 errors.EdgeX + if rf, ok := ret.Get(1).(func(context.Context, int, int) errors.EdgeX); ok { + r1 = rf(ctx, offset, limit) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(errors.EdgeX) + } + } + + return r0, r1 +} + +// DeleteSubscriptionByName provides a mock function with given fields: ctx, name +func (_m *SubscriptionClient) DeleteSubscriptionByName(ctx context.Context, name string) (common.BaseResponse, errors.EdgeX) { + ret := _m.Called(ctx, name) + + var r0 common.BaseResponse + if rf, ok := ret.Get(0).(func(context.Context, string) common.BaseResponse); ok { + r0 = rf(ctx, name) + } else { + r0 = ret.Get(0).(common.BaseResponse) + } + + var r1 errors.EdgeX + if rf, ok := ret.Get(1).(func(context.Context, string) errors.EdgeX); ok { + r1 = rf(ctx, name) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(errors.EdgeX) + } + } + + return r0, r1 +} + +// SubscriptionByName provides a mock function with given fields: ctx, name +func (_m *SubscriptionClient) SubscriptionByName(ctx context.Context, name string) (responses.SubscriptionResponse, errors.EdgeX) { + ret := _m.Called(ctx, name) + + var r0 responses.SubscriptionResponse + if rf, ok := ret.Get(0).(func(context.Context, string) responses.SubscriptionResponse); ok { + r0 = rf(ctx, name) + } else { + r0 = ret.Get(0).(responses.SubscriptionResponse) + } + + var r1 errors.EdgeX + if rf, ok := ret.Get(1).(func(context.Context, string) errors.EdgeX); ok { + r1 = rf(ctx, name) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(errors.EdgeX) + } + } + + return r0, r1 +} + +// SubscriptionsByCategory provides a mock function with given fields: ctx, category, offset, limit +func (_m *SubscriptionClient) SubscriptionsByCategory(ctx context.Context, category string, offset int, limit int) (responses.MultiSubscriptionsResponse, errors.EdgeX) { + ret := _m.Called(ctx, category, offset, limit) + + var r0 responses.MultiSubscriptionsResponse + if rf, ok := ret.Get(0).(func(context.Context, string, int, int) responses.MultiSubscriptionsResponse); ok { + r0 = rf(ctx, category, offset, limit) + } else { + r0 = ret.Get(0).(responses.MultiSubscriptionsResponse) + } + + var r1 errors.EdgeX + if rf, ok := ret.Get(1).(func(context.Context, string, int, int) errors.EdgeX); ok { + r1 = rf(ctx, category, offset, limit) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(errors.EdgeX) + } + } + + return r0, r1 +} + +// SubscriptionsByLabel provides a mock function with given fields: ctx, label, offset, limit +func (_m *SubscriptionClient) SubscriptionsByLabel(ctx context.Context, label string, offset int, limit int) (responses.MultiSubscriptionsResponse, errors.EdgeX) { + ret := _m.Called(ctx, label, offset, limit) + + var r0 responses.MultiSubscriptionsResponse + if rf, ok := ret.Get(0).(func(context.Context, string, int, int) responses.MultiSubscriptionsResponse); ok { + r0 = rf(ctx, label, offset, limit) + } else { + r0 = ret.Get(0).(responses.MultiSubscriptionsResponse) + } + + var r1 errors.EdgeX + if rf, ok := ret.Get(1).(func(context.Context, string, int, int) errors.EdgeX); ok { + r1 = rf(ctx, label, offset, limit) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(errors.EdgeX) + } + } + + return r0, r1 +} + +// SubscriptionsByReceiver provides a mock function with given fields: ctx, receiver, offset, limit +func (_m *SubscriptionClient) SubscriptionsByReceiver(ctx context.Context, receiver string, offset int, limit int) (responses.MultiSubscriptionsResponse, errors.EdgeX) { + ret := _m.Called(ctx, receiver, offset, limit) + + var r0 responses.MultiSubscriptionsResponse + if rf, ok := ret.Get(0).(func(context.Context, string, int, int) responses.MultiSubscriptionsResponse); ok { + r0 = rf(ctx, receiver, offset, limit) + } else { + r0 = ret.Get(0).(responses.MultiSubscriptionsResponse) + } + + var r1 errors.EdgeX + if rf, ok := ret.Get(1).(func(context.Context, string, int, int) errors.EdgeX); ok { + r1 = rf(ctx, receiver, offset, limit) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(errors.EdgeX) + } + } + + return r0, r1 +} + +// Update provides a mock function with given fields: ctx, reqs +func (_m *SubscriptionClient) Update(ctx context.Context, reqs []requests.UpdateSubscriptionRequest) ([]common.BaseResponse, errors.EdgeX) { + ret := _m.Called(ctx, reqs) + + var r0 []common.BaseResponse + if rf, ok := ret.Get(0).(func(context.Context, []requests.UpdateSubscriptionRequest) []common.BaseResponse); ok { + r0 = rf(ctx, reqs) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]common.BaseResponse) + } + } + + var r1 errors.EdgeX + if rf, ok := ret.Get(1).(func(context.Context, []requests.UpdateSubscriptionRequest) errors.EdgeX); ok { + r1 = rf(ctx, reqs) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(errors.EdgeX) + } + } + + return r0, r1 +} diff --git a/v2/clients/interfaces/mocks/TransmissionClient.go b/v2/clients/interfaces/mocks/TransmissionClient.go new file mode 100644 index 00000000..8d7bf4b0 --- /dev/null +++ b/v2/clients/interfaces/mocks/TransmissionClient.go @@ -0,0 +1,158 @@ +// Code generated by mockery v2.7.4. DO NOT EDIT. + +package mocks + +import ( + context "context" + + common "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos/common" + + errors "github.com/edgexfoundry/go-mod-core-contracts/v2/errors" + + mock "github.com/stretchr/testify/mock" + + responses "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos/responses" +) + +// TransmissionClient is an autogenerated mock type for the TransmissionClient type +type TransmissionClient struct { + mock.Mock +} + +// AllTransmissions provides a mock function with given fields: ctx, offset, limit +func (_m *TransmissionClient) AllTransmissions(ctx context.Context, offset int, limit int) (responses.MultiTransmissionsResponse, errors.EdgeX) { + ret := _m.Called(ctx, offset, limit) + + var r0 responses.MultiTransmissionsResponse + if rf, ok := ret.Get(0).(func(context.Context, int, int) responses.MultiTransmissionsResponse); ok { + r0 = rf(ctx, offset, limit) + } else { + r0 = ret.Get(0).(responses.MultiTransmissionsResponse) + } + + var r1 errors.EdgeX + if rf, ok := ret.Get(1).(func(context.Context, int, int) errors.EdgeX); ok { + r1 = rf(ctx, offset, limit) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(errors.EdgeX) + } + } + + return r0, r1 +} + +// DeleteProcessedTransmissionsByAge provides a mock function with given fields: ctx, age +func (_m *TransmissionClient) DeleteProcessedTransmissionsByAge(ctx context.Context, age int) (common.BaseResponse, errors.EdgeX) { + ret := _m.Called(ctx, age) + + var r0 common.BaseResponse + if rf, ok := ret.Get(0).(func(context.Context, int) common.BaseResponse); ok { + r0 = rf(ctx, age) + } else { + r0 = ret.Get(0).(common.BaseResponse) + } + + var r1 errors.EdgeX + if rf, ok := ret.Get(1).(func(context.Context, int) errors.EdgeX); ok { + r1 = rf(ctx, age) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(errors.EdgeX) + } + } + + return r0, r1 +} + +// TransmissionById provides a mock function with given fields: ctx, id +func (_m *TransmissionClient) TransmissionById(ctx context.Context, id string) (responses.TransmissionResponse, errors.EdgeX) { + ret := _m.Called(ctx, id) + + var r0 responses.TransmissionResponse + if rf, ok := ret.Get(0).(func(context.Context, string) responses.TransmissionResponse); ok { + r0 = rf(ctx, id) + } else { + r0 = ret.Get(0).(responses.TransmissionResponse) + } + + var r1 errors.EdgeX + if rf, ok := ret.Get(1).(func(context.Context, string) errors.EdgeX); ok { + r1 = rf(ctx, id) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(errors.EdgeX) + } + } + + return r0, r1 +} + +// TransmissionsByStatus provides a mock function with given fields: ctx, status, offset, limit +func (_m *TransmissionClient) TransmissionsByStatus(ctx context.Context, status string, offset int, limit int) (responses.MultiTransmissionsResponse, errors.EdgeX) { + ret := _m.Called(ctx, status, offset, limit) + + var r0 responses.MultiTransmissionsResponse + if rf, ok := ret.Get(0).(func(context.Context, string, int, int) responses.MultiTransmissionsResponse); ok { + r0 = rf(ctx, status, offset, limit) + } else { + r0 = ret.Get(0).(responses.MultiTransmissionsResponse) + } + + var r1 errors.EdgeX + if rf, ok := ret.Get(1).(func(context.Context, string, int, int) errors.EdgeX); ok { + r1 = rf(ctx, status, offset, limit) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(errors.EdgeX) + } + } + + return r0, r1 +} + +// TransmissionsBySubscriptionName provides a mock function with given fields: ctx, subscriptionName, offset, limit +func (_m *TransmissionClient) TransmissionsBySubscriptionName(ctx context.Context, subscriptionName string, offset int, limit int) (responses.MultiTransmissionsResponse, errors.EdgeX) { + ret := _m.Called(ctx, subscriptionName, offset, limit) + + var r0 responses.MultiTransmissionsResponse + if rf, ok := ret.Get(0).(func(context.Context, string, int, int) responses.MultiTransmissionsResponse); ok { + r0 = rf(ctx, subscriptionName, offset, limit) + } else { + r0 = ret.Get(0).(responses.MultiTransmissionsResponse) + } + + var r1 errors.EdgeX + if rf, ok := ret.Get(1).(func(context.Context, string, int, int) errors.EdgeX); ok { + r1 = rf(ctx, subscriptionName, offset, limit) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(errors.EdgeX) + } + } + + return r0, r1 +} + +// TransmissionsByTimeRange provides a mock function with given fields: ctx, start, end, offset, limit +func (_m *TransmissionClient) TransmissionsByTimeRange(ctx context.Context, start int, end int, offset int, limit int) (responses.MultiTransmissionsResponse, errors.EdgeX) { + ret := _m.Called(ctx, start, end, offset, limit) + + var r0 responses.MultiTransmissionsResponse + if rf, ok := ret.Get(0).(func(context.Context, int, int, int, int) responses.MultiTransmissionsResponse); ok { + r0 = rf(ctx, start, end, offset, limit) + } else { + r0 = ret.Get(0).(responses.MultiTransmissionsResponse) + } + + var r1 errors.EdgeX + if rf, ok := ret.Get(1).(func(context.Context, int, int, int, int) errors.EdgeX); ok { + r1 = rf(ctx, start, end, offset, limit) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(errors.EdgeX) + } + } + + return r0, r1 +} diff --git a/v2/clients/interfaces/notification.go b/v2/clients/interfaces/notification.go new file mode 100644 index 00000000..8927c909 --- /dev/null +++ b/v2/clients/interfaces/notification.go @@ -0,0 +1,44 @@ +// +// Copyright (C) 2021 IOTech Ltd +// +// SPDX-License-Identifier: Apache-2.0 + +package interfaces + +import ( + "context" + + "github.com/edgexfoundry/go-mod-core-contracts/v2/errors" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos/common" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos/requests" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos/responses" +) + +// NotificationClient defines the interface for interactions with the Notification endpoint on the EdgeX Foundry support-notifications service. +type NotificationClient interface { + // Add adds new notifications. + Add(ctx context.Context, reqs []requests.AddNotificationRequest) ([]common.BaseWithIdResponse, errors.EdgeX) + // NotificationById query notification by id. + NotificationById(ctx context.Context, id string) (responses.NotificationResponse, errors.EdgeX) + // DeleteNotificationById deletes a notification by id. + DeleteNotificationById(ctx context.Context, id string) (common.BaseResponse, errors.EdgeX) + // NotificationsByCategory queries notifications with category, offset and limit + NotificationsByCategory(ctx context.Context, category string, offset int, limit int) (responses.MultiNotificationsResponse, errors.EdgeX) + // NotificationsByLabel queries notifications with label, offset and limit + NotificationsByLabel(ctx context.Context, label string, offset int, limit int) (responses.MultiNotificationsResponse, errors.EdgeX) + // NotificationsByStatus queries notifications with status, offset and limit + NotificationsByStatus(ctx context.Context, status string, offset int, limit int) (responses.MultiNotificationsResponse, errors.EdgeX) + // NotificationsByTimeRange query notifications with time range, offset and limit + NotificationsByTimeRange(ctx context.Context, start int, end int, offset int, limit int) (responses.MultiNotificationsResponse, errors.EdgeX) + // NotificationsBySubscriptionName query notifications with subscriptionName, offset and limit + NotificationsBySubscriptionName(ctx context.Context, subscriptionName string, offset int, limit int) (responses.MultiNotificationsResponse, errors.EdgeX) + // CleanupNotificationsByAge removes notifications that are older than age. And the corresponding transmissions will also be deleted. + // Age is supposed in milliseconds since modified timestamp + CleanupNotificationsByAge(ctx context.Context, age int) (common.BaseResponse, errors.EdgeX) + // CleanupNotifications removes notifications and the corresponding transmissions. + CleanupNotifications(ctx context.Context) (common.BaseResponse, errors.EdgeX) + // DeleteProcessedNotificationsByAge removes processed notifications that are older than age. And the corresponding transmissions will also be deleted. + // Age is supposed in milliseconds since modified timestamp + // Please notice that this API is only for processed notifications (status = PROCESSED). If the deletion purpose includes each kind of notifications, please refer to cleanup API. + DeleteProcessedNotificationsByAge(ctx context.Context, age int) (common.BaseResponse, errors.EdgeX) +} diff --git a/v2/clients/interfaces/subscription.go b/v2/clients/interfaces/subscription.go new file mode 100644 index 00000000..9c499683 --- /dev/null +++ b/v2/clients/interfaces/subscription.go @@ -0,0 +1,35 @@ +// +// Copyright (C) 2021 IOTech Ltd +// +// SPDX-License-Identifier: Apache-2.0 + +package interfaces + +import ( + "context" + + "github.com/edgexfoundry/go-mod-core-contracts/v2/errors" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos/common" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos/requests" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos/responses" +) + +// SubscriptionClient defines the interface for interactions with the Subscription endpoint on the EdgeX Foundry support-notifications service. +type SubscriptionClient interface { + // Add adds new subscriptions. + Add(ctx context.Context, reqs []requests.AddSubscriptionRequest) ([]common.BaseWithIdResponse, errors.EdgeX) + // Update updates subscriptions. + Update(ctx context.Context, reqs []requests.UpdateSubscriptionRequest) ([]common.BaseResponse, errors.EdgeX) + // AllSubscriptions queries subscriptions with offset and limit + AllSubscriptions(ctx context.Context, offset int, limit int) (responses.MultiSubscriptionsResponse, errors.EdgeX) + // SubscriptionsByCategory queries subscriptions with category, offset and limit + SubscriptionsByCategory(ctx context.Context, category string, offset int, limit int) (responses.MultiSubscriptionsResponse, errors.EdgeX) + // SubscriptionsByLabel queries subscriptions with label, offset and limit + SubscriptionsByLabel(ctx context.Context, label string, offset int, limit int) (responses.MultiSubscriptionsResponse, errors.EdgeX) + // SubscriptionsByReceiver queries subscriptions with receiver, offset and limit + SubscriptionsByReceiver(ctx context.Context, receiver string, offset int, limit int) (responses.MultiSubscriptionsResponse, errors.EdgeX) + // SubscriptionByName query subscription by name. + SubscriptionByName(ctx context.Context, name string) (responses.SubscriptionResponse, errors.EdgeX) + // DeleteSubscriptionByName deletes a subscription by name. + DeleteSubscriptionByName(ctx context.Context, name string) (common.BaseResponse, errors.EdgeX) +} diff --git a/v2/clients/interfaces/transmission.go b/v2/clients/interfaces/transmission.go new file mode 100644 index 00000000..32d19799 --- /dev/null +++ b/v2/clients/interfaces/transmission.go @@ -0,0 +1,30 @@ +// +// Copyright (C) 2021 IOTech Ltd +// +// SPDX-License-Identifier: Apache-2.0 + +package interfaces + +import ( + "context" + + "github.com/edgexfoundry/go-mod-core-contracts/v2/errors" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos/common" + "github.com/edgexfoundry/go-mod-core-contracts/v2/v2/dtos/responses" +) + +// TransmissionClient defines the interface for interactions with the Transmission endpoint on the EdgeX Foundry support-notifications service. +type TransmissionClient interface { + // TransmissionById query transmission by id. + TransmissionById(ctx context.Context, id string) (responses.TransmissionResponse, errors.EdgeX) + // TransmissionsByTimeRange query transmissions with time range, offset and limit + TransmissionsByTimeRange(ctx context.Context, start int, end int, offset int, limit int) (responses.MultiTransmissionsResponse, errors.EdgeX) + // AllTransmissions query transmissions with offset and limit + AllTransmissions(ctx context.Context, offset int, limit int) (responses.MultiTransmissionsResponse, errors.EdgeX) + // TransmissionsByStatus queries transmissions with status, offset and limit + TransmissionsByStatus(ctx context.Context, status string, offset int, limit int) (responses.MultiTransmissionsResponse, errors.EdgeX) + // DeleteProcessedTransmissionsByAge deletes the processed transmissions if the current timestamp minus their created timestamp is less than the age parameter. + DeleteProcessedTransmissionsByAge(ctx context.Context, age int) (common.BaseResponse, errors.EdgeX) + // TransmissionsBySubscriptionName query transmissions with subscriptionName, offset and limit + TransmissionsBySubscriptionName(ctx context.Context, subscriptionName string, offset int, limit int) (responses.MultiTransmissionsResponse, errors.EdgeX) +}