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: Create client library for support-notifications #626

Merged
merged 2 commits into from
May 31, 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
6 changes: 6 additions & 0 deletions v2/clients/http/const_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
158 changes: 158 additions & 0 deletions v2/clients/http/notification.go
Original file line number Diff line number Diff line change
@@ -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,
}
}

// SendNotification sends new notifications.
func (client *NotificationClient) SendNotification(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
}
153 changes: 153 additions & 0 deletions v2/clients/http/notification_test.go
Original file line number Diff line number Diff line change
@@ -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_SendNotification(t *testing.T) {
ts := newTestServer(http.MethodPost, v2.ApiNotificationRoute, []common.BaseWithIdResponse{})
defer ts.Close()
client := NewNotificationClient(ts.URL)
res, err := client.SendNotification(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)
}
Loading