MG-2147 - Generate mocks with mockery for Consumer service (#2150)

Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
This commit is contained in:
Steve Munene
2024-04-22 11:52:54 +03:00
committed by GitHub
parent 49028e2950
commit cf832af14b
11 changed files with 708 additions and 391 deletions
@@ -66,6 +66,9 @@ jobs:
- "mqtt/events/streams.go"
- "readers/messages.go"
- "lora/routemap.go"
- "consumers/notifiers/notifier.go"
- "consumers/notifiers/service.go"
- "consumers/notifiers/subscriptions.go"
- name: Set up protoc
if: steps.changes.outputs.proto == 'true'
@@ -138,6 +141,9 @@ jobs:
mv ./mqtt/mocks/events.go ./mqtt/mocks/events.go.tmp
mv ./readers/mocks/messages.go ./readers/mocks/messages.go.tmp
mv ./lora/mocks/routes.go ./lora/mocks/routes.go.tmp
mv ./consumers/notifiers/mocks/notifier.go ./consumers/notifiers/mocks/notifier.go.tmp
mv ./consumers/notifiers/mocks/service.go ./consumers/notifiers/mocks/service.go.tmp
mv ./consumers/notifiers/mocks/repository.go ./consumers/notifiers/mocks/repository.go.tmp
make mocks
@@ -179,3 +185,6 @@ jobs:
check_mock_changes ./mqtt/mocks/events.go "MQTT Events Store ./mqtt/mocks/events.go"
check_mock_changes ./readers/mocks/messages.go "Message Readers ./readers/mocks/messages.go"
check_mock_changes ./lora/mocks/routes.go "LoRa Repository ./lora/mocks/routes.go"
check_mock_changes ./consumers/notifiers/mocks/notifier.go "Notifiers Notifier ./consumers/notifiers/mocks/notifier.go"
check_mock_changes ./consumers/notifiers/mocks/service.go "Notifiers Service ./consumers/notifiers/mocks/service.go"
check_mock_changes ./consumers/notifiers/mocks/repository.go "Notifiers Repository ./consumers/notifiers/mocks/repository.go"
+97 -53
View File
@@ -4,21 +4,21 @@
package api_test
import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"net/http/httptest"
"path"
"strings"
"testing"
"github.com/absmach/magistrala"
authmocks "github.com/absmach/magistrala/auth/mocks"
"github.com/absmach/magistrala/consumers/notifiers"
httpapi "github.com/absmach/magistrala/consumers/notifiers/api"
"github.com/absmach/magistrala/consumers/notifiers/mocks"
"github.com/absmach/magistrala/internal/apiutil"
"github.com/absmach/magistrala/internal/testsutil"
mglog "github.com/absmach/magistrala/logger"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
"github.com/absmach/magistrala/pkg/uuid"
@@ -67,19 +67,11 @@ func (tr testRequest) make() (*http.Response, error) {
return tr.client.Do(req)
}
func newService() (notifiers.Service, *authmocks.AuthClient) {
auth := new(authmocks.AuthClient)
repo := mocks.NewRepo(make(map[string]notifiers.Subscription))
idp := uuid.NewMock()
notif := mocks.NewNotifier()
from := "exampleFrom"
return notifiers.New(auth, repo, idp, notif, from), auth
}
func newServer(svc notifiers.Service) *httptest.Server {
func newServer() (*httptest.Server, *mocks.Service) {
logger := mglog.NewMock()
svc := new(mocks.Service)
mux := httpapi.MakeHandler(svc, logger, instanceID)
return httptest.NewServer(mux)
return httptest.NewServer(mux), svc
}
func toJSON(data interface{}) string {
@@ -91,8 +83,7 @@ func toJSON(data interface{}) string {
}
func TestCreate(t *testing.T) {
svc, auth := newService()
ss := newServer(svc)
ss, svc := newServer()
defer ss.Close()
sub := notifiers.Subscription{
@@ -112,6 +103,7 @@ func TestCreate(t *testing.T) {
auth string
status int
location string
err error
}{
{
desc: "add successfully",
@@ -120,6 +112,7 @@ func TestCreate(t *testing.T) {
auth: token,
status: http.StatusCreated,
location: fmt.Sprintf("/subscriptions/%s%012d", uuid.Prefix, 1),
err: nil,
},
{
desc: "add an existing subscription",
@@ -128,6 +121,7 @@ func TestCreate(t *testing.T) {
auth: token,
status: http.StatusConflict,
location: "",
err: svcerr.ErrConflict,
},
{
desc: "add with empty topic",
@@ -136,6 +130,7 @@ func TestCreate(t *testing.T) {
auth: token,
status: http.StatusBadRequest,
location: "",
err: svcerr.ErrMalformedEntity,
},
{
desc: "add with empty contact",
@@ -144,6 +139,7 @@ func TestCreate(t *testing.T) {
auth: token,
status: http.StatusBadRequest,
location: "",
err: svcerr.ErrMalformedEntity,
},
{
desc: "add with invalid auth token",
@@ -152,6 +148,7 @@ func TestCreate(t *testing.T) {
auth: authmocks.InvalidValue,
status: http.StatusUnauthorized,
location: "",
err: svcerr.ErrAuthentication,
},
{
desc: "add with empty auth token",
@@ -160,6 +157,7 @@ func TestCreate(t *testing.T) {
auth: "",
status: http.StatusUnauthorized,
location: "",
err: svcerr.ErrAuthentication,
},
{
desc: "add with invalid request format",
@@ -168,6 +166,7 @@ func TestCreate(t *testing.T) {
auth: token,
status: http.StatusBadRequest,
location: "",
err: svcerr.ErrMalformedEntity,
},
{
desc: "add without content type",
@@ -176,11 +175,12 @@ func TestCreate(t *testing.T) {
auth: token,
status: http.StatusUnsupportedMediaType,
location: "",
err: apiutil.ErrUnsupportedContentType,
},
}
for _, tc := range cases {
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.auth}).Return(&magistrala.IdentityRes{Id: validID}, nil)
svcCall := svc.On("CreateSubscription", mock.Anything, tc.auth, sub).Return(path.Base(tc.location), tc.err)
req := testRequest{
client: ss.Client(),
@@ -197,26 +197,23 @@ func TestCreate(t *testing.T) {
assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode))
assert.Equal(t, tc.location, location, fmt.Sprintf("%s: expected location %s got %s", tc.desc, tc.location, location))
repoCall.Unset()
svcCall.Unset()
}
}
func TestView(t *testing.T) {
svc, auth := newService()
ss := newServer(svc)
ss, svc := newServer()
defer ss.Close()
sub := notifiers.Subscription{
Topic: topic,
Contact: contact1,
ID: testsutil.GenerateUUID(t),
OwnerID: validID,
}
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: token}).Return(&magistrala.IdentityRes{Id: validID}, nil)
id, err := svc.CreateSubscription(context.Background(), token, sub)
assert.Nil(t, err, fmt.Sprintf("got an error creating id: %s", err))
repoCall.Unset()
sr := subRes{
ID: id,
ID: sub.ID,
OwnerID: validID,
Contact: sub.Contact,
Topic: sub.Topic,
@@ -229,13 +226,17 @@ func TestView(t *testing.T) {
auth string
status int
res string
err error
Sub notifiers.Subscription
}{
{
desc: "view successfully",
id: id,
id: sub.ID,
auth: token,
status: http.StatusOK,
res: data,
err: nil,
Sub: sub,
},
{
desc: "view not existing",
@@ -243,25 +244,28 @@ func TestView(t *testing.T) {
auth: token,
status: http.StatusNotFound,
res: notFoundRes,
err: svcerr.ErrNotFound,
},
{
desc: "view with invalid auth token",
id: id,
id: sub.ID,
auth: authmocks.InvalidValue,
status: http.StatusUnauthorized,
res: unauthRes,
err: svcerr.ErrAuthentication,
},
{
desc: "view with empty auth token",
id: id,
id: sub.ID,
auth: "",
status: http.StatusUnauthorized,
res: missingTokRes,
err: svcerr.ErrAuthentication,
},
}
for _, tc := range cases {
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.auth}).Return(&magistrala.IdentityRes{Id: validID}, nil)
svcCall := svc.On("ViewSubscription", mock.Anything, tc.auth, tc.id).Return(tc.Sub, tc.err)
req := testRequest{
client: ss.Client(),
@@ -277,36 +281,33 @@ func TestView(t *testing.T) {
assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode))
assert.Equal(t, tc.res, data, fmt.Sprintf("%s: expected body %s got %s", tc.desc, tc.res, data))
repoCall.Unset()
svcCall.Unset()
}
}
func TestList(t *testing.T) {
svc, auth := newService()
ss := newServer(svc)
ss, svc := newServer()
defer ss.Close()
const numSubs = 100
var subs []subRes
var sub notifiers.Subscription
for i := 0; i < numSubs; i++ {
sub := notifiers.Subscription{
sub = notifiers.Subscription{
Topic: fmt.Sprintf("topic.subtopic.%d", i),
Contact: contact1,
ID: testsutil.GenerateUUID(t),
}
if i%2 == 0 {
sub.Contact = contact2
}
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: token}).Return(&magistrala.IdentityRes{Id: validID}, nil)
id, err := svc.CreateSubscription(context.Background(), token, sub)
sr := subRes{
ID: id,
ID: sub.ID,
OwnerID: validID,
Contact: sub.Contact,
Topic: sub.Topic,
}
assert.Nil(t, err, fmt.Sprintf("got an error creating id: %s", err))
repoCall.Unset()
subs = append(subs, sr)
}
noLimit := toJSON(page{Offset: 5, Limit: 20, Total: numSubs, Subscriptions: subs[5:25]})
@@ -324,6 +325,8 @@ func TestList(t *testing.T) {
auth string
status int
res string
err error
page notifiers.Page
}{
{
desc: "list default limit",
@@ -333,6 +336,15 @@ func TestList(t *testing.T) {
auth: token,
status: http.StatusOK,
res: noLimit,
err: nil,
page: notifiers.Page{
PageMetadata: notifiers.PageMetadata{
Offset: 5,
Limit: 20,
},
Total: numSubs,
Subscriptions: subscriptionsSlice(subs, 5, 25),
},
},
{
desc: "list not existing",
@@ -342,6 +354,7 @@ func TestList(t *testing.T) {
auth: token,
status: http.StatusNotFound,
res: notFoundRes,
err: svcerr.ErrNotFound,
},
{
desc: "list one with topic",
@@ -351,6 +364,15 @@ func TestList(t *testing.T) {
auth: token,
status: http.StatusOK,
res: one,
err: nil,
page: notifiers.Page{
PageMetadata: notifiers.PageMetadata{
Offset: 0,
Limit: 20,
},
Total: 1,
Subscriptions: subscriptionsSlice(subs, 10, 11),
},
},
{
desc: "list with contact",
@@ -362,6 +384,15 @@ func TestList(t *testing.T) {
auth: token,
status: http.StatusOK,
res: contactList,
err: nil,
page: notifiers.Page{
PageMetadata: notifiers.PageMetadata{
Offset: 10,
Limit: 10,
},
Total: 50,
Subscriptions: subscriptionsSlice(contact2Subs, 0, 10),
},
},
{
desc: "list with invalid query",
@@ -371,24 +402,26 @@ func TestList(t *testing.T) {
auth: token,
status: http.StatusBadRequest,
res: invalidRes,
err: svcerr.ErrMalformedEntity,
},
{
desc: "list with invalid auth token",
auth: authmocks.InvalidValue,
status: http.StatusUnauthorized,
res: unauthRes,
err: svcerr.ErrAuthentication,
},
{
desc: "list with empty auth token",
auth: "",
status: http.StatusUnauthorized,
res: missingTokRes,
err: svcerr.ErrAuthentication,
},
}
for _, tc := range cases {
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.auth}).Return(&magistrala.IdentityRes{Id: validID}, nil)
svcCall := svc.On("ListSubscriptions", mock.Anything, tc.auth, mock.Anything).Return(tc.page, tc.err)
req := testRequest{
client: ss.Client(),
method: http.MethodGet,
@@ -403,23 +436,14 @@ func TestList(t *testing.T) {
assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode))
assert.Equal(t, tc.res, data, fmt.Sprintf("%s: got unexpected body\n", tc.desc))
repoCall.Unset()
svcCall.Unset()
}
}
func TestRemove(t *testing.T) {
svc, auth := newService()
ss := newServer(svc)
ss, svc := newServer()
defer ss.Close()
sub := notifiers.Subscription{
Topic: "topic",
Contact: contact1,
}
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: token}).Return(&magistrala.IdentityRes{Id: validID}, nil)
id, err := svc.CreateSubscription(context.Background(), token, sub)
assert.Nil(t, err, fmt.Sprintf("got an error creating id: %s", err))
repoCall.Unset()
id := testsutil.GenerateUUID(t)
cases := []struct {
desc string
@@ -427,24 +451,28 @@ func TestRemove(t *testing.T) {
auth string
status int
res string
err error
}{
{
desc: "remove successfully",
id: id,
auth: token,
status: http.StatusNoContent,
err: nil,
},
{
desc: "remove not existing",
id: "not existing",
auth: token,
status: http.StatusNotFound,
err: svcerr.ErrNotFound,
},
{
desc: "remove empty id",
id: "",
auth: token,
status: http.StatusBadRequest,
err: svcerr.ErrMalformedEntity,
},
{
desc: "view with invalid auth token",
@@ -452,6 +480,7 @@ func TestRemove(t *testing.T) {
auth: authmocks.InvalidValue,
status: http.StatusUnauthorized,
res: unauthRes,
err: svcerr.ErrAuthentication,
},
{
desc: "view with empty auth token",
@@ -459,11 +488,12 @@ func TestRemove(t *testing.T) {
auth: "",
status: http.StatusUnauthorized,
res: missingTokRes,
err: svcerr.ErrAuthentication,
},
}
for _, tc := range cases {
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.auth}).Return(&magistrala.IdentityRes{Id: validID}, nil)
svcCall := svc.On("RemoveSubscription", mock.Anything, tc.auth, tc.id).Return(tc.err)
req := testRequest{
client: ss.Client(),
@@ -475,7 +505,7 @@ func TestRemove(t *testing.T) {
assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err))
assert.Equal(t, tc.status, res.StatusCode, fmt.Sprintf("%s: expected status code %d got %d", tc.desc, tc.status, res.StatusCode))
repoCall.Unset()
svcCall.Unset()
}
}
@@ -502,3 +532,17 @@ type page struct {
Total uint `json:"total,omitempty"`
Subscriptions []subRes `json:"subscriptions,omitempty"`
}
func subscriptionsSlice(subs []subRes, start, end int) []notifiers.Subscription {
var res []notifiers.Subscription
for i := start; i < end; i++ {
sub := subs[i]
res = append(res, notifiers.Subscription{
ID: sub.ID,
OwnerID: sub.OwnerID,
Contact: sub.Contact,
Topic: sub.Topic,
})
}
return res
}
+36 -18
View File
@@ -1,29 +1,47 @@
// Code generated by mockery v2.42.1. DO NOT EDIT.
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package mocks
import (
"github.com/absmach/magistrala/consumers/notifiers"
"github.com/absmach/magistrala/pkg/messaging"
messaging "github.com/absmach/magistrala/pkg/messaging"
mock "github.com/stretchr/testify/mock"
)
var _ notifiers.Notifier = (*notifier)(nil)
const InvalidSender = "invalid@example.com"
type notifier struct{}
// NewNotifier returns a new Notifier mock.
func NewNotifier() notifiers.Notifier {
return notifier{}
// Notifier is an autogenerated mock type for the Notifier type
type Notifier struct {
mock.Mock
}
func (n notifier) Notify(from string, to []string, msg *messaging.Message) error {
for _, t := range to {
if t == InvalidSender {
return notifiers.ErrNotify
}
// Notify provides a mock function with given fields: from, to, msg
func (_m *Notifier) Notify(from string, to []string, msg *messaging.Message) error {
ret := _m.Called(from, to, msg)
if len(ret) == 0 {
panic("no return value specified for Notify")
}
return nil
var r0 error
if rf, ok := ret.Get(0).(func(string, []string, *messaging.Message) error); ok {
r0 = rf(from, to, msg)
} else {
r0 = ret.Error(0)
}
return r0
}
// NewNotifier creates a new instance of Notifier. 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 NewNotifier(t interface {
mock.TestingT
Cleanup(func())
}) *Notifier {
mock := &Notifier{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}
+133
View File
@@ -0,0 +1,133 @@
// Code generated by mockery v2.42.1. DO NOT EDIT.
// Copyright (c) Abstract Machines
package mocks
import (
context "context"
notifiers "github.com/absmach/magistrala/consumers/notifiers"
mock "github.com/stretchr/testify/mock"
)
// SubscriptionsRepository is an autogenerated mock type for the SubscriptionsRepository type
type SubscriptionsRepository struct {
mock.Mock
}
// Remove provides a mock function with given fields: ctx, id
func (_m *SubscriptionsRepository) Remove(ctx context.Context, id string) error {
ret := _m.Called(ctx, id)
if len(ret) == 0 {
panic("no return value specified for Remove")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, string) error); ok {
r0 = rf(ctx, id)
} else {
r0 = ret.Error(0)
}
return r0
}
// Retrieve provides a mock function with given fields: ctx, id
func (_m *SubscriptionsRepository) Retrieve(ctx context.Context, id string) (notifiers.Subscription, error) {
ret := _m.Called(ctx, id)
if len(ret) == 0 {
panic("no return value specified for Retrieve")
}
var r0 notifiers.Subscription
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string) (notifiers.Subscription, error)); ok {
return rf(ctx, id)
}
if rf, ok := ret.Get(0).(func(context.Context, string) notifiers.Subscription); ok {
r0 = rf(ctx, id)
} else {
r0 = ret.Get(0).(notifiers.Subscription)
}
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
r1 = rf(ctx, id)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// RetrieveAll provides a mock function with given fields: ctx, pm
func (_m *SubscriptionsRepository) RetrieveAll(ctx context.Context, pm notifiers.PageMetadata) (notifiers.Page, error) {
ret := _m.Called(ctx, pm)
if len(ret) == 0 {
panic("no return value specified for RetrieveAll")
}
var r0 notifiers.Page
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, notifiers.PageMetadata) (notifiers.Page, error)); ok {
return rf(ctx, pm)
}
if rf, ok := ret.Get(0).(func(context.Context, notifiers.PageMetadata) notifiers.Page); ok {
r0 = rf(ctx, pm)
} else {
r0 = ret.Get(0).(notifiers.Page)
}
if rf, ok := ret.Get(1).(func(context.Context, notifiers.PageMetadata) error); ok {
r1 = rf(ctx, pm)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// Save provides a mock function with given fields: ctx, sub
func (_m *SubscriptionsRepository) Save(ctx context.Context, sub notifiers.Subscription) (string, error) {
ret := _m.Called(ctx, sub)
if len(ret) == 0 {
panic("no return value specified for Save")
}
var r0 string
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, notifiers.Subscription) (string, error)); ok {
return rf(ctx, sub)
}
if rf, ok := ret.Get(0).(func(context.Context, notifiers.Subscription) string); ok {
r0 = rf(ctx, sub)
} else {
r0 = ret.Get(0).(string)
}
if rf, ok := ret.Get(1).(func(context.Context, notifiers.Subscription) error); ok {
r1 = rf(ctx, sub)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// NewSubscriptionsRepository creates a new instance of SubscriptionsRepository. 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 NewSubscriptionsRepository(t interface {
mock.TestingT
Cleanup(func())
}) *SubscriptionsRepository {
mock := &SubscriptionsRepository{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}
+151
View File
@@ -0,0 +1,151 @@
// Code generated by mockery v2.42.1. DO NOT EDIT.
// Copyright (c) Abstract Machines
package mocks
import (
context "context"
notifiers "github.com/absmach/magistrala/consumers/notifiers"
mock "github.com/stretchr/testify/mock"
)
// Service is an autogenerated mock type for the Service type
type Service struct {
mock.Mock
}
// ConsumeBlocking provides a mock function with given fields: ctx, messages
func (_m *Service) ConsumeBlocking(ctx context.Context, messages interface{}) error {
ret := _m.Called(ctx, messages)
if len(ret) == 0 {
panic("no return value specified for ConsumeBlocking")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, interface{}) error); ok {
r0 = rf(ctx, messages)
} else {
r0 = ret.Error(0)
}
return r0
}
// CreateSubscription provides a mock function with given fields: ctx, token, sub
func (_m *Service) CreateSubscription(ctx context.Context, token string, sub notifiers.Subscription) (string, error) {
ret := _m.Called(ctx, token, sub)
if len(ret) == 0 {
panic("no return value specified for CreateSubscription")
}
var r0 string
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string, notifiers.Subscription) (string, error)); ok {
return rf(ctx, token, sub)
}
if rf, ok := ret.Get(0).(func(context.Context, string, notifiers.Subscription) string); ok {
r0 = rf(ctx, token, sub)
} else {
r0 = ret.Get(0).(string)
}
if rf, ok := ret.Get(1).(func(context.Context, string, notifiers.Subscription) error); ok {
r1 = rf(ctx, token, sub)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// ListSubscriptions provides a mock function with given fields: ctx, token, pm
func (_m *Service) ListSubscriptions(ctx context.Context, token string, pm notifiers.PageMetadata) (notifiers.Page, error) {
ret := _m.Called(ctx, token, pm)
if len(ret) == 0 {
panic("no return value specified for ListSubscriptions")
}
var r0 notifiers.Page
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string, notifiers.PageMetadata) (notifiers.Page, error)); ok {
return rf(ctx, token, pm)
}
if rf, ok := ret.Get(0).(func(context.Context, string, notifiers.PageMetadata) notifiers.Page); ok {
r0 = rf(ctx, token, pm)
} else {
r0 = ret.Get(0).(notifiers.Page)
}
if rf, ok := ret.Get(1).(func(context.Context, string, notifiers.PageMetadata) error); ok {
r1 = rf(ctx, token, pm)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// RemoveSubscription provides a mock function with given fields: ctx, token, id
func (_m *Service) RemoveSubscription(ctx context.Context, token string, id string) error {
ret := _m.Called(ctx, token, id)
if len(ret) == 0 {
panic("no return value specified for RemoveSubscription")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok {
r0 = rf(ctx, token, id)
} else {
r0 = ret.Error(0)
}
return r0
}
// ViewSubscription provides a mock function with given fields: ctx, token, id
func (_m *Service) ViewSubscription(ctx context.Context, token string, id string) (notifiers.Subscription, error) {
ret := _m.Called(ctx, token, id)
if len(ret) == 0 {
panic("no return value specified for ViewSubscription")
}
var r0 notifiers.Subscription
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string, string) (notifiers.Subscription, error)); ok {
return rf(ctx, token, id)
}
if rf, ok := ret.Get(0).(func(context.Context, string, string) notifiers.Subscription); ok {
r0 = rf(ctx, token, id)
} else {
r0 = ret.Get(0).(notifiers.Subscription)
}
if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok {
r1 = rf(ctx, token, id)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// NewService creates a new instance of Service. 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 NewService(t interface {
mock.TestingT
Cleanup(func())
}) *Service {
mock := &Service{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}
-131
View File
@@ -1,131 +0,0 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package mocks
import (
"context"
"sort"
"sync"
"github.com/absmach/magistrala/consumers/notifiers"
repoerr "github.com/absmach/magistrala/pkg/errors/repository"
)
var _ notifiers.SubscriptionsRepository = (*subRepoMock)(nil)
type subRepoMock struct {
mu sync.Mutex
subs map[string]notifiers.Subscription
}
// NewRepo returns a new Subscriptions repository mock.
func NewRepo(subs map[string]notifiers.Subscription) notifiers.SubscriptionsRepository {
return &subRepoMock{
subs: subs,
}
}
func (srm *subRepoMock) Save(_ context.Context, sub notifiers.Subscription) (string, error) {
srm.mu.Lock()
defer srm.mu.Unlock()
if _, ok := srm.subs[sub.ID]; ok {
return "", repoerr.ErrConflict
}
for _, s := range srm.subs {
if s.Contact == sub.Contact && s.Topic == sub.Topic {
return "", repoerr.ErrConflict
}
}
srm.subs[sub.ID] = sub
return sub.ID, nil
}
func (srm *subRepoMock) Retrieve(_ context.Context, id string) (notifiers.Subscription, error) {
srm.mu.Lock()
defer srm.mu.Unlock()
ret, ok := srm.subs[id]
if !ok {
return notifiers.Subscription{}, repoerr.ErrNotFound
}
return ret, nil
}
func (srm *subRepoMock) RetrieveAll(_ context.Context, pm notifiers.PageMetadata) (notifiers.Page, error) {
srm.mu.Lock()
defer srm.mu.Unlock()
// Sort keys
keys := make([]string, 0)
for k := range srm.subs {
keys = append(keys, k)
}
sort.Strings(keys)
var subs []notifiers.Subscription
var total int
offset := int(pm.Offset)
for _, k := range keys {
v := srm.subs[k]
if pm.Topic == "" {
if pm.Contact == "" {
if total < offset {
total++
continue
}
total++
subs = appendSubs(subs, v, pm.Limit)
continue
}
if pm.Contact == v.Contact {
if total < offset {
total++
continue
}
total++
subs = appendSubs(subs, v, pm.Limit)
continue
}
}
if pm.Topic == v.Topic {
if pm.Contact == "" || pm.Contact == v.Contact {
if total < offset {
total++
continue
}
total++
subs = appendSubs(subs, v, pm.Limit)
}
}
}
if len(subs) == 0 {
return notifiers.Page{}, repoerr.ErrNotFound
}
ret := notifiers.Page{
PageMetadata: pm,
Total: uint(total),
Subscriptions: subs,
}
return ret, nil
}
func appendSubs(subs []notifiers.Subscription, sub notifiers.Subscription, max int) []notifiers.Subscription {
if len(subs) < max || max == -1 {
subs = append(subs, sub)
}
return subs
}
func (srm *subRepoMock) Remove(_ context.Context, id string) error {
srm.mu.Lock()
defer srm.mu.Unlock()
if _, ok := srm.subs[id]; !ok {
return repoerr.ErrNotFound
}
delete(srm.subs, id)
return nil
}
+2
View File
@@ -13,6 +13,8 @@ import (
var ErrNotify = errors.New("error sending notification")
// Notifier represents an API for sending notification.
//
//go:generate mockery --name Notifier --output=./mocks --filename notifier.go --quiet --note "Copyright (c) Abstract Machines"
type Notifier interface {
// Notify method is used to send notification for the
// received message to the provided list of receivers.
+2
View File
@@ -19,6 +19,8 @@ var ErrMessage = errors.New("failed to convert to Magistrala message")
var _ consumers.AsyncConsumer = (*notifierService)(nil)
// Service reprents a notification service.
//
//go:generate mockery --name Service --output=./mocks --filename service.go --quiet --note "Copyright (c) Abstract Machines"
type Service interface {
// CreateSubscription persists a subscription.
// Successful operation is indicated by non-nil error response.
+136 -112
View File
@@ -20,7 +20,6 @@ import (
"github.com/absmach/magistrala/pkg/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
)
const (
@@ -30,125 +29,136 @@ const (
validID = "d4ebb847-5d0e-4e46-bdd9-b6aceaaa3a22"
)
func newService() (notifiers.Service, *authmocks.AuthClient) {
repo := mocks.NewRepo(make(map[string]notifiers.Subscription))
func newService() (notifiers.Service, *authmocks.AuthClient, *mocks.SubscriptionsRepository) {
repo := new(mocks.SubscriptionsRepository)
auth := new(authmocks.AuthClient)
notifier := mocks.NewNotifier()
notifier := new(mocks.Notifier)
idp := uuid.NewMock()
from := "exampleFrom"
return notifiers.New(auth, repo, idp, notifier, from), auth
return notifiers.New(auth, repo, idp, notifier, from), auth, repo
}
func TestCreateSubscription(t *testing.T) {
svc, auth := newService()
svc, auth, repo := newService()
cases := []struct {
desc string
token string
sub notifiers.Subscription
id string
err error
desc string
token string
sub notifiers.Subscription
id string
err error
identifyErr error
userID string
}{
{
desc: "test success",
token: exampleUser1,
sub: notifiers.Subscription{Contact: exampleUser1, Topic: "valid.topic"},
id: uuid.Prefix + fmt.Sprintf("%012d", 1),
err: nil,
desc: "test success",
token: exampleUser1,
sub: notifiers.Subscription{Contact: exampleUser1, Topic: "valid.topic"},
id: uuid.Prefix + fmt.Sprintf("%012d", 1),
err: nil,
identifyErr: nil,
userID: validID,
},
{
desc: "test already existing",
token: exampleUser1,
sub: notifiers.Subscription{Contact: exampleUser1, Topic: "valid.topic"},
id: "",
err: repoerr.ErrConflict,
desc: "test already existing",
token: exampleUser1,
sub: notifiers.Subscription{Contact: exampleUser1, Topic: "valid.topic"},
id: "",
err: repoerr.ErrConflict,
identifyErr: nil,
userID: validID,
},
{
desc: "test with empty token",
token: "",
sub: notifiers.Subscription{Contact: exampleUser1, Topic: "valid.topic"},
id: "",
err: svcerr.ErrAuthentication,
desc: "test with empty token",
token: "",
sub: notifiers.Subscription{Contact: exampleUser1, Topic: "valid.topic"},
id: "",
err: svcerr.ErrAuthentication,
identifyErr: svcerr.ErrAuthentication,
},
}
for _, tc := range cases {
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: testsutil.GenerateUUID(t)}, nil)
repoCall := auth.On("Identify", context.Background(), &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: tc.userID}, tc.identifyErr)
repoCall1 := repo.On("Save", context.Background(), mock.Anything).Return(tc.id, tc.err)
id, err := svc.CreateSubscription(context.Background(), tc.token, tc.sub)
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
assert.Equal(t, tc.id, id, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.id, id))
repoCall.Unset()
repoCall1.Unset()
}
}
func TestViewSubscription(t *testing.T) {
svc, auth := newService()
sub := notifiers.Subscription{Contact: exampleUser1, Topic: "valid.topic"}
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: exampleUser1}).Return(&magistrala.IdentityRes{Id: validID}, nil)
id, err := svc.CreateSubscription(context.Background(), exampleUser1, sub)
require.Nil(t, err, "Saving a Subscription must succeed")
repoCall.Unset()
sub.ID = id
sub.OwnerID = validID
svc, auth, repo := newService()
sub := notifiers.Subscription{
Contact: exampleUser1,
Topic: "valid.topic",
ID: testsutil.GenerateUUID(t),
OwnerID: validID,
}
cases := []struct {
desc string
token string
id string
sub notifiers.Subscription
err error
desc string
token string
id string
sub notifiers.Subscription
err error
identifyErr error
userID string
}{
{
desc: "test success",
token: exampleUser1,
id: id,
sub: sub,
err: nil,
desc: "test success",
token: exampleUser1,
id: validID,
sub: sub,
err: nil,
identifyErr: nil,
userID: validID,
},
{
desc: "test not existing",
token: exampleUser1,
id: "not_exist",
sub: notifiers.Subscription{},
err: svcerr.ErrNotFound,
desc: "test not existing",
token: exampleUser1,
id: "not_exist",
sub: notifiers.Subscription{},
err: svcerr.ErrNotFound,
identifyErr: nil,
userID: validID,
},
{
desc: "test with empty token",
token: "",
id: id,
sub: notifiers.Subscription{},
err: svcerr.ErrAuthentication,
desc: "test with empty token",
token: "",
id: validID,
sub: notifiers.Subscription{},
err: svcerr.ErrAuthentication,
identifyErr: svcerr.ErrAuthentication,
},
}
for _, tc := range cases {
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID}, nil)
repoCall := auth.On("Identify", context.Background(), &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: tc.userID}, tc.identifyErr)
repoCall1 := repo.On("Retrieve", context.Background(), tc.id).Return(tc.sub, tc.err)
sub, err := svc.ViewSubscription(context.Background(), tc.token, tc.id)
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
assert.Equal(t, tc.sub, sub, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.sub, sub))
repoCall.Unset()
repoCall1.Unset()
}
}
func TestListSubscriptions(t *testing.T) {
svc, auth := newService()
svc, auth, repo := newService()
sub := notifiers.Subscription{Contact: exampleUser1, OwnerID: exampleUser1}
topic := "topic.subtopic"
var subs []notifiers.Subscription
for i := 0; i < total; i++ {
tmp := sub
token := exampleUser1
if i%2 == 0 {
tmp.Contact = exampleUser2
tmp.OwnerID = exampleUser2
token = exampleUser2
}
tmp.Topic = fmt.Sprintf("%s.%d", topic, i)
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: token}).Return(&magistrala.IdentityRes{Id: validID}, nil)
id, err := svc.CreateSubscription(context.Background(), token, tmp)
require.Nil(t, err, "Saving a Subscription must succeed")
repoCall.Unset()
tmp.ID = id
tmp.ID = testsutil.GenerateUUID(t)
tmp.OwnerID = validID
subs = append(subs, tmp)
}
@@ -159,11 +169,13 @@ func TestListSubscriptions(t *testing.T) {
}
cases := []struct {
desc string
token string
pageMeta notifiers.PageMetadata
page notifiers.Page
err error
desc string
token string
pageMeta notifiers.PageMetadata
page notifiers.Page
err error
identifyErr error
userID string
}{
{
desc: "test success",
@@ -181,6 +193,8 @@ func TestListSubscriptions(t *testing.T) {
Subscriptions: subs[:3],
Total: total,
},
identifyErr: nil,
userID: validID,
},
{
desc: "test not existing",
@@ -189,8 +203,10 @@ func TestListSubscriptions(t *testing.T) {
Limit: 10,
Contact: "empty@example.com",
},
page: notifiers.Page{},
err: svcerr.ErrNotFound,
page: notifiers.Page{},
err: svcerr.ErrNotFound,
identifyErr: nil,
userID: validID,
},
{
desc: "test with empty token",
@@ -200,8 +216,9 @@ func TestListSubscriptions(t *testing.T) {
Limit: 12,
Topic: "topic.subtopic.13",
},
page: notifiers.Page{},
err: svcerr.ErrAuthentication,
page: notifiers.Page{},
err: svcerr.ErrAuthentication,
identifyErr: svcerr.ErrAuthentication,
},
{
desc: "test with topic",
@@ -218,7 +235,9 @@ func TestListSubscriptions(t *testing.T) {
Subscriptions: subs[4:5],
Total: 1,
},
err: nil,
err: nil,
identifyErr: nil,
userID: validID,
},
{
desc: "test with contact and offset",
@@ -237,65 +256,77 @@ func TestListSubscriptions(t *testing.T) {
Subscriptions: offsetSubs,
Total: uint(total / 2),
},
err: nil,
err: nil,
identifyErr: nil,
userID: validID,
},
}
for _, tc := range cases {
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID}, nil)
repoCall := auth.On("Identify", context.Background(), &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: tc.userID}, tc.identifyErr)
repoCall1 := repo.On("RetrieveAll", context.Background(), tc.pageMeta).Return(tc.page, tc.err)
page, err := svc.ListSubscriptions(context.Background(), tc.token, tc.pageMeta)
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
assert.Equal(t, tc.page, page, fmt.Sprintf("%s: got unexpected page\n", tc.desc))
repoCall.Unset()
repoCall1.Unset()
}
}
func TestRemoveSubscription(t *testing.T) {
svc, auth := newService()
sub := notifiers.Subscription{Contact: exampleUser1, Topic: "valid.topic"}
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: exampleUser1}).Return(&magistrala.IdentityRes{Id: validID}, nil)
id, err := svc.CreateSubscription(context.Background(), exampleUser1, sub)
require.Nil(t, err, "Saving a Subscription must succeed")
repoCall.Unset()
sub.ID = id
sub.OwnerID = validID
svc, auth, repo := newService()
sub := notifiers.Subscription{
Contact: exampleUser1,
Topic: "valid.topic",
ID: testsutil.GenerateUUID(t),
OwnerID: validID,
}
cases := []struct {
desc string
token string
id string
err error
desc string
token string
id string
err error
identifyErr error
userID string
}{
{
desc: "test success",
token: exampleUser1,
id: id,
err: nil,
desc: "test success",
token: exampleUser1,
id: sub.ID,
err: nil,
identifyErr: nil,
userID: validID,
},
{
desc: "test not existing",
token: exampleUser1,
id: "not_exist",
err: svcerr.ErrNotFound,
desc: "test not existing",
token: exampleUser1,
id: "not_exist",
err: svcerr.ErrNotFound,
identifyErr: nil,
userID: validID,
},
{
desc: "test with empty token",
token: "",
id: id,
err: svcerr.ErrAuthentication,
desc: "test with empty token",
token: "",
id: sub.ID,
err: svcerr.ErrAuthentication,
identifyErr: svcerr.ErrAuthentication,
},
}
for _, tc := range cases {
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID}, nil)
repoCall := auth.On("Identify", context.Background(), &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: tc.userID}, tc.identifyErr)
repoCall1 := repo.On("Remove", context.Background(), tc.id).Return(tc.err)
err := svc.RemoveSubscription(context.Background(), tc.token, tc.id)
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
repoCall.Unset()
repoCall1.Unset()
}
}
func TestConsume(t *testing.T) {
svc, auth := newService()
svc, _, repo := newService()
sub := notifiers.Subscription{
Contact: exampleUser1,
OwnerID: validID,
@@ -307,18 +338,9 @@ func TestConsume(t *testing.T) {
if i%2 == 0 {
tmp.Topic = fmt.Sprintf("%s-2", sub.Topic)
}
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: exampleUser1}).Return(&magistrala.IdentityRes{Id: validID}, nil)
_, err := svc.CreateSubscription(context.Background(), exampleUser1, tmp)
require.Nil(t, err, "Saving a Subscription must succeed")
repoCall.Unset()
}
sub.Contact = mocks.InvalidSender
sub.Contact = "invalid@example.com"
sub.Topic = fmt.Sprintf("%s-2", sub.Topic)
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: exampleUser1}).Return(&magistrala.IdentityRes{Id: validID}, nil)
_, err := svc.CreateSubscription(context.Background(), exampleUser1, sub)
require.Nil(t, err, "Saving a Subscription must succeed")
repoCall.Unset()
msg := messaging.Message{
Channel: "topic",
@@ -347,7 +369,9 @@ func TestConsume(t *testing.T) {
}
for _, tc := range cases {
repoCall := repo.On("RetrieveAll", context.TODO(), mock.Anything).Return(notifiers.Page{}, tc.err)
err := svc.ConsumeBlocking(context.TODO(), tc.msg)
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
repoCall.Unset()
}
}
+2
View File
@@ -30,6 +30,8 @@ type PageMetadata struct {
}
// SubscriptionsRepository specifies a Subscription persistence API.
//
//go:generate mockery --name SubscriptionsRepository --output=./mocks --filename repository.go --quiet --note "Copyright (c) Abstract Machines"
type SubscriptionsRepository interface {
// Save persists a subscription. Successful operation is indicated by non-nil
// error response.
+140 -77
View File
@@ -15,6 +15,7 @@ import (
httpapi "github.com/absmach/magistrala/consumers/notifiers/api"
"github.com/absmach/magistrala/consumers/notifiers/mocks"
"github.com/absmach/magistrala/internal/apiutil"
"github.com/absmach/magistrala/internal/testsutil"
mglog "github.com/absmach/magistrala/logger"
"github.com/absmach/magistrala/pkg/errors"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
@@ -22,7 +23,6 @@ import (
"github.com/absmach/magistrala/pkg/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
)
var (
@@ -32,12 +32,13 @@ var (
}
emptySubscription = sdk.Subscription{}
exampleUser1 = "email1@example.com"
ID = testsutil.GenerateUUID(&testing.T{})
)
func setupSubscriptions() (*httptest.Server, *authmocks.AuthClient) {
repo := mocks.NewRepo(make(map[string]notifiers.Subscription))
func setupSubscriptions() (*httptest.Server, *authmocks.AuthClient, *mocks.SubscriptionsRepository) {
repo := new(mocks.SubscriptionsRepository)
auth := new(authmocks.AuthClient)
notifier := mocks.NewNotifier()
notifier := new(mocks.Notifier)
idp := uuid.NewMock()
from := "exampleFrom"
@@ -45,11 +46,11 @@ func setupSubscriptions() (*httptest.Server, *authmocks.AuthClient) {
logger := mglog.NewMock()
mux := httpapi.MakeHandler(svc, logger, instanceID)
return httptest.NewServer(mux), auth
return httptest.NewServer(mux), auth, repo
}
func TestCreateSubscription(t *testing.T) {
ts, auth := setupSubscriptions()
ts, auth, repo := setupSubscriptions()
defer ts.Close()
sdkConf := sdk.Config{
@@ -66,6 +67,9 @@ func TestCreateSubscription(t *testing.T) {
token string
err errors.SDKError
empty bool
id string
identifyErr error
userID string
}{
{
desc: "create new subscription",
@@ -73,6 +77,9 @@ func TestCreateSubscription(t *testing.T) {
token: exampleUser1,
err: nil,
empty: false,
id: ID,
identifyErr: nil,
userID: validID,
},
{
desc: "create new subscription with empty token",
@@ -80,6 +87,8 @@ func TestCreateSubscription(t *testing.T) {
token: "",
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, apiutil.ErrBearerToken), http.StatusUnauthorized),
empty: true,
id: "",
identifyErr: svcerr.ErrAuthorization,
},
{
desc: "create new subscription with invalid token",
@@ -87,6 +96,8 @@ func TestCreateSubscription(t *testing.T) {
token: authmocks.InvalidValue,
err: errors.NewSDKErrorWithStatus(svcerr.ErrAuthentication, http.StatusUnauthorized),
empty: true,
id: "",
identifyErr: svcerr.ErrAuthorization,
},
{
desc: "create new empty subscription",
@@ -94,20 +105,25 @@ func TestCreateSubscription(t *testing.T) {
token: token,
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, apiutil.ErrInvalidTopic), http.StatusBadRequest),
empty: true,
id: "",
identifyErr: nil,
userID: validID,
},
}
for _, tc := range cases {
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID}, nil)
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: tc.userID}, tc.identifyErr)
repoCall1 := repo.On("Save", mock.Anything, mock.Anything).Return(tc.id, tc.err)
loc, err := mgsdk.CreateSubscription(tc.subscription.Topic, tc.subscription.Contact, tc.token)
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected error %s, got %s", tc.desc, tc.err, err))
assert.Equal(t, tc.empty, loc == "", fmt.Sprintf("%s: expected empty result location, got: %s", tc.desc, loc))
repoCall.Unset()
repoCall1.Unset()
}
}
func TestViewSubscription(t *testing.T) {
ts, auth := setupSubscriptions()
ts, auth, repo := setupSubscriptions()
defer ts.Close()
sdkConf := sdk.Config{
UsersURL: ts.URL,
@@ -116,54 +132,59 @@ func TestViewSubscription(t *testing.T) {
}
mgsdk := sdk.NewSDK(sdkConf)
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: exampleUser1}).Return(&magistrala.IdentityRes{Id: validID}, nil)
id, err := mgsdk.CreateSubscription("topic", "contact", exampleUser1)
require.Nil(t, err, fmt.Sprintf("unexpected error during creating subscription: %s", err))
repoCall.Unset()
cases := []struct {
desc string
subID string
token string
err errors.SDKError
response sdk.Subscription
desc string
subID string
token string
err errors.SDKError
response sdk.Subscription
identifyErr error
userID string
}{
{
desc: "get existing subscription",
subID: id,
token: exampleUser1,
err: nil,
response: sub1,
desc: "get existing subscription",
subID: ID,
token: exampleUser1,
err: nil,
response: sub1,
identifyErr: nil,
userID: validID,
},
{
desc: "get non-existent subscription",
subID: "43",
token: exampleUser1,
err: errors.NewSDKErrorWithStatus(svcerr.ErrNotFound, http.StatusNotFound),
response: sdk.Subscription{},
desc: "get non-existent subscription",
subID: "43",
token: exampleUser1,
err: errors.NewSDKErrorWithStatus(svcerr.ErrNotFound, http.StatusNotFound),
response: sdk.Subscription{},
identifyErr: nil,
userID: validID,
},
{
desc: "get subscription with invalid token",
subID: id,
token: "",
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, apiutil.ErrBearerToken), http.StatusUnauthorized),
response: sdk.Subscription{},
desc: "get subscription with invalid token",
subID: ID,
token: "",
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, apiutil.ErrBearerToken), http.StatusUnauthorized),
response: sdk.Subscription{},
identifyErr: svcerr.ErrAuthorization,
},
}
for _, tc := range cases {
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID}, nil)
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: tc.userID}, tc.identifyErr)
repoCall1 := repo.On("Retrieve", mock.Anything, mock.Anything).Return(notifiers.Subscription{Contact: sub1.Contact, Topic: sub1.Topic}, tc.err)
respSub, err := mgsdk.ViewSubscription(tc.subID, tc.token)
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected error %s, got %s", tc.desc, tc.err, err))
tc.response.ID = respSub.ID
tc.response.OwnerID = respSub.OwnerID
assert.Equal(t, tc.response, respSub, fmt.Sprintf("%s: expected response %s, got %s", tc.desc, tc.response, respSub))
repoCall.Unset()
repoCall1.Unset()
}
}
func TestListSubscription(t *testing.T) {
ts, auth := setupSubscriptions()
ts, auth, repo := setupSubscriptions()
defer ts.Close()
sdkConf := sdk.Config{
UsersURL: ts.URL,
@@ -174,24 +195,16 @@ func TestListSubscription(t *testing.T) {
mgsdk := sdk.NewSDK(sdkConf)
nSubs := 10
subs := make([]sdk.Subscription, nSubs)
for i := 0; i < nSubs; i++ {
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: exampleUser1}).Return(&magistrala.IdentityRes{Id: validID}, nil)
id, err := mgsdk.CreateSubscription(fmt.Sprintf("topic_%d", i), fmt.Sprintf("contact_%d", i), exampleUser1)
require.Nil(t, err, fmt.Sprintf("unexpected error during creating subscription: %s", err))
repoCall.Unset()
repoCall = auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: exampleUser1}).Return(&magistrala.IdentityRes{Id: validID}, nil)
sub, err := mgsdk.ViewSubscription(id, exampleUser1)
require.Nil(t, err, fmt.Sprintf("unexpected error during getting subscription: %s", err))
repoCall.Unset()
subs[i] = sub
}
cases := []struct {
desc string
page sdk.PageMetadata
token string
err errors.SDKError
response []sdk.Subscription
desc string
page sdk.PageMetadata
token string
err errors.SDKError
response []sdk.Subscription
Page notifiers.Page
identifyErr error
userID string
}{
{
desc: "list all subscription",
@@ -199,6 +212,15 @@ func TestListSubscription(t *testing.T) {
page: sdk.PageMetadata{Offset: 0, Limit: uint64(nSubs)},
err: nil,
response: subs,
Page: notifiers.Page{
PageMetadata: notifiers.PageMetadata{
Offset: 0,
Limit: nSubs,
},
Subscriptions: subSlice(subs, 0, 10),
},
identifyErr: nil,
userID: validID,
},
{
desc: "list subscription with specific topic",
@@ -206,6 +228,16 @@ func TestListSubscription(t *testing.T) {
page: sdk.PageMetadata{Offset: 0, Limit: uint64(nSubs), Topic: "topic_1"},
err: nil,
response: []sdk.Subscription{subs[1]},
Page: notifiers.Page{
PageMetadata: notifiers.PageMetadata{
Offset: 0,
Limit: nSubs,
Topic: "topic_1",
},
Subscriptions: subSlice(subs, 0, 1),
},
identifyErr: nil,
userID: validID,
},
{
desc: "list subscription with specific contact",
@@ -213,20 +245,32 @@ func TestListSubscription(t *testing.T) {
page: sdk.PageMetadata{Offset: 0, Limit: uint64(nSubs), Contact: "contact_1"},
err: nil,
response: []sdk.Subscription{subs[1]},
Page: notifiers.Page{
PageMetadata: notifiers.PageMetadata{
Offset: 0,
Limit: nSubs,
Contact: "contact_1",
},
Subscriptions: subSlice(subs, 0, 1),
},
identifyErr: nil,
userID: validID,
},
}
for _, tc := range cases {
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID}, nil)
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: tc.userID}, tc.identifyErr)
repoCall1 := repo.On("RetrieveAll", mock.Anything, mock.Anything).Return(tc.Page, tc.err)
subs, err := mgsdk.ListSubscriptions(tc.page, tc.token)
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected error %s, got %s", tc.desc, tc.err, err))
assert.Equal(t, tc.response, subs.Subscriptions, fmt.Sprintf("%s: expected response %v, got %v", tc.desc, tc.response, subs.Subscriptions))
repoCall.Unset()
repoCall1.Unset()
}
}
func TestDeleteSubscription(t *testing.T) {
ts, auth := setupSubscriptions()
ts, auth, repo := setupSubscriptions()
defer ts.Close()
sdkConf := sdk.Config{
UsersURL: ts.URL,
@@ -235,45 +279,64 @@ func TestDeleteSubscription(t *testing.T) {
}
mgsdk := sdk.NewSDK(sdkConf)
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: exampleUser1}).Return(&magistrala.IdentityRes{Id: validID}, nil)
id, err := mgsdk.CreateSubscription("topic", "contact", exampleUser1)
require.Nil(t, err, fmt.Sprintf("unexpected error during creating subscription: %s", err))
repoCall.Unset()
cases := []struct {
desc string
subID string
token string
err errors.SDKError
response sdk.Subscription
desc string
subID string
token string
err errors.SDKError
response sdk.Subscription
identifyErr error
userID string
}{
{
desc: "delete existing subscription",
subID: id,
token: exampleUser1,
err: nil,
response: sub1,
desc: "delete existing subscription",
subID: ID,
token: exampleUser1,
err: nil,
response: sub1,
identifyErr: nil,
userID: validID,
},
{
desc: "delete non-existent subscription",
subID: "43",
token: exampleUser1,
err: errors.NewSDKErrorWithStatus(svcerr.ErrNotFound, http.StatusNotFound),
response: sdk.Subscription{},
desc: "delete non-existent subscription",
subID: "43",
token: exampleUser1,
err: errors.NewSDKErrorWithStatus(svcerr.ErrNotFound, http.StatusNotFound),
response: sdk.Subscription{},
identifyErr: nil,
userID: validID,
},
{
desc: "delete subscription with invalid token",
subID: id,
token: "",
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, apiutil.ErrBearerToken), http.StatusUnauthorized),
response: sdk.Subscription{},
desc: "delete subscription with invalid token",
subID: ID,
token: "",
err: errors.NewSDKErrorWithStatus(errors.Wrap(apiutil.ErrValidation, apiutil.ErrBearerToken), http.StatusUnauthorized),
response: sdk.Subscription{},
identifyErr: svcerr.ErrAuthorization,
},
}
for _, tc := range cases {
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: validID}, nil)
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: tc.userID}, tc.err)
repoCall1 := repo.On("Remove", mock.Anything, mock.Anything).Return(tc.err)
err := mgsdk.DeleteSubscription(tc.subID, tc.token)
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected error %s, got %s", tc.desc, tc.err, err))
repoCall.Unset()
repoCall1.Unset()
}
}
func subSlice(subs []sdk.Subscription, start, end int) []notifiers.Subscription {
var res []notifiers.Subscription
for i := start; i < end; i++ {
sub := subs[i]
res = append(res, notifiers.Subscription{
ID: sub.ID,
OwnerID: sub.OwnerID,
Contact: sub.Contact,
Topic: sub.Topic,
})
}
return res
}