mirror of
https://github.com/absmach/supermq.git
synced 2026-06-23 06:50:18 +00:00
MG-2173 - Generate mocks with mockery for Twins service (#2174)
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
This commit is contained in:
@@ -72,6 +72,9 @@ jobs:
|
||||
- "certs/certs.go"
|
||||
- "certs/pki/vault.go"
|
||||
- "certs/service.go"
|
||||
- "twins/twins.go"
|
||||
- "twins/states.go"
|
||||
- "twins/service.go"
|
||||
|
||||
- name: Set up protoc
|
||||
if: steps.changes.outputs.proto == 'true'
|
||||
@@ -115,7 +118,7 @@ jobs:
|
||||
- name: Check Mocks are up to Date
|
||||
if: steps.changes.outputs.mocks == 'true'
|
||||
run: |
|
||||
MOCKERY_VERSION=v2.42.1
|
||||
MOCKERY_VERSION=v2.42.3
|
||||
go install github.com/vektra/mockery/v2@$MOCKERY_VERSION
|
||||
|
||||
mv ./pkg/sdk/mocks/sdk.go ./pkg/sdk/mocks/sdk.go.tmp
|
||||
@@ -150,6 +153,10 @@ jobs:
|
||||
mv ./certs/mocks/certs.go ./certs/mocks/certs.go.tmp
|
||||
mv ./certs/mocks/pki.go ./certs/mocks/pki.go.tmp
|
||||
mv ./certs/mocks/service.go ./certs/mocks/service.go.tmp
|
||||
mv ./twins/mocks/service.go ./twins/mocks/service.go.tmp
|
||||
mv ./twins/mocks/states.go ./twins/mocks/states.go.tmp
|
||||
mv ./twins/mocks/repository.go ./twins/mocks/repository.go.tmp
|
||||
mv ./twins/mocks/cache.go ./twins/mocks/cache.go.tmp
|
||||
|
||||
make mocks
|
||||
|
||||
@@ -197,3 +204,7 @@ jobs:
|
||||
check_mock_changes ./certs/mocks/certs.go "Certs Repository ./certs/mocks/certs.go"
|
||||
check_mock_changes ./certs/mocks/pki.go "PKI ./certs/mocks/pki.go"
|
||||
check_mock_changes ./certs/mocks/service.go "Certs Service ./certs/mocks/service.go"
|
||||
check_mock_changes ./twins/mocks/service.go "Twins Service ./twins/mocks/service.go"
|
||||
check_mock_changes ./twins/mocks/states.go "Twins States ./twins/mocks/states.go"
|
||||
check_mock_changes ./twins/mocks/repository.go "Twins Repository ./twins/mocks/repository.go"
|
||||
check_mock_changes ./twins/mocks/cache.go "Twins Cache ./twins/mocks/cache.go"
|
||||
|
||||
@@ -23,7 +23,7 @@ DOCKER_PROJECT ?= $(shell echo $(subst $(space),,$(USER_REPO)) | tr -c -s '[:aln
|
||||
DOCKER_COMPOSE_COMMANDS_SUPPORTED := up down config
|
||||
DEFAULT_DOCKER_COMPOSE_COMMAND := up
|
||||
GRPC_MTLS_CERT_FILES_EXISTS = 0
|
||||
MOCKERY_VERSION=v2.42.1
|
||||
MOCKERY_VERSION=v2.42.3
|
||||
ifneq ($(MG_MESSAGE_BROKER_TYPE),)
|
||||
MG_MESSAGE_BROKER_TYPE := $(MG_MESSAGE_BROKER_TYPE)
|
||||
else
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.42.1. DO NOT EDIT.
|
||||
// Code generated by mockery v2.42.3. DO NOT EDIT.
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.42.1. DO NOT EDIT.
|
||||
// Code generated by mockery v2.42.3. DO NOT EDIT.
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.42.1. DO NOT EDIT.
|
||||
// Code generated by mockery v2.42.3. DO NOT EDIT.
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.42.1. DO NOT EDIT.
|
||||
// Code generated by mockery v2.42.3. DO NOT EDIT.
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.42.1. DO NOT EDIT.
|
||||
// Code generated by mockery v2.42.3. DO NOT EDIT.
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.42.1. DO NOT EDIT.
|
||||
// Code generated by mockery v2.42.3. DO NOT EDIT.
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.42.1. DO NOT EDIT.
|
||||
// Code generated by mockery v2.42.3. DO NOT EDIT.
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.42.1. DO NOT EDIT.
|
||||
// Code generated by mockery v2.42.3. DO NOT EDIT.
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.42.1. DO NOT EDIT.
|
||||
// Code generated by mockery v2.42.3. DO NOT EDIT.
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.42.1. DO NOT EDIT.
|
||||
// Code generated by mockery v2.42.3. DO NOT EDIT.
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.42.1. DO NOT EDIT.
|
||||
// Code generated by mockery v2.42.3. DO NOT EDIT.
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.42.1. DO NOT EDIT.
|
||||
// Code generated by mockery v2.42.3. DO NOT EDIT.
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.42.1. DO NOT EDIT.
|
||||
// Code generated by mockery v2.42.3. DO NOT EDIT.
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.42.1. DO NOT EDIT.
|
||||
// Code generated by mockery v2.42.3. DO NOT EDIT.
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.42.1. DO NOT EDIT.
|
||||
// Code generated by mockery v2.42.3. DO NOT EDIT.
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
|
||||
|
||||
@@ -137,8 +137,6 @@ func TestPublish(t *testing.T) {
|
||||
repoCall2 := connsRM.On("Get", context.Background(), mock.Anything).Return("", tc.connectionsErr)
|
||||
repoCall3 := pub.On("Publish", context.Background(), tc.msg.ApplicationID, mock.Anything).Return(tc.publishErr)
|
||||
err := svc.Publish(context.Background(), &tc.msg)
|
||||
fmt.Println(err)
|
||||
fmt.Println(tc.err)
|
||||
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()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.42.1. DO NOT EDIT.
|
||||
// Code generated by mockery v2.42.3. DO NOT EDIT.
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.42.1. DO NOT EDIT.
|
||||
// Code generated by mockery v2.42.3. DO NOT EDIT.
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.42.1. DO NOT EDIT.
|
||||
// Code generated by mockery v2.42.3. DO NOT EDIT.
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.42.1. DO NOT EDIT.
|
||||
// Code generated by mockery v2.42.3. DO NOT EDIT.
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.42.1. DO NOT EDIT.
|
||||
// Code generated by mockery v2.42.3. DO NOT EDIT.
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.42.1. DO NOT EDIT.
|
||||
// Code generated by mockery v2.42.3. DO NOT EDIT.
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.42.1. DO NOT EDIT.
|
||||
// Code generated by mockery v2.42.3. DO NOT EDIT.
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.42.1. DO NOT EDIT.
|
||||
// Code generated by mockery v2.42.3. DO NOT EDIT.
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.42.1. DO NOT EDIT.
|
||||
// Code generated by mockery v2.42.3. DO NOT EDIT.
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.42.1. DO NOT EDIT.
|
||||
// Code generated by mockery v2.42.3. DO NOT EDIT.
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.42.1. DO NOT EDIT.
|
||||
// Code generated by mockery v2.42.3. DO NOT EDIT.
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.42.1. DO NOT EDIT.
|
||||
// Code generated by mockery v2.42.3. DO NOT EDIT.
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.42.1. DO NOT EDIT.
|
||||
// Code generated by mockery v2.42.3. DO NOT EDIT.
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.42.1. DO NOT EDIT.
|
||||
// Code generated by mockery v2.42.3. DO NOT EDIT.
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
|
||||
|
||||
@@ -4,24 +4,29 @@
|
||||
package http_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/absmach/magistrala"
|
||||
authmocks "github.com/absmach/magistrala/auth/mocks"
|
||||
"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"
|
||||
"github.com/absmach/magistrala/twins"
|
||||
"github.com/absmach/magistrala/twins/mocks"
|
||||
"github.com/absmach/senml"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const numRecs = 100
|
||||
const (
|
||||
numRecs = 100
|
||||
publisher = "twins"
|
||||
)
|
||||
|
||||
var (
|
||||
subtopics = []string{"engine", "chassis", "wheel_2"}
|
||||
@@ -40,42 +45,50 @@ type statesPageRes struct {
|
||||
States []stateRes `json:"states"`
|
||||
}
|
||||
|
||||
func NewService() (twins.Service, *authmocks.AuthClient, *mocks.TwinRepository, *mocks.TwinCache, *mocks.StateRepository) {
|
||||
auth := new(authmocks.AuthClient)
|
||||
twinsRepo := new(mocks.TwinRepository)
|
||||
twinCache := new(mocks.TwinCache)
|
||||
statesRepo := new(mocks.StateRepository)
|
||||
idProvider := uuid.NewMock()
|
||||
subs := map[string]string{"chanID": "chanID"}
|
||||
broker := mocks.NewBroker(subs)
|
||||
|
||||
return twins.New(broker, auth, twinsRepo, twinCache, statesRepo, idProvider, "chanID", mglog.NewMock()), auth, twinsRepo, twinCache, statesRepo
|
||||
}
|
||||
|
||||
func TestListStates(t *testing.T) {
|
||||
svc, auth := mocks.NewService()
|
||||
svc, auth, _, _, stateRepo := NewService()
|
||||
ts := newServer(svc)
|
||||
defer ts.Close()
|
||||
|
||||
twin := twins.Twin{
|
||||
Owner: email,
|
||||
}
|
||||
def := mocks.CreateDefinition(channels[0:2], subtopics[0:2])
|
||||
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: token}).Return(&magistrala.IdentityRes{Id: testsutil.GenerateUUID(t)}, nil)
|
||||
tw, err := svc.AddTwin(context.Background(), token, twin, def)
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
repoCall.Unset()
|
||||
attr := def.Attributes[0]
|
||||
|
||||
twin := twins.Twin{
|
||||
Owner: email,
|
||||
Definitions: []twins.Definition{def},
|
||||
ID: testsutil.GenerateUUID(t),
|
||||
Created: time.Now(),
|
||||
}
|
||||
recs := make([]senml.Record, numRecs)
|
||||
mocks.CreateSenML(recs)
|
||||
message, err := mocks.CreateMessage(attr, recs)
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
err = svc.SaveStates(context.Background(), message)
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
|
||||
var data []stateRes
|
||||
for i := 0; i < len(recs); i++ {
|
||||
res := createStateResponse(i, tw, recs[i])
|
||||
res := createStateResponse(i, twin, recs[i])
|
||||
data = append(data, res)
|
||||
}
|
||||
|
||||
baseURL := fmt.Sprintf("%s/states/%s", ts.URL, tw.ID)
|
||||
baseURL := fmt.Sprintf("%s/states/%s", ts.URL, twin.ID)
|
||||
queryFmt := "%s?offset=%d&limit=%d"
|
||||
cases := []struct {
|
||||
desc string
|
||||
auth string
|
||||
status int
|
||||
url string
|
||||
res []stateRes
|
||||
desc string
|
||||
auth string
|
||||
status int
|
||||
url string
|
||||
res []stateRes
|
||||
err error
|
||||
page twins.StatesPage
|
||||
identifyErr error
|
||||
userID string
|
||||
}{
|
||||
{
|
||||
desc: "get a list of states",
|
||||
@@ -83,6 +96,12 @@ func TestListStates(t *testing.T) {
|
||||
status: http.StatusOK,
|
||||
url: baseURL,
|
||||
res: data[0:10],
|
||||
err: nil,
|
||||
page: twins.StatesPage{
|
||||
States: convState(data[0:10]),
|
||||
},
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "get a list of states with valid offset and limit",
|
||||
@@ -90,20 +109,30 @@ func TestListStates(t *testing.T) {
|
||||
status: http.StatusOK,
|
||||
url: fmt.Sprintf(queryFmt, baseURL, 20, 15),
|
||||
res: data[20:35],
|
||||
page: twins.StatesPage{
|
||||
States: convState(data[20:35]),
|
||||
},
|
||||
err: nil,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "get a list of states with invalid token",
|
||||
auth: authmocks.InvalidValue,
|
||||
status: http.StatusUnauthorized,
|
||||
url: fmt.Sprintf(queryFmt, baseURL, 0, 5),
|
||||
res: nil,
|
||||
desc: "get a list of states with invalid token",
|
||||
auth: authmocks.InvalidValue,
|
||||
status: http.StatusUnauthorized,
|
||||
url: fmt.Sprintf(queryFmt, baseURL, 0, 5),
|
||||
res: nil,
|
||||
err: svcerr.ErrAuthentication,
|
||||
identifyErr: svcerr.ErrAuthentication,
|
||||
},
|
||||
{
|
||||
desc: "get a list of states with empty token",
|
||||
auth: "",
|
||||
status: http.StatusUnauthorized,
|
||||
url: fmt.Sprintf(queryFmt, baseURL, 0, 5),
|
||||
res: nil,
|
||||
desc: "get a list of states with empty token",
|
||||
auth: "",
|
||||
status: http.StatusUnauthorized,
|
||||
url: fmt.Sprintf(queryFmt, baseURL, 0, 5),
|
||||
res: nil,
|
||||
err: svcerr.ErrAuthentication,
|
||||
identifyErr: svcerr.ErrAuthentication,
|
||||
},
|
||||
{
|
||||
desc: "get a list of states with + limit > total",
|
||||
@@ -111,48 +140,72 @@ func TestListStates(t *testing.T) {
|
||||
status: http.StatusOK,
|
||||
url: fmt.Sprintf(queryFmt, baseURL, 91, 20),
|
||||
res: data[91:],
|
||||
page: twins.StatesPage{
|
||||
States: convState(data[91:]),
|
||||
},
|
||||
err: nil,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "get a list of states with negative offset",
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
url: fmt.Sprintf(queryFmt, baseURL, -1, 5),
|
||||
res: nil,
|
||||
desc: "get a list of states with negative offset",
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
url: fmt.Sprintf(queryFmt, baseURL, -1, 5),
|
||||
res: nil,
|
||||
err: svcerr.ErrMalformedEntity,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "get a list of states with negative limit",
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
url: fmt.Sprintf(queryFmt, baseURL, 0, -5),
|
||||
res: nil,
|
||||
desc: "get a list of states with negative limit",
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
url: fmt.Sprintf(queryFmt, baseURL, 0, -5),
|
||||
res: nil,
|
||||
err: svcerr.ErrMalformedEntity,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "get a list of states with zero limit",
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
url: fmt.Sprintf(queryFmt, baseURL, 0, 0),
|
||||
res: nil,
|
||||
desc: "get a list of states with zero limit",
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
url: fmt.Sprintf(queryFmt, baseURL, 0, 0),
|
||||
res: nil,
|
||||
err: svcerr.ErrMalformedEntity,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "get a list of states with limit greater than max",
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
url: fmt.Sprintf(queryFmt, baseURL, 0, 110),
|
||||
res: nil,
|
||||
desc: "get a list of states with limit greater than max",
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
url: fmt.Sprintf(queryFmt, baseURL, 0, 110),
|
||||
res: nil,
|
||||
err: svcerr.ErrMalformedEntity,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "get a list of states with invalid offset",
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
url: fmt.Sprintf("%s?offset=invalid&limit=%d", baseURL, 15),
|
||||
res: nil,
|
||||
desc: "get a list of states with invalid offset",
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
url: fmt.Sprintf("%s?offset=invalid&limit=%d", baseURL, 15),
|
||||
res: nil,
|
||||
err: svcerr.ErrMalformedEntity,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "get a list of states with invalid limit",
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
url: fmt.Sprintf("%s?offset=%d&limit=invalid", baseURL, 0),
|
||||
res: nil,
|
||||
desc: "get a list of states with invalid limit",
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
url: fmt.Sprintf("%s?offset=%d&limit=invalid", baseURL, 0),
|
||||
res: nil,
|
||||
err: svcerr.ErrMalformedEntity,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "get a list of states without offset",
|
||||
@@ -160,6 +213,12 @@ func TestListStates(t *testing.T) {
|
||||
status: http.StatusOK,
|
||||
url: fmt.Sprintf("%s?limit=%d", baseURL, 15),
|
||||
res: data[0:15],
|
||||
page: twins.StatesPage{
|
||||
States: convState(data[0:15]),
|
||||
},
|
||||
err: nil,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "get a list of states without limit",
|
||||
@@ -167,13 +226,22 @@ func TestListStates(t *testing.T) {
|
||||
status: http.StatusOK,
|
||||
url: fmt.Sprintf("%s?offset=%d", baseURL, 14),
|
||||
res: data[14:24],
|
||||
page: twins.StatesPage{
|
||||
States: convState(data[14:24]),
|
||||
},
|
||||
err: nil,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "get a list of states with invalid number of parameters",
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
url: fmt.Sprintf("%s%s", baseURL, "?offset=4&limit=4&limit=5&offset=5"),
|
||||
res: nil,
|
||||
desc: "get a list of states with invalid number of parameters",
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
url: fmt.Sprintf("%s%s", baseURL, "?offset=4&limit=4&limit=5&offset=5"),
|
||||
res: nil,
|
||||
err: svcerr.ErrMalformedEntity,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "get a list of states with redundant query parameters",
|
||||
@@ -181,11 +249,18 @@ func TestListStates(t *testing.T) {
|
||||
status: http.StatusOK,
|
||||
url: fmt.Sprintf("%s?offset=%d&limit=%d&value=something", baseURL, 0, 5),
|
||||
res: data[0:5],
|
||||
page: twins.StatesPage{
|
||||
States: convState(data[0:5]),
|
||||
},
|
||||
err: nil,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
repoCall := auth.On("Identify", mock.Anything, mock.Anything).Return(&magistrala.IdentityRes{Id: testsutil.GenerateUUID(t)}, nil)
|
||||
authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.auth}).Return(&magistrala.IdentityRes{Id: tc.userID}, tc.identifyErr)
|
||||
repoCall := stateRepo.On("RetrieveAll", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.page, tc.err)
|
||||
req := testRequest{
|
||||
client: ts.Client(),
|
||||
method: http.MethodGet,
|
||||
@@ -203,6 +278,7 @@ func TestListStates(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.ElementsMatch(t, tc.res, resData.States, fmt.Sprintf("%s: got incorrect body from response", tc.desc))
|
||||
authCall.Unset()
|
||||
repoCall.Unset()
|
||||
}
|
||||
}
|
||||
@@ -215,3 +291,16 @@ func createStateResponse(id int, tw twins.Twin, rec senml.Record) stateRes {
|
||||
Payload: map[string]interface{}{rec.BaseName: nil},
|
||||
}
|
||||
}
|
||||
|
||||
func convState(data []stateRes) []twins.State {
|
||||
states := make([]twins.State, len(data))
|
||||
for i, d := range data {
|
||||
states[i] = twins.State{
|
||||
TwinID: d.TwinID,
|
||||
ID: d.ID,
|
||||
Definition: d.Definition,
|
||||
Payload: d.Payload,
|
||||
}
|
||||
}
|
||||
return states
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
package http_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -19,12 +18,11 @@ import (
|
||||
"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/twins"
|
||||
httpapi "github.com/absmach/magistrala/twins/api/http"
|
||||
"github.com/absmach/magistrala/twins/mocks"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -35,6 +33,8 @@ const (
|
||||
wrongID = 0
|
||||
maxNameSize = 1024
|
||||
instanceID = "5de9b29a-feb9-11ed-be56-0242ac120002"
|
||||
retained = "saved"
|
||||
validID = "123e4567-e89b-12d3-a456-426614174000"
|
||||
)
|
||||
|
||||
var invalidName = strings.Repeat("m", maxNameSize+1)
|
||||
@@ -101,7 +101,7 @@ func toJSON(data interface{}) (string, error) {
|
||||
}
|
||||
|
||||
func TestAddTwin(t *testing.T) {
|
||||
svc, auth := mocks.NewService()
|
||||
svc, auth, twinRepo, twinCache, _ := NewService()
|
||||
ts := newServer(svc)
|
||||
defer ts.Close()
|
||||
|
||||
@@ -120,6 +120,10 @@ func TestAddTwin(t *testing.T) {
|
||||
auth string
|
||||
status int
|
||||
location string
|
||||
err error
|
||||
saveErr error
|
||||
identifyErr error
|
||||
userID string
|
||||
}{
|
||||
{
|
||||
desc: "add valid twin",
|
||||
@@ -128,6 +132,10 @@ func TestAddTwin(t *testing.T) {
|
||||
auth: token,
|
||||
status: http.StatusCreated,
|
||||
location: "/twins/123e4567-e89b-12d3-a456-000000000001",
|
||||
err: nil,
|
||||
saveErr: nil,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "add twin with empty JSON request",
|
||||
@@ -136,6 +144,10 @@ func TestAddTwin(t *testing.T) {
|
||||
auth: token,
|
||||
status: http.StatusCreated,
|
||||
location: "/twins/123e4567-e89b-12d3-a456-000000000002",
|
||||
err: nil,
|
||||
saveErr: nil,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "add twin with invalid auth token",
|
||||
@@ -144,6 +156,9 @@ func TestAddTwin(t *testing.T) {
|
||||
auth: authmocks.InvalidValue,
|
||||
status: http.StatusUnauthorized,
|
||||
location: "",
|
||||
err: svcerr.ErrAuthentication,
|
||||
saveErr: svcerr.ErrCreateEntity,
|
||||
identifyErr: svcerr.ErrAuthentication,
|
||||
},
|
||||
{
|
||||
desc: "add twin with empty auth token",
|
||||
@@ -152,6 +167,9 @@ func TestAddTwin(t *testing.T) {
|
||||
auth: "",
|
||||
status: http.StatusUnauthorized,
|
||||
location: "",
|
||||
err: svcerr.ErrAuthentication,
|
||||
saveErr: svcerr.ErrCreateEntity,
|
||||
identifyErr: svcerr.ErrAuthentication,
|
||||
},
|
||||
{
|
||||
desc: "add twin with invalid request format",
|
||||
@@ -160,6 +178,10 @@ func TestAddTwin(t *testing.T) {
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
location: "",
|
||||
err: svcerr.ErrMalformedEntity,
|
||||
saveErr: svcerr.ErrCreateEntity,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "add twin with empty request",
|
||||
@@ -168,6 +190,10 @@ func TestAddTwin(t *testing.T) {
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
location: "",
|
||||
err: svcerr.ErrMalformedEntity,
|
||||
saveErr: svcerr.ErrCreateEntity,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "add twin without content type",
|
||||
@@ -176,6 +202,10 @@ func TestAddTwin(t *testing.T) {
|
||||
auth: token,
|
||||
status: http.StatusUnsupportedMediaType,
|
||||
location: "",
|
||||
err: apiutil.ErrUnsupportedContentType,
|
||||
saveErr: svcerr.ErrCreateEntity,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "add twin with invalid name",
|
||||
@@ -184,11 +214,17 @@ func TestAddTwin(t *testing.T) {
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
location: "",
|
||||
err: svcerr.ErrMalformedEntity,
|
||||
saveErr: svcerr.ErrCreateEntity,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.auth}).Return(&magistrala.IdentityRes{Id: testsutil.GenerateUUID(t)}, nil)
|
||||
authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.auth}).Return(&magistrala.IdentityRes{Id: tc.userID}, tc.identifyErr)
|
||||
repoCall := twinRepo.On("Save", mock.Anything, mock.Anything).Return(retained, tc.saveErr)
|
||||
cacheCall := twinCache.On("Save", mock.Anything, mock.Anything).Return(tc.err)
|
||||
req := testRequest{
|
||||
client: ts.Client(),
|
||||
method: http.MethodPost,
|
||||
@@ -203,22 +239,21 @@ func TestAddTwin(t *testing.T) {
|
||||
location := res.Header.Get("Location")
|
||||
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))
|
||||
authCall.Unset()
|
||||
repoCall.Unset()
|
||||
cacheCall.Unset()
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateTwin(t *testing.T) {
|
||||
svc, auth := mocks.NewService()
|
||||
svc, auth, twinRepo, twinCache, _ := NewService()
|
||||
ts := newServer(svc)
|
||||
defer ts.Close()
|
||||
|
||||
twin := twins.Twin{}
|
||||
def := twins.Definition{}
|
||||
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: token}).Return(&magistrala.IdentityRes{Id: testsutil.GenerateUUID(t)}, nil)
|
||||
stw, err := svc.AddTwin(context.Background(), token, twin, def)
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
repoCall.Unset()
|
||||
|
||||
twin := twins.Twin{
|
||||
Owner: email,
|
||||
ID: testsutil.GenerateUUID(t),
|
||||
}
|
||||
twin.Name = twinName
|
||||
data, err := toJSON(twin)
|
||||
assert.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
@@ -235,22 +270,35 @@ func TestUpdateTwin(t *testing.T) {
|
||||
contentType string
|
||||
auth string
|
||||
status int
|
||||
err error
|
||||
retrieveErr error
|
||||
updateErr error
|
||||
identifyErr error
|
||||
userID string
|
||||
}{
|
||||
{
|
||||
desc: "update existing twin",
|
||||
req: data,
|
||||
id: stw.ID,
|
||||
id: twin.ID,
|
||||
contentType: contentType,
|
||||
auth: token,
|
||||
status: http.StatusOK,
|
||||
err: nil,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "update twin with empty JSON request",
|
||||
req: "{}",
|
||||
id: stw.ID,
|
||||
id: twin.ID,
|
||||
contentType: contentType,
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
err: svcerr.ErrMalformedEntity,
|
||||
retrieveErr: nil,
|
||||
updateErr: svcerr.ErrUpdateEntity,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "update non-existent twin",
|
||||
@@ -259,46 +307,74 @@ func TestUpdateTwin(t *testing.T) {
|
||||
contentType: contentType,
|
||||
auth: token,
|
||||
status: http.StatusNotFound,
|
||||
err: svcerr.ErrNotFound,
|
||||
retrieveErr: svcerr.ErrNotFound,
|
||||
updateErr: svcerr.ErrUpdateEntity,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "update twin with invalid token",
|
||||
req: data,
|
||||
id: stw.ID,
|
||||
id: twin.ID,
|
||||
contentType: contentType,
|
||||
auth: authmocks.InvalidValue,
|
||||
status: http.StatusUnauthorized,
|
||||
err: svcerr.ErrAuthentication,
|
||||
retrieveErr: svcerr.ErrNotFound,
|
||||
updateErr: svcerr.ErrUpdateEntity,
|
||||
identifyErr: svcerr.ErrAuthentication,
|
||||
},
|
||||
{
|
||||
desc: "update twin with empty token",
|
||||
req: data,
|
||||
id: stw.ID,
|
||||
id: twin.ID,
|
||||
contentType: contentType,
|
||||
auth: "",
|
||||
status: http.StatusUnauthorized,
|
||||
err: svcerr.ErrAuthentication,
|
||||
retrieveErr: svcerr.ErrNotFound,
|
||||
updateErr: svcerr.ErrUpdateEntity,
|
||||
identifyErr: svcerr.ErrAuthentication,
|
||||
},
|
||||
{
|
||||
desc: "update twin with invalid data format",
|
||||
req: "{",
|
||||
id: stw.ID,
|
||||
id: twin.ID,
|
||||
contentType: contentType,
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
err: svcerr.ErrMalformedEntity,
|
||||
identifyErr: nil,
|
||||
retrieveErr: nil,
|
||||
updateErr: svcerr.ErrUpdateEntity,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "update twin with empty request",
|
||||
req: "",
|
||||
id: stw.ID,
|
||||
id: twin.ID,
|
||||
contentType: contentType,
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
err: svcerr.ErrMalformedEntity,
|
||||
retrieveErr: nil,
|
||||
updateErr: svcerr.ErrUpdateEntity,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "update twin without content type",
|
||||
req: data,
|
||||
id: stw.ID,
|
||||
id: twin.ID,
|
||||
contentType: "",
|
||||
auth: token,
|
||||
status: http.StatusUnsupportedMediaType,
|
||||
err: apiutil.ErrUnsupportedContentType,
|
||||
retrieveErr: nil,
|
||||
updateErr: svcerr.ErrUpdateEntity,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "update twin with invalid name",
|
||||
@@ -306,11 +382,19 @@ func TestUpdateTwin(t *testing.T) {
|
||||
contentType: contentType,
|
||||
auth: token,
|
||||
status: http.StatusMethodNotAllowed,
|
||||
err: svcerr.ErrMalformedEntity,
|
||||
retrieveErr: svcerr.ErrNotFound,
|
||||
updateErr: svcerr.ErrUpdateEntity,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.auth}).Return(&magistrala.IdentityRes{Id: testsutil.GenerateUUID(t)}, nil)
|
||||
authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.auth}).Return(&magistrala.IdentityRes{Id: tc.userID}, tc.identifyErr)
|
||||
repoCall := twinRepo.On("RetrieveByID", mock.Anything, tc.id).Return(twins.Twin{}, tc.retrieveErr)
|
||||
repoCall1 := twinRepo.On("Update", mock.Anything, mock.Anything).Return(tc.updateErr)
|
||||
cacheCall := twinCache.On("Update", mock.Anything, mock.Anything).Return(tc.err)
|
||||
req := testRequest{
|
||||
client: ts.Client(),
|
||||
method: http.MethodPut,
|
||||
@@ -322,69 +406,88 @@ func TestUpdateTwin(t *testing.T) {
|
||||
res, err := req.make()
|
||||
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))
|
||||
authCall.Unset()
|
||||
repoCall.Unset()
|
||||
repoCall1.Unset()
|
||||
cacheCall.Unset()
|
||||
}
|
||||
}
|
||||
|
||||
func TestViewTwin(t *testing.T) {
|
||||
svc, auth := mocks.NewService()
|
||||
svc, auth, twinRepo, _, _ := NewService()
|
||||
ts := newServer(svc)
|
||||
defer ts.Close()
|
||||
|
||||
def := twins.Definition{}
|
||||
twin := twins.Twin{}
|
||||
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: token}).Return(&magistrala.IdentityRes{Id: testsutil.GenerateUUID(t)}, nil)
|
||||
stw, err := svc.AddTwin(context.Background(), token, twin, def)
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
repoCall.Unset()
|
||||
twin := twins.Twin{
|
||||
Owner: email,
|
||||
ID: testsutil.GenerateUUID(t),
|
||||
Name: twinName,
|
||||
Revision: 50,
|
||||
}
|
||||
|
||||
twres := twinRes{
|
||||
Owner: stw.Owner,
|
||||
Name: stw.Name,
|
||||
ID: stw.ID,
|
||||
Revision: stw.Revision,
|
||||
Metadata: stw.Metadata,
|
||||
Owner: twin.Owner,
|
||||
Name: twin.Name,
|
||||
ID: twin.ID,
|
||||
Revision: twin.Revision,
|
||||
Metadata: twin.Metadata,
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
id string
|
||||
auth string
|
||||
status int
|
||||
res twinRes
|
||||
desc string
|
||||
id string
|
||||
auth string
|
||||
status int
|
||||
res twinRes
|
||||
err error
|
||||
twin twins.Twin
|
||||
identifyErr error
|
||||
userID string
|
||||
}{
|
||||
{
|
||||
desc: "view existing twin",
|
||||
id: stw.ID,
|
||||
auth: token,
|
||||
status: http.StatusOK,
|
||||
res: twres,
|
||||
desc: "view existing twin",
|
||||
id: twin.ID,
|
||||
auth: token,
|
||||
status: http.StatusOK,
|
||||
res: twres,
|
||||
err: nil,
|
||||
twin: twin,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "view non-existent twin",
|
||||
id: strconv.FormatUint(wrongID, 10),
|
||||
auth: token,
|
||||
status: http.StatusNotFound,
|
||||
res: twinRes{},
|
||||
desc: "view non-existent twin",
|
||||
id: strconv.FormatUint(wrongID, 10),
|
||||
auth: token,
|
||||
status: http.StatusNotFound,
|
||||
res: twinRes{},
|
||||
err: svcerr.ErrNotFound,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "view twin by passing invalid token",
|
||||
id: stw.ID,
|
||||
auth: authmocks.InvalidValue,
|
||||
status: http.StatusUnauthorized,
|
||||
res: twinRes{},
|
||||
desc: "view twin by passing invalid token",
|
||||
id: twin.ID,
|
||||
auth: authmocks.InvalidValue,
|
||||
status: http.StatusUnauthorized,
|
||||
res: twinRes{},
|
||||
err: svcerr.ErrAuthentication,
|
||||
identifyErr: svcerr.ErrAuthentication,
|
||||
},
|
||||
{
|
||||
desc: "view twin by passing empty token",
|
||||
id: stw.ID,
|
||||
auth: "",
|
||||
status: http.StatusUnauthorized,
|
||||
res: twinRes{},
|
||||
desc: "view twin by passing empty token",
|
||||
id: twin.ID,
|
||||
auth: "",
|
||||
status: http.StatusUnauthorized,
|
||||
res: twinRes{},
|
||||
err: svcerr.ErrAuthentication,
|
||||
identifyErr: svcerr.ErrAuthentication,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.auth}).Return(&magistrala.IdentityRes{Id: testsutil.GenerateUUID(t)}, nil)
|
||||
authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.auth}).Return(&magistrala.IdentityRes{Id: tc.userID}, tc.identifyErr)
|
||||
repoCall := twinRepo.On("RetrieveByID", mock.Anything, tc.id).Return(tc.twin, tc.err)
|
||||
req := testRequest{
|
||||
client: ts.Client(),
|
||||
method: http.MethodGet,
|
||||
@@ -399,33 +502,32 @@ func TestViewTwin(t *testing.T) {
|
||||
err = json.NewDecoder(res.Body).Decode(&resData)
|
||||
assert.Nil(t, err, fmt.Sprintf("%s: got unexpected error while decoding response body: %s\n", tc.desc, err))
|
||||
assert.Equal(t, tc.res, resData, fmt.Sprintf("%s: expected body %v got %v", tc.desc, tc.res, resData))
|
||||
authCall.Unset()
|
||||
repoCall.Unset()
|
||||
}
|
||||
}
|
||||
|
||||
func TestListTwins(t *testing.T) {
|
||||
svc, auth := mocks.NewService()
|
||||
svc, auth, twinRepo, _, _ := NewService()
|
||||
ts := newServer(svc)
|
||||
defer ts.Close()
|
||||
|
||||
var data []twinRes
|
||||
userID := testsutil.GenerateUUID(t)
|
||||
for i := 0; i < 100; i++ {
|
||||
name := fmt.Sprintf("%s-%d", twinName, i)
|
||||
twin := twins.Twin{
|
||||
Owner: email,
|
||||
Name: name,
|
||||
Owner: email,
|
||||
Name: name,
|
||||
ID: testsutil.GenerateUUID(t),
|
||||
Revision: 150,
|
||||
}
|
||||
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: token}).Return(&magistrala.IdentityRes{Id: userID}, nil)
|
||||
tw, err := svc.AddTwin(context.Background(), token, twin, twins.Definition{})
|
||||
assert.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
repoCall.Unset()
|
||||
|
||||
twres := twinRes{
|
||||
Owner: tw.Owner,
|
||||
ID: tw.ID,
|
||||
Name: tw.Name,
|
||||
Revision: tw.Revision,
|
||||
Metadata: tw.Metadata,
|
||||
Owner: twin.Owner,
|
||||
ID: twin.ID,
|
||||
Name: twin.Name,
|
||||
Revision: twin.Revision,
|
||||
Metadata: twin.Metadata,
|
||||
}
|
||||
data = append(data, twres)
|
||||
}
|
||||
@@ -433,11 +535,15 @@ func TestListTwins(t *testing.T) {
|
||||
baseURL := fmt.Sprintf("%s/twins", ts.URL)
|
||||
queryFmt := "%s?offset=%d&limit=%d"
|
||||
cases := []struct {
|
||||
desc string
|
||||
auth string
|
||||
status int
|
||||
url string
|
||||
res []twinRes
|
||||
desc string
|
||||
auth string
|
||||
status int
|
||||
url string
|
||||
res []twinRes
|
||||
err error
|
||||
page twins.Page
|
||||
identifyErr error
|
||||
userID string
|
||||
}{
|
||||
{
|
||||
desc: "get a list of twins",
|
||||
@@ -445,20 +551,30 @@ func TestListTwins(t *testing.T) {
|
||||
status: http.StatusOK,
|
||||
url: baseURL,
|
||||
res: data[0:10],
|
||||
err: nil,
|
||||
page: twins.Page{
|
||||
Twins: convTwin(data[0:10]),
|
||||
},
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "get a list of twins with invalid token",
|
||||
auth: authmocks.InvalidValue,
|
||||
status: http.StatusUnauthorized,
|
||||
url: fmt.Sprintf(queryFmt, baseURL, 0, 1),
|
||||
res: nil,
|
||||
desc: "get a list of twins with invalid token",
|
||||
auth: authmocks.InvalidValue,
|
||||
status: http.StatusUnauthorized,
|
||||
url: fmt.Sprintf(queryFmt, baseURL, 0, 1),
|
||||
res: nil,
|
||||
err: svcerr.ErrAuthentication,
|
||||
identifyErr: svcerr.ErrAuthentication,
|
||||
},
|
||||
{
|
||||
desc: "get a list of twins with empty token",
|
||||
auth: "",
|
||||
status: http.StatusUnauthorized,
|
||||
url: fmt.Sprintf(queryFmt, baseURL, 0, 1),
|
||||
res: nil,
|
||||
desc: "get a list of twins with empty token",
|
||||
auth: "",
|
||||
status: http.StatusUnauthorized,
|
||||
url: fmt.Sprintf(queryFmt, baseURL, 0, 1),
|
||||
res: nil,
|
||||
err: svcerr.ErrAuthentication,
|
||||
identifyErr: svcerr.ErrAuthentication,
|
||||
},
|
||||
{
|
||||
desc: "get a list of twins with valid offset and limit",
|
||||
@@ -466,6 +582,12 @@ func TestListTwins(t *testing.T) {
|
||||
status: http.StatusOK,
|
||||
url: fmt.Sprintf(queryFmt, baseURL, 25, 40),
|
||||
res: data[25:65],
|
||||
err: nil,
|
||||
page: twins.Page{
|
||||
Twins: convTwin(data[25:65]),
|
||||
},
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "get a list of twins with offset + limit > total",
|
||||
@@ -473,48 +595,72 @@ func TestListTwins(t *testing.T) {
|
||||
status: http.StatusOK,
|
||||
url: fmt.Sprintf(queryFmt, baseURL, 91, 20),
|
||||
res: data[91:],
|
||||
err: nil,
|
||||
page: twins.Page{
|
||||
Twins: convTwin(data[91:]),
|
||||
},
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "get a list of twins with negative offset",
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
url: fmt.Sprintf(queryFmt, baseURL, -1, 5),
|
||||
res: nil,
|
||||
desc: "get a list of twins with negative offset",
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
url: fmt.Sprintf(queryFmt, baseURL, -1, 5),
|
||||
res: nil,
|
||||
err: svcerr.ErrMalformedEntity,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "get a list of twins with negative limit",
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
url: fmt.Sprintf(queryFmt, baseURL, 1, -5),
|
||||
res: nil,
|
||||
desc: "get a list of twins with negative limit",
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
url: fmt.Sprintf(queryFmt, baseURL, 1, -5),
|
||||
res: nil,
|
||||
err: svcerr.ErrMalformedEntity,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "get a list of twins with zero limit",
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
url: fmt.Sprintf(queryFmt, baseURL, 1, 0),
|
||||
res: nil,
|
||||
desc: "get a list of twins with zero limit",
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
url: fmt.Sprintf(queryFmt, baseURL, 1, 0),
|
||||
res: nil,
|
||||
err: svcerr.ErrMalformedEntity,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "get a list of twins with limit greater than max",
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
url: fmt.Sprintf("%s?offset=%d&limit=%d", baseURL, 0, 110),
|
||||
res: nil,
|
||||
desc: "get a list of twins with limit greater than max",
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
url: fmt.Sprintf("%s?offset=%d&limit=%d", baseURL, 0, 110),
|
||||
res: nil,
|
||||
err: svcerr.ErrMalformedEntity,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "get a list of twins with invalid offset",
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
url: fmt.Sprintf("%s%s", baseURL, "?offset=e&limit=5"),
|
||||
res: nil,
|
||||
desc: "get a list of twins with invalid offset",
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
url: fmt.Sprintf("%s%s", baseURL, "?offset=e&limit=5"),
|
||||
res: nil,
|
||||
err: svcerr.ErrMalformedEntity,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "get a list of twins with invalid limit",
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
url: fmt.Sprintf("%s%s", baseURL, "?offset=5&limit=e"),
|
||||
res: nil,
|
||||
desc: "get a list of twins with invalid limit",
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
url: fmt.Sprintf("%s%s", baseURL, "?offset=5&limit=e"),
|
||||
res: nil,
|
||||
err: svcerr.ErrMalformedEntity,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "get a list of twins without offset",
|
||||
@@ -522,6 +668,12 @@ func TestListTwins(t *testing.T) {
|
||||
status: http.StatusOK,
|
||||
url: fmt.Sprintf("%s?limit=%d", baseURL, 5),
|
||||
res: data[0:5],
|
||||
err: nil,
|
||||
page: twins.Page{
|
||||
Twins: convTwin(data[0:5]),
|
||||
},
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "get a list of twins without limit",
|
||||
@@ -529,13 +681,22 @@ func TestListTwins(t *testing.T) {
|
||||
status: http.StatusOK,
|
||||
url: fmt.Sprintf("%s?offset=%d", baseURL, 1),
|
||||
res: data[1:11],
|
||||
err: nil,
|
||||
page: twins.Page{
|
||||
Twins: convTwin(data[1:11]),
|
||||
},
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "get a list of twins with invalid number of parameters",
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
url: fmt.Sprintf("%s%s", baseURL, "?offset=4&limit=4&limit=5&offset=5"),
|
||||
res: nil,
|
||||
desc: "get a list of twins with invalid number of parameters",
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
url: fmt.Sprintf("%s%s", baseURL, "?offset=4&limit=4&limit=5&offset=5"),
|
||||
res: nil,
|
||||
err: svcerr.ErrMalformedEntity,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "get a list of twins with redundant query parameters",
|
||||
@@ -543,13 +704,22 @@ func TestListTwins(t *testing.T) {
|
||||
status: http.StatusOK,
|
||||
url: fmt.Sprintf("%s?offset=%d&limit=%d&value=something", baseURL, 0, 5),
|
||||
res: data[0:5],
|
||||
err: nil,
|
||||
page: twins.Page{
|
||||
Twins: convTwin(data[0:5]),
|
||||
},
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "get a list of twins filtering with invalid name",
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
url: fmt.Sprintf("%s?offset=%d&limit=%d&name=%s", baseURL, 0, 5, invalidName),
|
||||
res: nil,
|
||||
desc: "get a list of twins filtering with invalid name",
|
||||
auth: token,
|
||||
status: http.StatusBadRequest,
|
||||
url: fmt.Sprintf("%s?offset=%d&limit=%d&name=%s", baseURL, 0, 5, invalidName),
|
||||
res: nil,
|
||||
err: svcerr.ErrMalformedEntity,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "get a list of twins filtering with valid name",
|
||||
@@ -557,11 +727,18 @@ func TestListTwins(t *testing.T) {
|
||||
status: http.StatusOK,
|
||||
url: fmt.Sprintf("%s?offset=%d&limit=%d&name=%s", baseURL, 2, 1, twinName+"-2"),
|
||||
res: data[2:3],
|
||||
err: nil,
|
||||
page: twins.Page{
|
||||
Twins: convTwin(data[2:3]),
|
||||
},
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.auth}).Return(&magistrala.IdentityRes{Id: userID}, nil)
|
||||
authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.auth}).Return(&magistrala.IdentityRes{Id: tc.userID}, nil)
|
||||
repoCall := twinRepo.On("RetrieveAll", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.page, tc.err)
|
||||
req := testRequest{
|
||||
client: ts.Client(),
|
||||
method: http.MethodGet,
|
||||
@@ -579,62 +756,87 @@ func TestListTwins(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.ElementsMatch(t, tc.res, resData.Twins, fmt.Sprintf("%s: got incorrect list of twins", tc.desc))
|
||||
authCall.Unset()
|
||||
repoCall.Unset()
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveTwin(t *testing.T) {
|
||||
svc, auth := mocks.NewService()
|
||||
svc, auth, twinRepo, twinCache, _ := NewService()
|
||||
ts := newServer(svc)
|
||||
defer ts.Close()
|
||||
|
||||
def := twins.Definition{}
|
||||
twin := twins.Twin{}
|
||||
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: token}).Return(&magistrala.IdentityRes{Id: testsutil.GenerateUUID(t)}, nil)
|
||||
stw, err := svc.AddTwin(context.Background(), token, twin, def)
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
repoCall.Unset()
|
||||
twin := twins.Twin{
|
||||
Owner: email,
|
||||
ID: testsutil.GenerateUUID(t),
|
||||
Name: twinName,
|
||||
Revision: 50,
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
id string
|
||||
auth string
|
||||
status int
|
||||
desc string
|
||||
id string
|
||||
auth string
|
||||
status int
|
||||
err error
|
||||
removeErr error
|
||||
identifyErr error
|
||||
userID string
|
||||
}{
|
||||
{
|
||||
desc: "delete existing twin",
|
||||
id: stw.ID,
|
||||
auth: token,
|
||||
status: http.StatusNoContent,
|
||||
desc: "delete existing twin",
|
||||
id: twin.ID,
|
||||
auth: token,
|
||||
status: http.StatusNoContent,
|
||||
err: nil,
|
||||
removeErr: nil,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "delete non-existent twin",
|
||||
id: strconv.FormatUint(wrongID, 10),
|
||||
auth: token,
|
||||
status: http.StatusNoContent,
|
||||
desc: "delete non-existent twin",
|
||||
id: strconv.FormatUint(wrongID, 10),
|
||||
auth: token,
|
||||
status: http.StatusNoContent,
|
||||
err: nil,
|
||||
removeErr: nil,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "delete twin by passing empty id",
|
||||
id: "",
|
||||
auth: token,
|
||||
status: http.StatusMethodNotAllowed,
|
||||
desc: "delete twin by passing empty id",
|
||||
id: "",
|
||||
auth: token,
|
||||
status: http.StatusMethodNotAllowed,
|
||||
err: svcerr.ErrMalformedEntity,
|
||||
removeErr: svcerr.ErrRemoveEntity,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "delete twin with invalid token",
|
||||
id: stw.ID,
|
||||
auth: authmocks.InvalidValue,
|
||||
status: http.StatusUnauthorized,
|
||||
desc: "delete twin with invalid token",
|
||||
id: twin.ID,
|
||||
auth: authmocks.InvalidValue,
|
||||
status: http.StatusUnauthorized,
|
||||
err: svcerr.ErrAuthentication,
|
||||
removeErr: svcerr.ErrRemoveEntity,
|
||||
identifyErr: svcerr.ErrAuthentication,
|
||||
},
|
||||
{
|
||||
desc: "delete twin with empty token",
|
||||
id: stw.ID,
|
||||
auth: "",
|
||||
status: http.StatusUnauthorized,
|
||||
desc: "delete twin with empty token",
|
||||
id: twin.ID,
|
||||
auth: "",
|
||||
status: http.StatusUnauthorized,
|
||||
err: svcerr.ErrAuthentication,
|
||||
removeErr: svcerr.ErrRemoveEntity,
|
||||
identifyErr: svcerr.ErrAuthentication,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.auth}).Return(&magistrala.IdentityRes{Id: testsutil.GenerateUUID(t)}, nil)
|
||||
authCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.auth}).Return(&magistrala.IdentityRes{Id: tc.userID}, tc.identifyErr)
|
||||
repoCall := twinRepo.On("Remove", mock.Anything, tc.id).Return(tc.removeErr)
|
||||
cacheCall2 := twinCache.On("Remove", mock.Anything, tc.id).Return(tc.err)
|
||||
req := testRequest{
|
||||
client: ts.Client(),
|
||||
method: http.MethodDelete,
|
||||
@@ -644,6 +846,20 @@ func TestRemoveTwin(t *testing.T) {
|
||||
res, err := req.make()
|
||||
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))
|
||||
authCall.Unset()
|
||||
repoCall.Unset()
|
||||
cacheCall2.Unset()
|
||||
}
|
||||
}
|
||||
|
||||
func convTwin(data []twinRes) []twins.Twin {
|
||||
twinSlice := make([]twins.Twin, len(data))
|
||||
for i, d := range data {
|
||||
twinSlice[i].ID = d.ID
|
||||
twinSlice[i].Name = d.Name
|
||||
twinSlice[i].Owner = d.Owner
|
||||
twinSlice[i].Revision = d.Revision
|
||||
twinSlice[i].Metadata = d.Metadata
|
||||
}
|
||||
return twinSlice
|
||||
}
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
// Code generated by mockery v2.42.3. DO NOT EDIT.
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
twins "github.com/absmach/magistrala/twins"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
// TwinCache is an autogenerated mock type for the TwinCache type
|
||||
type TwinCache struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// IDs provides a mock function with given fields: ctx, channel, subtopic
|
||||
func (_m *TwinCache) IDs(ctx context.Context, channel string, subtopic string) ([]string, error) {
|
||||
ret := _m.Called(ctx, channel, subtopic)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for IDs")
|
||||
}
|
||||
|
||||
var r0 []string
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string) ([]string, error)); ok {
|
||||
return rf(ctx, channel, subtopic)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string) []string); ok {
|
||||
r0 = rf(ctx, channel, subtopic)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]string)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok {
|
||||
r1 = rf(ctx, channel, subtopic)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Remove provides a mock function with given fields: ctx, twinID
|
||||
func (_m *TwinCache) Remove(ctx context.Context, twinID string) error {
|
||||
ret := _m.Called(ctx, twinID)
|
||||
|
||||
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, twinID)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// Save provides a mock function with given fields: ctx, twin
|
||||
func (_m *TwinCache) Save(ctx context.Context, twin twins.Twin) error {
|
||||
ret := _m.Called(ctx, twin)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Save")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, twins.Twin) error); ok {
|
||||
r0 = rf(ctx, twin)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// SaveIDs provides a mock function with given fields: ctx, channel, subtopic, twinIDs
|
||||
func (_m *TwinCache) SaveIDs(ctx context.Context, channel string, subtopic string, twinIDs []string) error {
|
||||
ret := _m.Called(ctx, channel, subtopic, twinIDs)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for SaveIDs")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string, []string) error); ok {
|
||||
r0 = rf(ctx, channel, subtopic, twinIDs)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// Update provides a mock function with given fields: ctx, twin
|
||||
func (_m *TwinCache) Update(ctx context.Context, twin twins.Twin) error {
|
||||
ret := _m.Called(ctx, twin)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Update")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, twins.Twin) error); ok {
|
||||
r0 = rf(ctx, twin)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// NewTwinCache creates a new instance of TwinCache. 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 NewTwinCache(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}) *TwinCache {
|
||||
mock := &TwinCache{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package mocks
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Since mocks will store data in map, and they need to resemble the real
|
||||
// identifiers as much as possible, a key will be created as combination of
|
||||
// owner and their id. This will allow searching by prefix or suffix.
|
||||
func key(owner, id string) string {
|
||||
return fmt.Sprintf("%s-%s", owner, id)
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
|
||||
"github.com/absmach/magistrala/pkg/messaging"
|
||||
twins "github.com/absmach/magistrala/twins"
|
||||
"github.com/absmach/senml"
|
||||
)
|
||||
|
||||
var (
|
||||
publisher = "twins"
|
||||
id = 0
|
||||
)
|
||||
|
||||
// CreateMessage creates Magistrala message using SenML record array.
|
||||
func CreateMessage(attr twins.Attribute, recs []senml.Record) (*messaging.Message, error) {
|
||||
mRecs, err := json.Marshal(recs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &messaging.Message{
|
||||
Channel: attr.Channel,
|
||||
Subtopic: attr.Subtopic,
|
||||
Payload: mRecs,
|
||||
Publisher: publisher,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CreateDefinition creates twin definition.
|
||||
func CreateDefinition(channels, subtopics []string) twins.Definition {
|
||||
var def twins.Definition
|
||||
for i := range channels {
|
||||
attr := twins.Attribute{
|
||||
Channel: channels[i],
|
||||
Subtopic: subtopics[i],
|
||||
PersistState: true,
|
||||
}
|
||||
def.Attributes = append(def.Attributes, attr)
|
||||
}
|
||||
return def
|
||||
}
|
||||
|
||||
// CreateTwin creates twin.
|
||||
func CreateTwin(channels, subtopics []string) twins.Twin {
|
||||
id++
|
||||
return twins.Twin{
|
||||
ID: strconv.Itoa(id),
|
||||
Definitions: []twins.Definition{CreateDefinition(channels, subtopics)},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
// Code generated by mockery v2.42.3. DO NOT EDIT.
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
twins "github.com/absmach/magistrala/twins"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
// TwinRepository is an autogenerated mock type for the TwinRepository type
|
||||
type TwinRepository struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// Remove provides a mock function with given fields: ctx, twinID
|
||||
func (_m *TwinRepository) Remove(ctx context.Context, twinID string) error {
|
||||
ret := _m.Called(ctx, twinID)
|
||||
|
||||
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, twinID)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// RetrieveAll provides a mock function with given fields: ctx, owner, offset, limit, name, metadata
|
||||
func (_m *TwinRepository) RetrieveAll(ctx context.Context, owner string, offset uint64, limit uint64, name string, metadata twins.Metadata) (twins.Page, error) {
|
||||
ret := _m.Called(ctx, owner, offset, limit, name, metadata)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for RetrieveAll")
|
||||
}
|
||||
|
||||
var r0 twins.Page
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, uint64, uint64, string, twins.Metadata) (twins.Page, error)); ok {
|
||||
return rf(ctx, owner, offset, limit, name, metadata)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, uint64, uint64, string, twins.Metadata) twins.Page); ok {
|
||||
r0 = rf(ctx, owner, offset, limit, name, metadata)
|
||||
} else {
|
||||
r0 = ret.Get(0).(twins.Page)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, uint64, uint64, string, twins.Metadata) error); ok {
|
||||
r1 = rf(ctx, owner, offset, limit, name, metadata)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// RetrieveByAttribute provides a mock function with given fields: ctx, channel, subtopic
|
||||
func (_m *TwinRepository) RetrieveByAttribute(ctx context.Context, channel string, subtopic string) ([]string, error) {
|
||||
ret := _m.Called(ctx, channel, subtopic)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for RetrieveByAttribute")
|
||||
}
|
||||
|
||||
var r0 []string
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string) ([]string, error)); ok {
|
||||
return rf(ctx, channel, subtopic)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string) []string); ok {
|
||||
r0 = rf(ctx, channel, subtopic)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]string)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok {
|
||||
r1 = rf(ctx, channel, subtopic)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// RetrieveByID provides a mock function with given fields: ctx, twinID
|
||||
func (_m *TwinRepository) RetrieveByID(ctx context.Context, twinID string) (twins.Twin, error) {
|
||||
ret := _m.Called(ctx, twinID)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for RetrieveByID")
|
||||
}
|
||||
|
||||
var r0 twins.Twin
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) (twins.Twin, error)); ok {
|
||||
return rf(ctx, twinID)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) twins.Twin); ok {
|
||||
r0 = rf(ctx, twinID)
|
||||
} else {
|
||||
r0 = ret.Get(0).(twins.Twin)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
|
||||
r1 = rf(ctx, twinID)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Save provides a mock function with given fields: ctx, twin
|
||||
func (_m *TwinRepository) Save(ctx context.Context, twin twins.Twin) (string, error) {
|
||||
ret := _m.Called(ctx, twin)
|
||||
|
||||
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, twins.Twin) (string, error)); ok {
|
||||
return rf(ctx, twin)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, twins.Twin) string); ok {
|
||||
r0 = rf(ctx, twin)
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, twins.Twin) error); ok {
|
||||
r1 = rf(ctx, twin)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Update provides a mock function with given fields: ctx, twin
|
||||
func (_m *TwinRepository) Update(ctx context.Context, twin twins.Twin) error {
|
||||
ret := _m.Called(ctx, twin)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Update")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, twins.Twin) error); ok {
|
||||
r0 = rf(ctx, twin)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// NewTwinRepository creates a new instance of TwinRepository. 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 NewTwinRepository(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}) *TwinRepository {
|
||||
mock := &TwinRepository{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
||||
+178
-59
@@ -1,80 +1,199 @@
|
||||
// Code generated by mockery v2.42.3. DO NOT EDIT.
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"time"
|
||||
context "context"
|
||||
|
||||
authmocks "github.com/absmach/magistrala/auth/mocks"
|
||||
mglog "github.com/absmach/magistrala/logger"
|
||||
"github.com/absmach/magistrala/pkg/messaging"
|
||||
"github.com/absmach/magistrala/pkg/uuid"
|
||||
"github.com/absmach/magistrala/twins"
|
||||
"github.com/absmach/senml"
|
||||
messaging "github.com/absmach/magistrala/pkg/messaging"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
twins "github.com/absmach/magistrala/twins"
|
||||
)
|
||||
|
||||
const publisher = "twins"
|
||||
|
||||
var id = 0
|
||||
|
||||
// NewService use mock dependencies to create real twins service.
|
||||
func NewService() (twins.Service, *authmocks.AuthClient) {
|
||||
auth := new(authmocks.AuthClient)
|
||||
twinsRepo := NewTwinRepository()
|
||||
twinCache := NewTwinCache()
|
||||
statesRepo := NewStateRepository()
|
||||
idProvider := uuid.NewMock()
|
||||
subs := map[string]string{"chanID": "chanID"}
|
||||
broker := NewBroker(subs)
|
||||
|
||||
return twins.New(broker, auth, twinsRepo, twinCache, statesRepo, idProvider, "chanID", mglog.NewMock()), auth
|
||||
// Service is an autogenerated mock type for the Service type
|
||||
type Service struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// CreateDefinition creates twin definition.
|
||||
func CreateDefinition(channels, subtopics []string) twins.Definition {
|
||||
var def twins.Definition
|
||||
for i := range channels {
|
||||
attr := twins.Attribute{
|
||||
Channel: channels[i],
|
||||
Subtopic: subtopics[i],
|
||||
PersistState: true,
|
||||
}
|
||||
def.Attributes = append(def.Attributes, attr)
|
||||
// AddTwin provides a mock function with given fields: ctx, token, twin, def
|
||||
func (_m *Service) AddTwin(ctx context.Context, token string, twin twins.Twin, def twins.Definition) (twins.Twin, error) {
|
||||
ret := _m.Called(ctx, token, twin, def)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for AddTwin")
|
||||
}
|
||||
return def
|
||||
|
||||
var r0 twins.Twin
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, twins.Twin, twins.Definition) (twins.Twin, error)); ok {
|
||||
return rf(ctx, token, twin, def)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, twins.Twin, twins.Definition) twins.Twin); ok {
|
||||
r0 = rf(ctx, token, twin, def)
|
||||
} else {
|
||||
r0 = ret.Get(0).(twins.Twin)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, twins.Twin, twins.Definition) error); ok {
|
||||
r1 = rf(ctx, token, twin, def)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// CreateTwin creates twin.
|
||||
func CreateTwin(channels, subtopics []string) twins.Twin {
|
||||
id++
|
||||
return twins.Twin{
|
||||
ID: strconv.Itoa(id),
|
||||
Definitions: []twins.Definition{CreateDefinition(channels, subtopics)},
|
||||
// ListStates provides a mock function with given fields: ctx, token, offset, limit, twinID
|
||||
func (_m *Service) ListStates(ctx context.Context, token string, offset uint64, limit uint64, twinID string) (twins.StatesPage, error) {
|
||||
ret := _m.Called(ctx, token, offset, limit, twinID)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for ListStates")
|
||||
}
|
||||
|
||||
var r0 twins.StatesPage
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, uint64, uint64, string) (twins.StatesPage, error)); ok {
|
||||
return rf(ctx, token, offset, limit, twinID)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, uint64, uint64, string) twins.StatesPage); ok {
|
||||
r0 = rf(ctx, token, offset, limit, twinID)
|
||||
} else {
|
||||
r0 = ret.Get(0).(twins.StatesPage)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, uint64, uint64, string) error); ok {
|
||||
r1 = rf(ctx, token, offset, limit, twinID)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// CreateSenML creates SenML record array.
|
||||
func CreateSenML(recs []senml.Record) {
|
||||
for i, rec := range recs {
|
||||
rec.BaseTime = float64(time.Now().Unix())
|
||||
rec.Time = float64(i)
|
||||
rec.Value = nil
|
||||
// ListTwins provides a mock function with given fields: ctx, token, offset, limit, name, metadata
|
||||
func (_m *Service) ListTwins(ctx context.Context, token string, offset uint64, limit uint64, name string, metadata twins.Metadata) (twins.Page, error) {
|
||||
ret := _m.Called(ctx, token, offset, limit, name, metadata)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for ListTwins")
|
||||
}
|
||||
|
||||
var r0 twins.Page
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, uint64, uint64, string, twins.Metadata) (twins.Page, error)); ok {
|
||||
return rf(ctx, token, offset, limit, name, metadata)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, uint64, uint64, string, twins.Metadata) twins.Page); ok {
|
||||
r0 = rf(ctx, token, offset, limit, name, metadata)
|
||||
} else {
|
||||
r0 = ret.Get(0).(twins.Page)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, uint64, uint64, string, twins.Metadata) error); ok {
|
||||
r1 = rf(ctx, token, offset, limit, name, metadata)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// CreateMessage creates Magistrala message using SenML record array.
|
||||
func CreateMessage(attr twins.Attribute, recs []senml.Record) (*messaging.Message, error) {
|
||||
mRecs, err := json.Marshal(recs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
// RemoveTwin provides a mock function with given fields: ctx, token, twinID
|
||||
func (_m *Service) RemoveTwin(ctx context.Context, token string, twinID string) error {
|
||||
ret := _m.Called(ctx, token, twinID)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for RemoveTwin")
|
||||
}
|
||||
return &messaging.Message{
|
||||
Channel: attr.Channel,
|
||||
Subtopic: attr.Subtopic,
|
||||
Payload: mRecs,
|
||||
Publisher: publisher,
|
||||
}, nil
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok {
|
||||
r0 = rf(ctx, token, twinID)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// SaveStates provides a mock function with given fields: ctx, msg
|
||||
func (_m *Service) SaveStates(ctx context.Context, msg *messaging.Message) error {
|
||||
ret := _m.Called(ctx, msg)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for SaveStates")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *messaging.Message) error); ok {
|
||||
r0 = rf(ctx, msg)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// UpdateTwin provides a mock function with given fields: ctx, token, twin, def
|
||||
func (_m *Service) UpdateTwin(ctx context.Context, token string, twin twins.Twin, def twins.Definition) error {
|
||||
ret := _m.Called(ctx, token, twin, def)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for UpdateTwin")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, twins.Twin, twins.Definition) error); ok {
|
||||
r0 = rf(ctx, token, twin, def)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// ViewTwin provides a mock function with given fields: ctx, token, twinID
|
||||
func (_m *Service) ViewTwin(ctx context.Context, token string, twinID string) (twins.Twin, error) {
|
||||
ret := _m.Called(ctx, token, twinID)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for ViewTwin")
|
||||
}
|
||||
|
||||
var r0 twins.Twin
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string) (twins.Twin, error)); ok {
|
||||
return rf(ctx, token, twinID)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string) twins.Twin); ok {
|
||||
r0 = rf(ctx, token, twinID)
|
||||
} else {
|
||||
r0 = ret.Get(0).(twins.Twin)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok {
|
||||
r1 = rf(ctx, token, twinID)
|
||||
} 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
|
||||
}
|
||||
|
||||
+124
-95
@@ -1,122 +1,151 @@
|
||||
// Code generated by mockery v2.42.3. DO NOT EDIT.
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
context "context"
|
||||
|
||||
"github.com/absmach/magistrala/twins"
|
||||
twins "github.com/absmach/magistrala/twins"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
var _ twins.StateRepository = (*stateRepositoryMock)(nil)
|
||||
|
||||
type stateRepositoryMock struct {
|
||||
mu sync.Mutex
|
||||
states map[string]twins.State
|
||||
// StateRepository is an autogenerated mock type for the StateRepository type
|
||||
type StateRepository struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// NewStateRepository creates in-memory twin repository.
|
||||
func NewStateRepository() twins.StateRepository {
|
||||
return &stateRepositoryMock{
|
||||
states: make(map[string]twins.State),
|
||||
}
|
||||
}
|
||||
// Count provides a mock function with given fields: ctx, twin
|
||||
func (_m *StateRepository) Count(ctx context.Context, twin twins.Twin) (int64, error) {
|
||||
ret := _m.Called(ctx, twin)
|
||||
|
||||
// SaveState persists the state.
|
||||
func (srm *stateRepositoryMock) Save(ctx context.Context, st twins.State) error {
|
||||
srm.mu.Lock()
|
||||
defer srm.mu.Unlock()
|
||||
|
||||
srm.states[key(st.TwinID, strconv.FormatInt(st.ID, 10))] = st
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateState updates the state.
|
||||
func (srm *stateRepositoryMock) Update(ctx context.Context, st twins.State) error {
|
||||
srm.mu.Lock()
|
||||
defer srm.mu.Unlock()
|
||||
|
||||
srm.states[key(st.TwinID, strconv.FormatInt(st.ID, 10))] = st
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CountStates returns the number of states related to twin.
|
||||
func (srm *stateRepositoryMock) Count(ctx context.Context, tw twins.Twin) (int64, error) {
|
||||
return int64(len(srm.states)), nil
|
||||
}
|
||||
|
||||
func (srm *stateRepositoryMock) RetrieveAll(ctx context.Context, offset, limit uint64, twinID string) (twins.StatesPage, error) {
|
||||
srm.mu.Lock()
|
||||
defer srm.mu.Unlock()
|
||||
|
||||
if limit <= 0 {
|
||||
return twins.StatesPage{}, nil
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Count")
|
||||
}
|
||||
|
||||
var items []twins.State
|
||||
for k, v := range srm.states {
|
||||
if (uint64)(len(items)) >= limit {
|
||||
break
|
||||
}
|
||||
if !strings.HasPrefix(k, twinID) {
|
||||
continue
|
||||
}
|
||||
id := uint64(v.ID)
|
||||
if id >= offset && id < offset+limit {
|
||||
items = append(items, v)
|
||||
}
|
||||
var r0 int64
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, twins.Twin) (int64, error)); ok {
|
||||
return rf(ctx, twin)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, twins.Twin) int64); ok {
|
||||
r0 = rf(ctx, twin)
|
||||
} else {
|
||||
r0 = ret.Get(0).(int64)
|
||||
}
|
||||
|
||||
sort.SliceStable(items, func(i, j int) bool {
|
||||
return items[i].ID < items[j].ID
|
||||
})
|
||||
|
||||
page := twins.StatesPage{
|
||||
States: items,
|
||||
PageMetadata: twins.PageMetadata{
|
||||
Total: srm.total(twinID),
|
||||
Offset: offset,
|
||||
Limit: limit,
|
||||
},
|
||||
if rf, ok := ret.Get(1).(func(context.Context, twins.Twin) error); ok {
|
||||
r1 = rf(ctx, twin)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return page, nil
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
func (srm *stateRepositoryMock) total(twinID string) uint64 {
|
||||
var total uint64
|
||||
for k := range srm.states {
|
||||
if strings.HasPrefix(k, twinID) {
|
||||
total++
|
||||
}
|
||||
// RetrieveAll provides a mock function with given fields: ctx, offset, limit, twinID
|
||||
func (_m *StateRepository) RetrieveAll(ctx context.Context, offset uint64, limit uint64, twinID string) (twins.StatesPage, error) {
|
||||
ret := _m.Called(ctx, offset, limit, twinID)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for RetrieveAll")
|
||||
}
|
||||
return total
|
||||
|
||||
var r0 twins.StatesPage
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, uint64, uint64, string) (twins.StatesPage, error)); ok {
|
||||
return rf(ctx, offset, limit, twinID)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, uint64, uint64, string) twins.StatesPage); ok {
|
||||
r0 = rf(ctx, offset, limit, twinID)
|
||||
} else {
|
||||
r0 = ret.Get(0).(twins.StatesPage)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, uint64, uint64, string) error); ok {
|
||||
r1 = rf(ctx, offset, limit, twinID)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// RetrieveLast returns the last state related to twin spec by id.
|
||||
func (srm *stateRepositoryMock) RetrieveLast(ctx context.Context, twinID string) (twins.State, error) {
|
||||
srm.mu.Lock()
|
||||
defer srm.mu.Unlock()
|
||||
// RetrieveLast provides a mock function with given fields: ctx, twinID
|
||||
func (_m *StateRepository) RetrieveLast(ctx context.Context, twinID string) (twins.State, error) {
|
||||
ret := _m.Called(ctx, twinID)
|
||||
|
||||
items := make([]twins.State, 0)
|
||||
for _, v := range srm.states {
|
||||
if v.TwinID == twinID {
|
||||
items = append(items, v)
|
||||
}
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for RetrieveLast")
|
||||
}
|
||||
sort.SliceStable(items, func(i, j int) bool {
|
||||
return items[i].ID < items[j].ID
|
||||
})
|
||||
|
||||
if len(items) > 0 {
|
||||
return items[len(items)-1], nil
|
||||
var r0 twins.State
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) (twins.State, error)); ok {
|
||||
return rf(ctx, twinID)
|
||||
}
|
||||
return twins.State{}, nil
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) twins.State); ok {
|
||||
r0 = rf(ctx, twinID)
|
||||
} else {
|
||||
r0 = ret.Get(0).(twins.State)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
|
||||
r1 = rf(ctx, twinID)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Save provides a mock function with given fields: ctx, state
|
||||
func (_m *StateRepository) Save(ctx context.Context, state twins.State) error {
|
||||
ret := _m.Called(ctx, state)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Save")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, twins.State) error); ok {
|
||||
r0 = rf(ctx, state)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// Update provides a mock function with given fields: ctx, state
|
||||
func (_m *StateRepository) Update(ctx context.Context, state twins.State) error {
|
||||
ret := _m.Called(ctx, state)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Update")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, twins.State) error); ok {
|
||||
r0 = rf(ctx, state)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// NewStateRepository creates a new instance of StateRepository. 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 NewStateRepository(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}) *StateRepository {
|
||||
mock := &StateRepository{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
||||
|
||||
@@ -1,259 +0,0 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
repoerr "github.com/absmach/magistrala/pkg/errors/repository"
|
||||
"github.com/absmach/magistrala/pkg/uuid"
|
||||
"github.com/absmach/magistrala/twins"
|
||||
)
|
||||
|
||||
var _ twins.TwinRepository = (*twinRepositoryMock)(nil)
|
||||
|
||||
type twinRepositoryMock struct {
|
||||
mu sync.Mutex
|
||||
twins map[string]twins.Twin
|
||||
}
|
||||
|
||||
// NewTwinRepository creates in-memory twin repository.
|
||||
func NewTwinRepository() twins.TwinRepository {
|
||||
return &twinRepositoryMock{
|
||||
twins: make(map[string]twins.Twin),
|
||||
}
|
||||
}
|
||||
|
||||
func (trm *twinRepositoryMock) Save(ctx context.Context, twin twins.Twin) (string, error) {
|
||||
trm.mu.Lock()
|
||||
defer trm.mu.Unlock()
|
||||
|
||||
for _, tw := range trm.twins {
|
||||
if tw.ID == twin.ID {
|
||||
return "", repoerr.ErrConflict
|
||||
}
|
||||
}
|
||||
|
||||
trm.twins[key(twin.Owner, twin.ID)] = twin
|
||||
|
||||
return twin.ID, nil
|
||||
}
|
||||
|
||||
func (trm *twinRepositoryMock) Update(ctx context.Context, twin twins.Twin) error {
|
||||
trm.mu.Lock()
|
||||
defer trm.mu.Unlock()
|
||||
|
||||
dbKey := key(twin.Owner, twin.ID)
|
||||
if _, ok := trm.twins[dbKey]; !ok {
|
||||
return repoerr.ErrNotFound
|
||||
}
|
||||
|
||||
trm.twins[dbKey] = twin
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (trm *twinRepositoryMock) RetrieveByID(_ context.Context, twinID string) (twins.Twin, error) {
|
||||
trm.mu.Lock()
|
||||
defer trm.mu.Unlock()
|
||||
|
||||
for k, v := range trm.twins {
|
||||
if twinID == v.ID {
|
||||
return trm.twins[k], nil
|
||||
}
|
||||
}
|
||||
|
||||
return twins.Twin{}, repoerr.ErrNotFound
|
||||
}
|
||||
|
||||
func (trm *twinRepositoryMock) RetrieveByAttribute(ctx context.Context, channel, subtopic string) ([]string, error) {
|
||||
var ids []string
|
||||
for _, twin := range trm.twins {
|
||||
def := twin.Definitions[len(twin.Definitions)-1]
|
||||
for _, attr := range def.Attributes {
|
||||
if attr.Channel == channel && (attr.Subtopic == twins.SubtopicWildcard || attr.Subtopic == subtopic) {
|
||||
ids = append(ids, twin.ID)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return ids, nil
|
||||
}
|
||||
|
||||
func (trm *twinRepositoryMock) RetrieveAll(_ context.Context, owner string, offset, limit uint64, name string, metadata twins.Metadata) (twins.Page, error) {
|
||||
trm.mu.Lock()
|
||||
defer trm.mu.Unlock()
|
||||
|
||||
items := make([]twins.Twin, 0)
|
||||
|
||||
if limit <= 0 {
|
||||
return twins.Page{}, nil
|
||||
}
|
||||
|
||||
for k, v := range trm.twins {
|
||||
if (uint64)(len(items)) >= limit {
|
||||
break
|
||||
}
|
||||
if name != "" && v.Name != name {
|
||||
continue
|
||||
}
|
||||
if !strings.HasPrefix(k, owner) {
|
||||
continue
|
||||
}
|
||||
suffix := string(v.ID[len(uuid.Prefix):])
|
||||
id, _ := strconv.ParseUint(suffix, 10, 64)
|
||||
if id > offset && id <= offset+limit {
|
||||
items = append(items, v)
|
||||
}
|
||||
}
|
||||
|
||||
sort.SliceStable(items, func(i, j int) bool {
|
||||
return items[i].ID < items[j].ID
|
||||
})
|
||||
|
||||
total := uint64(len(trm.twins))
|
||||
page := twins.Page{
|
||||
Twins: items,
|
||||
PageMetadata: twins.PageMetadata{
|
||||
Total: total,
|
||||
Offset: offset,
|
||||
Limit: limit,
|
||||
},
|
||||
}
|
||||
|
||||
return page, nil
|
||||
}
|
||||
|
||||
func (trm *twinRepositoryMock) Remove(ctx context.Context, twinID string) error {
|
||||
trm.mu.Lock()
|
||||
defer trm.mu.Unlock()
|
||||
|
||||
for k, v := range trm.twins {
|
||||
if twinID == v.ID {
|
||||
delete(trm.twins, k)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type twinCacheMock struct {
|
||||
mu sync.Mutex
|
||||
attrIds map[string]map[string]bool
|
||||
idAttrs map[string]map[string]bool
|
||||
}
|
||||
|
||||
// NewTwinCache returns mock cache instance.
|
||||
func NewTwinCache() twins.TwinCache {
|
||||
return &twinCacheMock{
|
||||
attrIds: make(map[string]map[string]bool),
|
||||
idAttrs: make(map[string]map[string]bool),
|
||||
}
|
||||
}
|
||||
|
||||
func (tcm *twinCacheMock) Save(_ context.Context, twin twins.Twin) error {
|
||||
tcm.mu.Lock()
|
||||
defer tcm.mu.Unlock()
|
||||
|
||||
if len(twin.Definitions) < 1 {
|
||||
return nil
|
||||
}
|
||||
def := twin.Definitions[len(twin.Definitions)-1]
|
||||
tcm.save(def, twin.ID)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tcm *twinCacheMock) SaveIDs(ctx context.Context, channel, subtopic string, ids []string) error {
|
||||
tcm.mu.Lock()
|
||||
defer tcm.mu.Unlock()
|
||||
|
||||
for _, id := range ids {
|
||||
attrKey := channel + subtopic
|
||||
if _, ok := tcm.attrIds[attrKey]; !ok {
|
||||
tcm.attrIds[attrKey] = make(map[string]bool)
|
||||
}
|
||||
tcm.attrIds[attrKey][id] = true
|
||||
|
||||
if _, ok := tcm.idAttrs[id]; !ok {
|
||||
tcm.idAttrs[id] = make(map[string]bool)
|
||||
}
|
||||
tcm.idAttrs[id][attrKey] = true
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tcm *twinCacheMock) Update(_ context.Context, twin twins.Twin) error {
|
||||
tcm.mu.Lock()
|
||||
defer tcm.mu.Unlock()
|
||||
|
||||
if err := tcm.remove(twin.ID); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(twin.Definitions) < 1 {
|
||||
return nil
|
||||
}
|
||||
def := twin.Definitions[len(twin.Definitions)-1]
|
||||
tcm.save(def, twin.ID)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tcm *twinCacheMock) IDs(_ context.Context, channel, subtopic string) ([]string, error) {
|
||||
tcm.mu.Lock()
|
||||
defer tcm.mu.Unlock()
|
||||
|
||||
var ids []string
|
||||
|
||||
for k := range tcm.attrIds[channel+subtopic] {
|
||||
ids = append(ids, k)
|
||||
}
|
||||
for k := range tcm.attrIds[channel+twins.SubtopicWildcard] {
|
||||
ids = append(ids, k)
|
||||
}
|
||||
|
||||
return ids, nil
|
||||
}
|
||||
|
||||
func (tcm *twinCacheMock) Remove(_ context.Context, twinID string) error {
|
||||
tcm.mu.Lock()
|
||||
defer tcm.mu.Unlock()
|
||||
|
||||
return tcm.remove(twinID)
|
||||
}
|
||||
|
||||
func (tcm *twinCacheMock) remove(twinID string) error {
|
||||
attrKeys, ok := tcm.idAttrs[twinID]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
delete(tcm.idAttrs, twinID)
|
||||
for attrKey := range attrKeys {
|
||||
delete(tcm.attrIds[attrKey], twinID)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tcm *twinCacheMock) save(def twins.Definition, twinID string) {
|
||||
for _, attr := range def.Attributes {
|
||||
attrKey := attr.Channel + attr.Subtopic
|
||||
if _, ok := tcm.attrIds[attrKey]; !ok {
|
||||
tcm.attrIds[attrKey] = make(map[string]bool)
|
||||
}
|
||||
tcm.attrIds[attrKey][twinID] = true
|
||||
|
||||
idKey := twinID
|
||||
if _, ok := tcm.idAttrs[idKey]; !ok {
|
||||
tcm.idAttrs[idKey] = make(map[string]bool)
|
||||
}
|
||||
tcm.idAttrs[idKey][attrKey] = true
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,8 @@ const publisher = "twins"
|
||||
|
||||
// Service specifies an API that must be fullfiled by the domain service
|
||||
// implementation, and all of its decorators (e.g. logging & metrics).
|
||||
//
|
||||
//go:generate mockery --name Service --output=./mocks --filename service.go --quiet --note "Copyright (c) Abstract Machines"
|
||||
type Service interface {
|
||||
// AddTwin adds new twin related to user identified by the provided key.
|
||||
AddTwin(ctx context.Context, token string, twin Twin, def Definition) (tw Twin, err error)
|
||||
|
||||
+342
-210
@@ -11,14 +11,15 @@ import (
|
||||
"github.com/absmach/magistrala"
|
||||
authmocks "github.com/absmach/magistrala/auth/mocks"
|
||||
"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"
|
||||
"github.com/absmach/magistrala/pkg/uuid"
|
||||
"github.com/absmach/magistrala/twins"
|
||||
"github.com/absmach/magistrala/twins/mocks"
|
||||
"github.com/absmach/senml"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -27,6 +28,8 @@ const (
|
||||
token = "token"
|
||||
email = "user@example.com"
|
||||
numRecs = 100
|
||||
retained = "saved"
|
||||
validID = "123e4567-e89b-12d3-a456-426614174000"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -34,274 +37,349 @@ var (
|
||||
channels = []string{"01ec3c3e-0e66-4e69-9751-a0545b44e08f", "48061e4f-7c23-4f5c-9012-0f9b7cd9d18d", "5b2180e4-e96b-4469-9dc1-b6745078d0b6"}
|
||||
)
|
||||
|
||||
func NewService() (twins.Service, *authmocks.AuthClient, *mocks.TwinRepository, *mocks.TwinCache, *mocks.StateRepository) {
|
||||
auth := new(authmocks.AuthClient)
|
||||
twinsRepo := new(mocks.TwinRepository)
|
||||
twinCache := new(mocks.TwinCache)
|
||||
statesRepo := new(mocks.StateRepository)
|
||||
idProvider := uuid.NewMock()
|
||||
subs := map[string]string{"chanID": "chanID"}
|
||||
broker := mocks.NewBroker(subs)
|
||||
|
||||
return twins.New(broker, auth, twinsRepo, twinCache, statesRepo, idProvider, "chanID", mglog.NewMock()), auth, twinsRepo, twinCache, statesRepo
|
||||
}
|
||||
|
||||
func TestAddTwin(t *testing.T) {
|
||||
svc, auth := mocks.NewService()
|
||||
svc, auth, twinRepo, twinCache, _ := NewService()
|
||||
twin := twins.Twin{}
|
||||
def := twins.Definition{}
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
twin twins.Twin
|
||||
token string
|
||||
err error
|
||||
desc string
|
||||
twin twins.Twin
|
||||
token string
|
||||
err error
|
||||
saveErr error
|
||||
identifyErr error
|
||||
userID string
|
||||
}{
|
||||
{
|
||||
desc: "add new twin",
|
||||
twin: twin,
|
||||
token: token,
|
||||
err: nil,
|
||||
desc: "add new twin",
|
||||
twin: twin,
|
||||
token: token,
|
||||
err: nil,
|
||||
saveErr: nil,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "add twin with wrong credentials",
|
||||
twin: twin,
|
||||
token: authmocks.InvalidValue,
|
||||
err: svcerr.ErrAuthentication,
|
||||
desc: "add twin with wrong credentials",
|
||||
twin: twin,
|
||||
token: authmocks.InvalidValue,
|
||||
err: svcerr.ErrAuthentication,
|
||||
saveErr: svcerr.ErrCreateEntity,
|
||||
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)
|
||||
authCall := auth.On("Identify", context.Background(), &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: tc.userID}, tc.identifyErr)
|
||||
repoCall := twinRepo.On("Save", context.Background(), mock.Anything).Return(retained, tc.saveErr)
|
||||
cacheCall := twinCache.On("Save", context.Background(), mock.Anything).Return(tc.err)
|
||||
_, err := svc.AddTwin(context.Background(), tc.token, tc.twin, def)
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
authCall.Unset()
|
||||
repoCall.Unset()
|
||||
cacheCall.Unset()
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateTwin(t *testing.T) {
|
||||
svc, auth := mocks.NewService()
|
||||
twin := twins.Twin{}
|
||||
svc, auth, twinRepo, twinCache, _ := NewService()
|
||||
|
||||
other := twins.Twin{}
|
||||
def := twins.Definition{}
|
||||
twin := twins.Twin{
|
||||
Owner: email,
|
||||
ID: testsutil.GenerateUUID(t),
|
||||
Name: twinName,
|
||||
}
|
||||
|
||||
other.ID = wrongID
|
||||
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: token}).Return(&magistrala.IdentityRes{Id: testsutil.GenerateUUID(t)}, nil)
|
||||
saved, err := svc.AddTwin(context.Background(), token, twin, def)
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s\n", err))
|
||||
repoCall.Unset()
|
||||
|
||||
saved.Name = twinName
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
twin twins.Twin
|
||||
token string
|
||||
err error
|
||||
desc string
|
||||
twin twins.Twin
|
||||
token string
|
||||
err error
|
||||
retrieveErr error
|
||||
updateErr error
|
||||
identifyErr error
|
||||
userID string
|
||||
}{
|
||||
{
|
||||
desc: "update existing twin",
|
||||
twin: saved,
|
||||
token: token,
|
||||
err: nil,
|
||||
desc: "update existing twin",
|
||||
twin: twin,
|
||||
token: token,
|
||||
err: nil,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "update twin with wrong credentials",
|
||||
twin: saved,
|
||||
token: authmocks.InvalidValue,
|
||||
err: svcerr.ErrAuthentication,
|
||||
desc: "update twin with wrong credentials",
|
||||
twin: twin,
|
||||
token: authmocks.InvalidValue,
|
||||
err: svcerr.ErrAuthentication,
|
||||
retrieveErr: svcerr.ErrNotFound,
|
||||
updateErr: svcerr.ErrUpdateEntity,
|
||||
identifyErr: svcerr.ErrAuthentication,
|
||||
},
|
||||
{
|
||||
desc: "update non-existing twin",
|
||||
twin: other,
|
||||
token: token,
|
||||
err: svcerr.ErrNotFound,
|
||||
desc: "update non-existing twin",
|
||||
twin: other,
|
||||
token: token,
|
||||
err: svcerr.ErrNotFound,
|
||||
retrieveErr: svcerr.ErrNotFound,
|
||||
updateErr: svcerr.ErrUpdateEntity,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: testsutil.GenerateUUID(t)}, nil)
|
||||
authCall := auth.On("Identify", context.Background(), &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: tc.userID}, tc.identifyErr)
|
||||
repoCall := twinRepo.On("RetrieveByID", context.Background(), tc.twin.ID).Return(tc.twin, tc.retrieveErr)
|
||||
repoCall1 := twinRepo.On("Update", context.Background(), mock.Anything).Return(tc.updateErr)
|
||||
cacheCall := twinCache.On("Update", context.Background(), mock.Anything).Return(tc.err)
|
||||
err := svc.UpdateTwin(context.Background(), tc.token, tc.twin, def)
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
authCall.Unset()
|
||||
repoCall.Unset()
|
||||
repoCall1.Unset()
|
||||
cacheCall.Unset()
|
||||
}
|
||||
}
|
||||
|
||||
func TestViewTwin(t *testing.T) {
|
||||
svc, auth := mocks.NewService()
|
||||
twin := twins.Twin{}
|
||||
def := twins.Definition{}
|
||||
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: token}).Return(&magistrala.IdentityRes{Id: testsutil.GenerateUUID(t)}, nil)
|
||||
saved, err := svc.AddTwin(context.Background(), token, twin, def)
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s\n", err))
|
||||
repoCall.Unset()
|
||||
svc, auth, twinRepo, _, _ := NewService()
|
||||
|
||||
twin := twins.Twin{
|
||||
Owner: email,
|
||||
ID: testsutil.GenerateUUID(t),
|
||||
Name: twinName,
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
id string
|
||||
token string
|
||||
err error
|
||||
desc string
|
||||
id string
|
||||
token string
|
||||
err error
|
||||
identifyErr error
|
||||
userID string
|
||||
}{
|
||||
{
|
||||
desc: "view existing twin",
|
||||
id: saved.ID,
|
||||
token: token,
|
||||
err: nil,
|
||||
desc: "view existing twin",
|
||||
id: twin.ID,
|
||||
token: token,
|
||||
err: nil,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "view twin with wrong credentials",
|
||||
id: saved.ID,
|
||||
token: authmocks.InvalidValue,
|
||||
err: svcerr.ErrAuthentication,
|
||||
desc: "view twin with wrong credentials",
|
||||
id: twin.ID,
|
||||
token: authmocks.InvalidValue,
|
||||
err: svcerr.ErrAuthentication,
|
||||
identifyErr: svcerr.ErrAuthentication,
|
||||
},
|
||||
{
|
||||
desc: "view non-existing twin",
|
||||
id: wrongID,
|
||||
token: token,
|
||||
err: svcerr.ErrNotFound,
|
||||
desc: "view non-existing twin",
|
||||
id: wrongID,
|
||||
token: token,
|
||||
err: svcerr.ErrNotFound,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: testsutil.GenerateUUID(t)}, nil)
|
||||
authCall := auth.On("Identify", context.Background(), &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: tc.userID}, tc.identifyErr)
|
||||
repoCall := twinRepo.On("RetrieveByID", context.Background(), tc.id).Return(twins.Twin{}, tc.err)
|
||||
_, err := svc.ViewTwin(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))
|
||||
authCall.Unset()
|
||||
repoCall.Unset()
|
||||
}
|
||||
}
|
||||
|
||||
func TestListTwins(t *testing.T) {
|
||||
svc, auth := mocks.NewService()
|
||||
svc, auth, twinRepo, _, _ := NewService()
|
||||
twin := twins.Twin{Name: twinName, Owner: email}
|
||||
def := twins.Definition{}
|
||||
m := make(map[string]interface{})
|
||||
m["serial"] = "123456"
|
||||
twin.Metadata = m
|
||||
|
||||
n := uint64(10)
|
||||
for i := uint64(0); i < n; i++ {
|
||||
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: token}).Return(&magistrala.IdentityRes{Id: testsutil.GenerateUUID(t)}, nil)
|
||||
_, err := svc.AddTwin(context.Background(), token, twin, def)
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s\n", err))
|
||||
repoCall.Unset()
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
token string
|
||||
offset uint64
|
||||
limit uint64
|
||||
size uint64
|
||||
metadata map[string]interface{}
|
||||
err error
|
||||
desc string
|
||||
token string
|
||||
offset uint64
|
||||
limit uint64
|
||||
size uint64
|
||||
metadata map[string]interface{}
|
||||
err error
|
||||
repoerr error
|
||||
identifyErr error
|
||||
userID string
|
||||
}{
|
||||
{
|
||||
desc: "list all twins",
|
||||
token: token,
|
||||
offset: 0,
|
||||
limit: n,
|
||||
size: n,
|
||||
err: nil,
|
||||
desc: "list all twins",
|
||||
token: token,
|
||||
offset: 0,
|
||||
limit: n,
|
||||
size: n,
|
||||
err: nil,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "list with zero limit",
|
||||
token: token,
|
||||
limit: 0,
|
||||
offset: 0,
|
||||
size: 0,
|
||||
err: nil,
|
||||
desc: "list with zero limit",
|
||||
token: token,
|
||||
limit: 0,
|
||||
offset: 0,
|
||||
size: 0,
|
||||
err: nil,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "list with offset and limit",
|
||||
token: token,
|
||||
offset: 8,
|
||||
limit: 5,
|
||||
size: 2,
|
||||
err: nil,
|
||||
desc: "list with offset and limit",
|
||||
token: token,
|
||||
offset: 8,
|
||||
limit: 5,
|
||||
size: 2,
|
||||
err: nil,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "list with wrong credentials",
|
||||
token: authmocks.InvalidValue,
|
||||
limit: 0,
|
||||
offset: n,
|
||||
err: svcerr.ErrAuthentication,
|
||||
desc: "list with wrong credentials",
|
||||
token: authmocks.InvalidValue,
|
||||
limit: 0,
|
||||
offset: n,
|
||||
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)
|
||||
authCall := auth.On("Identify", context.Background(), &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: tc.userID}, tc.identifyErr)
|
||||
repoCall := twinRepo.On("RetrieveAll", context.Background(), mock.Anything, tc.offset, tc.limit, twinName, mock.Anything).Return(twins.Page{}, tc.err)
|
||||
_, err := svc.ListTwins(context.Background(), tc.token, tc.offset, tc.limit, twinName, tc.metadata)
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
authCall.Unset()
|
||||
repoCall.Unset()
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveTwin(t *testing.T) {
|
||||
svc, auth := mocks.NewService()
|
||||
twin := twins.Twin{}
|
||||
def := twins.Definition{}
|
||||
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: token}).Return(&magistrala.IdentityRes{Id: testsutil.GenerateUUID(t)}, nil)
|
||||
saved, err := svc.AddTwin(context.Background(), token, twin, def)
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s\n", err))
|
||||
repoCall.Unset()
|
||||
svc, auth, twinRepo, twinCache, _ := NewService()
|
||||
twin := twins.Twin{
|
||||
Owner: email,
|
||||
ID: testsutil.GenerateUUID(t),
|
||||
Name: twinName,
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
id string
|
||||
token string
|
||||
err error
|
||||
desc string
|
||||
id string
|
||||
token string
|
||||
err error
|
||||
removeErr error
|
||||
identifyErr error
|
||||
userID string
|
||||
}{
|
||||
{
|
||||
desc: "remove twin with wrong credentials",
|
||||
id: saved.ID,
|
||||
token: authmocks.InvalidValue,
|
||||
err: svcerr.ErrAuthentication,
|
||||
desc: "remove twin with wrong credentials",
|
||||
id: twin.ID,
|
||||
token: authmocks.InvalidValue,
|
||||
err: svcerr.ErrAuthentication,
|
||||
removeErr: svcerr.ErrRemoveEntity,
|
||||
identifyErr: svcerr.ErrAuthentication,
|
||||
},
|
||||
{
|
||||
desc: "remove existing twin",
|
||||
id: saved.ID,
|
||||
token: token,
|
||||
err: nil,
|
||||
desc: "remove existing twin",
|
||||
id: twin.ID,
|
||||
token: token,
|
||||
err: nil,
|
||||
removeErr: nil,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "remove removed twin",
|
||||
id: saved.ID,
|
||||
token: token,
|
||||
err: nil,
|
||||
desc: "remove removed twin",
|
||||
id: twin.ID,
|
||||
token: token,
|
||||
err: nil,
|
||||
removeErr: nil,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "remove non-existing twin",
|
||||
id: wrongID,
|
||||
token: token,
|
||||
err: nil,
|
||||
desc: "remove non-existing twin",
|
||||
id: wrongID,
|
||||
token: token,
|
||||
err: nil,
|
||||
removeErr: nil,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: testsutil.GenerateUUID(t)}, nil)
|
||||
authCall := auth.On("Identify", context.Background(), &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: tc.userID}, tc.identifyErr)
|
||||
repoCall := twinRepo.On("Remove", context.Background(), tc.id).Return(tc.removeErr)
|
||||
cacheCall := twinCache.On("Remove", context.Background(), tc.id).Return(tc.err)
|
||||
err := svc.RemoveTwin(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))
|
||||
authCall.Unset()
|
||||
repoCall.Unset()
|
||||
cacheCall.Unset()
|
||||
}
|
||||
}
|
||||
|
||||
func TestSaveStates(t *testing.T) {
|
||||
svc, auth := mocks.NewService()
|
||||
svc, auth, twinRepo, twinCache, stateRepo := NewService()
|
||||
|
||||
twin := twins.Twin{Owner: email}
|
||||
def := mocks.CreateDefinition(channels[0:2], subtopics[0:2])
|
||||
twin := twins.Twin{
|
||||
Owner: email,
|
||||
ID: testsutil.GenerateUUID(t),
|
||||
Name: twinName,
|
||||
Definitions: []twins.Definition{def},
|
||||
}
|
||||
|
||||
attr := def.Attributes[0]
|
||||
attrSansTwin := mocks.CreateDefinition(channels[2:3], subtopics[2:3]).Attributes[0]
|
||||
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: token}).Return(&magistrala.IdentityRes{Id: testsutil.GenerateUUID(t)}, nil)
|
||||
tw, err := svc.AddTwin(context.Background(), token, twin, def)
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
repoCall.Unset()
|
||||
|
||||
defWildcard := mocks.CreateDefinition(channels[0:2], []string{twins.SubtopicWildcard, twins.SubtopicWildcard})
|
||||
repoCall = auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: token}).Return(&magistrala.IdentityRes{Id: testsutil.GenerateUUID(t)}, nil)
|
||||
twWildcard, err := svc.AddTwin(context.Background(), token, twin, defWildcard)
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
repoCall.Unset()
|
||||
twWildcard := twins.Twin{
|
||||
Definitions: []twins.Definition{defWildcard},
|
||||
}
|
||||
|
||||
recs := make([]senml.Record, numRecs)
|
||||
mocks.CreateSenML(recs)
|
||||
|
||||
var ttlAdded uint64
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
recs []senml.Record
|
||||
attr twins.Attribute
|
||||
size uint64
|
||||
err error
|
||||
desc string
|
||||
recs []senml.Record
|
||||
attr twins.Attribute
|
||||
size uint64
|
||||
err error
|
||||
String []string
|
||||
page twins.StatesPage
|
||||
}{
|
||||
{
|
||||
desc: "add 100 states",
|
||||
@@ -309,6 +387,11 @@ func TestSaveStates(t *testing.T) {
|
||||
attr: attr,
|
||||
size: numRecs,
|
||||
err: nil,
|
||||
page: twins.StatesPage{
|
||||
PageMetadata: twins.PageMetadata{
|
||||
Total: numRecs,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "add 20 states",
|
||||
@@ -316,6 +399,11 @@ func TestSaveStates(t *testing.T) {
|
||||
attr: attr,
|
||||
size: 20,
|
||||
err: nil,
|
||||
page: twins.StatesPage{
|
||||
PageMetadata: twins.PageMetadata{
|
||||
Total: numRecs + 20,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "add 20 states for atttribute without twin",
|
||||
@@ -323,6 +411,11 @@ func TestSaveStates(t *testing.T) {
|
||||
size: 0,
|
||||
attr: attrSansTwin,
|
||||
err: svcerr.ErrNotFound,
|
||||
page: twins.StatesPage{
|
||||
PageMetadata: twins.PageMetadata{
|
||||
Total: numRecs + 20,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "use empty senml record",
|
||||
@@ -330,135 +423,174 @@ func TestSaveStates(t *testing.T) {
|
||||
attr: attr,
|
||||
size: 0,
|
||||
err: nil,
|
||||
page: twins.StatesPage{
|
||||
PageMetadata: twins.PageMetadata{
|
||||
Total: numRecs + 20,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: token}).Return(&magistrala.IdentityRes{Id: testsutil.GenerateUUID(t)}, nil)
|
||||
repoCall := auth.On("Identify", context.TODO(), &magistrala.IdentityReq{Token: token}).Return(&magistrala.IdentityRes{Id: testsutil.GenerateUUID(t)}, nil)
|
||||
message, err := mocks.CreateMessage(tc.attr, tc.recs)
|
||||
assert.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
|
||||
repoCall1 := twinRepo.On("RetrieveByAttribute", context.Background(), mock.Anything, mock.Anything).Return(tc.String, nil)
|
||||
repoCall2 := twinRepo.On("SaveIDs", context.Background(), mock.Anything, mock.Anything, mock.Anything).Return(tc.err)
|
||||
repoCall3 := twinCache.On("IDs", context.Background(), mock.Anything, mock.Anything).Return(tc.String, nil)
|
||||
err = svc.SaveStates(context.Background(), message)
|
||||
assert.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
|
||||
ttlAdded += tc.size
|
||||
page, err := svc.ListStates(context.TODO(), token, 0, 10, tw.ID)
|
||||
repoCall4 := stateRepo.On("RetrieveAll", context.TODO(), mock.Anything, mock.Anything, twin.ID).Return(tc.page, nil)
|
||||
page, err := svc.ListStates(context.TODO(), token, 0, 10, twin.ID)
|
||||
assert.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
assert.Equal(t, ttlAdded, page.Total, fmt.Sprintf("%s: expected %d total got %d total\n", tc.desc, ttlAdded, page.Total))
|
||||
|
||||
repoCall5 := stateRepo.On("RetrieveAll", context.TODO(), mock.Anything, mock.Anything, twWildcard.ID).Return(tc.page, nil)
|
||||
page, err = svc.ListStates(context.TODO(), token, 0, 10, twWildcard.ID)
|
||||
assert.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
assert.Equal(t, ttlAdded, page.Total, fmt.Sprintf("%s: expected %d total got %d total\n", tc.desc, ttlAdded, page.Total))
|
||||
repoCall.Unset()
|
||||
repoCall1.Unset()
|
||||
repoCall2.Unset()
|
||||
repoCall3.Unset()
|
||||
repoCall4.Unset()
|
||||
repoCall5.Unset()
|
||||
}
|
||||
}
|
||||
|
||||
func TestListStates(t *testing.T) {
|
||||
svc, auth := mocks.NewService()
|
||||
svc, auth, _, _, stateRepo := NewService()
|
||||
|
||||
twin := twins.Twin{Owner: email}
|
||||
def := mocks.CreateDefinition(channels[0:2], subtopics[0:2])
|
||||
attr := def.Attributes[0]
|
||||
repoCall := auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: token}).Return(&magistrala.IdentityRes{Id: testsutil.GenerateUUID(t)}, nil)
|
||||
tw, err := svc.AddTwin(context.Background(), token, twin, def)
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
repoCall.Unset()
|
||||
twin := twins.Twin{
|
||||
Owner: email,
|
||||
ID: testsutil.GenerateUUID(t),
|
||||
Name: twinName,
|
||||
Definitions: []twins.Definition{def},
|
||||
}
|
||||
|
||||
repoCall = auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: token}).Return(&magistrala.IdentityRes{Id: testsutil.GenerateUUID(t)}, nil)
|
||||
tw2, err := svc.AddTwin(context.Background(), token,
|
||||
twins.Twin{Owner: email},
|
||||
mocks.CreateDefinition(channels[2:3], subtopics[2:3]))
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
repoCall.Unset()
|
||||
|
||||
recs := make([]senml.Record, numRecs)
|
||||
mocks.CreateSenML(recs)
|
||||
message, err := mocks.CreateMessage(attr, recs)
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
repoCall = auth.On("Identify", mock.Anything, &magistrala.IdentityReq{Token: token}).Return(&magistrala.IdentityRes{Id: testsutil.GenerateUUID(t)}, nil)
|
||||
err = svc.SaveStates(context.Background(), message)
|
||||
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
||||
repoCall.Unset()
|
||||
tw2 := twins.Twin{
|
||||
Owner: email,
|
||||
Definitions: []twins.Definition{mocks.CreateDefinition(channels[2:3], subtopics[2:3])},
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
id string
|
||||
token string
|
||||
offset uint64
|
||||
limit uint64
|
||||
size int
|
||||
err error
|
||||
desc string
|
||||
id string
|
||||
token string
|
||||
offset uint64
|
||||
limit uint64
|
||||
size int
|
||||
err error
|
||||
page twins.StatesPage
|
||||
identifyErr error
|
||||
userID string
|
||||
}{
|
||||
{
|
||||
desc: "get a list of first 10 states",
|
||||
id: tw.ID,
|
||||
id: twin.ID,
|
||||
token: token,
|
||||
offset: 0,
|
||||
limit: 10,
|
||||
size: 10,
|
||||
err: nil,
|
||||
page: twins.StatesPage{
|
||||
States: genStates(10),
|
||||
},
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "get a list of last 10 states",
|
||||
id: tw.ID,
|
||||
id: twin.ID,
|
||||
token: token,
|
||||
offset: numRecs - 10,
|
||||
limit: numRecs,
|
||||
size: 10,
|
||||
err: nil,
|
||||
page: twins.StatesPage{
|
||||
States: genStates(10),
|
||||
},
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "get a list of last 10 states with limit > numRecs",
|
||||
id: tw.ID,
|
||||
id: twin.ID,
|
||||
token: token,
|
||||
offset: numRecs - 10,
|
||||
limit: numRecs + 10,
|
||||
size: 10,
|
||||
err: nil,
|
||||
page: twins.StatesPage{
|
||||
States: genStates(10),
|
||||
},
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "get a list of first 10 states with offset == numRecs",
|
||||
id: tw.ID,
|
||||
token: token,
|
||||
offset: numRecs,
|
||||
limit: numRecs + 10,
|
||||
size: 0,
|
||||
err: nil,
|
||||
desc: "get a list of first 10 states with offset == numRecs",
|
||||
id: twin.ID,
|
||||
token: token,
|
||||
offset: numRecs,
|
||||
limit: numRecs + 10,
|
||||
size: 0,
|
||||
err: nil,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "get a list with wrong user token",
|
||||
id: tw.ID,
|
||||
token: authmocks.InvalidValue,
|
||||
offset: 0,
|
||||
limit: 10,
|
||||
size: 0,
|
||||
err: svcerr.ErrAuthentication,
|
||||
desc: "get a list with wrong user token",
|
||||
id: twin.ID,
|
||||
token: authmocks.InvalidValue,
|
||||
offset: 0,
|
||||
limit: 10,
|
||||
size: 0,
|
||||
err: svcerr.ErrAuthentication,
|
||||
identifyErr: svcerr.ErrAuthentication,
|
||||
},
|
||||
{
|
||||
desc: "get a list with id of non-existent twin",
|
||||
id: "1234567890",
|
||||
token: token,
|
||||
offset: 0,
|
||||
limit: 10,
|
||||
size: 0,
|
||||
err: nil,
|
||||
desc: "get a list with id of non-existent twin",
|
||||
id: "1234567890",
|
||||
token: token,
|
||||
offset: 0,
|
||||
limit: 10,
|
||||
size: 0,
|
||||
err: nil,
|
||||
identifyErr: nil,
|
||||
userID: validID,
|
||||
},
|
||||
{
|
||||
desc: "get a list with id of existing twin without states ",
|
||||
id: tw2.ID,
|
||||
token: token,
|
||||
offset: 0,
|
||||
limit: 10,
|
||||
size: 0,
|
||||
err: nil,
|
||||
desc: "get a list with id of existing twin without states ",
|
||||
id: tw2.ID,
|
||||
token: token,
|
||||
offset: 0,
|
||||
limit: 10,
|
||||
size: 0,
|
||||
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: testsutil.GenerateUUID(t)}, nil)
|
||||
repoCall := auth.On("Identify", context.TODO(), &magistrala.IdentityReq{Token: tc.token}).Return(&magistrala.IdentityRes{Id: tc.userID}, tc.identifyErr)
|
||||
repoCall1 := stateRepo.On("RetrieveAll", context.TODO(), mock.Anything, mock.Anything, tc.id).Return(tc.page, nil)
|
||||
page, err := svc.ListStates(context.TODO(), tc.token, tc.offset, tc.limit, tc.id)
|
||||
assert.Equal(t, tc.err, err, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
assert.Equal(t, tc.size, len(page.States), fmt.Sprintf("%s: expected %d total got %d total\n", tc.desc, tc.size, len(page.States)))
|
||||
repoCall.Unset()
|
||||
repoCall1.Unset()
|
||||
}
|
||||
}
|
||||
|
||||
func genStates(length int) []twins.State {
|
||||
states := make([]twins.State, length)
|
||||
for i := range states {
|
||||
states[i] = twins.State{}
|
||||
}
|
||||
return states
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ type StatesPage struct {
|
||||
}
|
||||
|
||||
// StateRepository specifies a state persistence API.
|
||||
//
|
||||
//go:generate mockery --name StateRepository --output=./mocks --filename states.go --quiet --note "Copyright (c) Abstract Machines"
|
||||
type StateRepository interface {
|
||||
// Save persists the state
|
||||
Save(ctx context.Context, state State) error
|
||||
|
||||
@@ -55,6 +55,8 @@ type Page struct {
|
||||
}
|
||||
|
||||
// TwinRepository specifies a twin persistence API.
|
||||
//
|
||||
//go:generate mockery --name TwinRepository --output=./mocks --filename repository.go --quiet --note "Copyright (c) Abstract Machines"
|
||||
type TwinRepository interface {
|
||||
// Save persists the twin
|
||||
Save(ctx context.Context, twin Twin) (string, error)
|
||||
@@ -78,6 +80,8 @@ type TwinRepository interface {
|
||||
}
|
||||
|
||||
// TwinCache contains twin caching interface.
|
||||
//
|
||||
//go:generate mockery --name TwinCache --output=./mocks --filename cache.go --quiet --note "Copyright (c) Abstract Machines"
|
||||
type TwinCache interface {
|
||||
// Save stores twin ID as element of channel-subtopic keyed set and vice versa.
|
||||
Save(ctx context.Context, twin Twin) error
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.42.1. DO NOT EDIT.
|
||||
// Code generated by mockery v2.42.3. DO NOT EDIT.
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.42.1. DO NOT EDIT.
|
||||
// Code generated by mockery v2.42.3. DO NOT EDIT.
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.42.1. DO NOT EDIT.
|
||||
// Code generated by mockery v2.42.3. DO NOT EDIT.
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.42.1. DO NOT EDIT.
|
||||
// Code generated by mockery v2.42.3. DO NOT EDIT.
|
||||
|
||||
// Copyright (c) Abstract Machines
|
||||
|
||||
|
||||
Reference in New Issue
Block a user