Files
magistrala/channels/api/grpc/endpoint_test.go
T
Dušan Borovčanin 61d0427898 NOISSUE - Rename to Magistrala (#3427)
Signed-off-by: dusan <borovcanindusan1@gmail.com>
2026-04-06 15:23:42 +02:00

346 lines
10 KiB
Go

// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0
package grpc_test
import (
"context"
"fmt"
"net"
"testing"
"time"
grpcChannelsV1 "github.com/absmach/magistrala/api/grpc/channels/v1"
grpcCommonV1 "github.com/absmach/magistrala/api/grpc/common/v1"
apiutil "github.com/absmach/magistrala/api/http/util"
"github.com/absmach/magistrala/channels"
ch "github.com/absmach/magistrala/channels"
grpcapi "github.com/absmach/magistrala/channels/api/grpc"
"github.com/absmach/magistrala/channels/private/mocks"
"github.com/absmach/magistrala/internal/testsutil"
"github.com/absmach/magistrala/pkg/connections"
"github.com/absmach/magistrala/pkg/errors"
svcerr "github.com/absmach/magistrala/pkg/errors/service"
"github.com/absmach/magistrala/pkg/policies"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/credentials/insecure"
)
const port = 7005
var (
validID = testsutil.GenerateUUID(&testing.T{})
validChannel = ch.Channel{
ID: validID,
Domain: testsutil.GenerateUUID(&testing.T{}),
Status: channels.EnabledStatus,
}
)
func startGRPCServer(svc *mocks.Service, port int) *grpc.Server {
listener, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
if err != nil {
panic(fmt.Sprintf("failed to obtain port: %s", err))
}
server := grpc.NewServer()
grpcChannelsV1.RegisterChannelsServiceServer(server, grpcapi.NewServer(svc))
go func() {
if err := server.Serve(listener); err != nil {
panic(fmt.Sprintf("failed to serve: %s", err))
}
}()
return server
}
func TestAuthorize(t *testing.T) {
svc := new(mocks.Service)
server := startGRPCServer(svc, port)
defer server.GracefulStop()
authAddr := fmt.Sprintf("localhost:%d", port)
conn, _ := grpc.NewClient(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
client := grpcapi.NewClient(conn, time.Second)
cases := []struct {
desc string
domainID string
clientID string
clientType string
channelID string
connType connections.ConnType
err error
authzErr error
res *grpcChannelsV1.AuthzRes
code codes.Code
}{
{
desc: "authorize successfully",
domainID: validID,
clientID: validID,
clientType: policies.UserType,
channelID: validID,
connType: connections.Publish,
res: &grpcChannelsV1.AuthzRes{Authorized: true},
err: nil,
},
{
desc: "authorize with authorization error",
domainID: validID,
clientID: validID,
clientType: policies.UserType,
channelID: validID,
connType: connections.Publish,
res: &grpcChannelsV1.AuthzRes{Authorized: false},
authzErr: svcerr.ErrAuthorization,
err: svcerr.ErrAuthorization,
},
{
desc: "authorize withnot found error",
domainID: validID,
clientID: validID,
clientType: policies.UserType,
channelID: validID,
connType: connections.Publish,
res: &grpcChannelsV1.AuthzRes{Authorized: false},
authzErr: svcerr.ErrNotFound,
err: svcerr.ErrNotFound,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
authReq := ch.AuthzReq{
DomainID: tc.domainID,
ClientID: tc.clientID,
ClientType: tc.clientType,
ChannelID: tc.channelID,
Type: tc.connType,
}
svcCall := svc.On("Authorize", mock.Anything, authReq).Return(tc.authzErr)
res, err := client.Authorize(context.Background(), &grpcChannelsV1.AuthzReq{
DomainId: tc.domainID,
ClientId: tc.clientID,
ClientType: tc.clientType,
ChannelId: tc.channelID,
Type: uint32(tc.connType),
})
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s", tc.desc, tc.err, err))
assert.Equal(t, tc.res, res, fmt.Sprintf("%s: expected %s got %s", tc.desc, tc.res, res))
svcCall.Unset()
})
}
}
func TestRemoveClientConnections(t *testing.T) {
svc := new(mocks.Service)
server := startGRPCServer(svc, port)
defer server.GracefulStop()
authAddr := fmt.Sprintf("localhost:%d", port)
conn, _ := grpc.NewClient(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
client := grpcapi.NewClient(conn, time.Second)
cases := []struct {
desc string
clientID string
err error
code codes.Code
}{
{
desc: "remove client connections successfully",
clientID: validID,
err: nil,
},
{
desc: "remove client connections with error",
clientID: validID,
err: svcerr.ErrNotFound,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
svcCall := svc.On("RemoveClientConnections", mock.Anything, tc.clientID).Return(tc.err)
res, err := client.RemoveClientConnections(context.Background(), &grpcChannelsV1.RemoveClientConnectionsReq{
ClientId: tc.clientID,
})
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s", tc.desc, tc.err, err))
assert.Equal(t, &grpcChannelsV1.RemoveClientConnectionsRes{}, res)
svcCall.Unset()
})
}
}
func TestUnsetParentGroupFromChannelsEndpoint(t *testing.T) {
svc := new(mocks.Service)
server := startGRPCServer(svc, port)
defer server.GracefulStop()
authAddr := fmt.Sprintf("localhost:%d", port)
conn, _ := grpc.NewClient(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
client := grpcapi.NewClient(conn, time.Second)
cases := []struct {
desc string
parentGroupID string
err error
code codes.Code
}{
{
desc: "unset parent group from channels successfully",
parentGroupID: validID,
err: nil,
},
{
desc: "unset parent group from channels authorization error",
parentGroupID: validID,
err: svcerr.ErrAuthorization,
},
{
desc: "unset parent group from channels with not found error",
parentGroupID: validID,
err: svcerr.ErrNotFound,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
svcCall := svc.On("UnsetParentGroupFromChannels", mock.Anything, tc.parentGroupID).Return(tc.err)
res, err := client.UnsetParentGroupFromChannels(context.Background(), &grpcChannelsV1.UnsetParentGroupFromChannelsReq{
ParentGroupId: tc.parentGroupID,
})
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s", tc.desc, tc.err, err))
assert.Equal(t, &grpcChannelsV1.UnsetParentGroupFromChannelsRes{}, res)
svcCall.Unset()
})
}
}
func TestRetrieveEntity(t *testing.T) {
svc := new(mocks.Service)
server := startGRPCServer(svc, port)
defer server.GracefulStop()
authAddr := fmt.Sprintf("localhost:%d", port)
conn, _ := grpc.NewClient(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
client := grpcapi.NewClient(conn, time.Second)
cases := []struct {
desc string
id string
svcRes ch.Channel
resp *grpcCommonV1.RetrieveEntityRes
code codes.Code
err error
}{
{
desc: "retrieve entity successfully",
id: validID,
svcRes: validChannel,
resp: &grpcCommonV1.RetrieveEntityRes{
Entity: &grpcCommonV1.EntityBasic{
Id: validChannel.ID,
DomainId: validChannel.Domain,
ParentGroupId: validChannel.ParentGroup,
Status: uint32(validChannel.Status),
},
},
err: nil,
},
{
desc: "retrieve entity with error",
id: validID,
resp: &grpcCommonV1.RetrieveEntityRes{},
err: svcerr.ErrNotFound,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
svcCall := svc.On("RetrieveByID", mock.Anything, tc.id).Return(tc.svcRes, tc.err)
res, err := client.RetrieveEntity(context.Background(), &grpcCommonV1.RetrieveEntityReq{
Id: tc.id,
})
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s", tc.desc, tc.err, err))
assert.Equal(t, tc.resp.Entity, res.Entity)
svcCall.Unset()
})
}
}
func TestRetrieveIDByRoute(t *testing.T) {
svc := new(mocks.Service)
server := startGRPCServer(svc, port)
defer server.GracefulStop()
authAddr := fmt.Sprintf("localhost:%d", port)
conn, _ := grpc.NewClient(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
client := grpcapi.NewClient(conn, time.Second)
validRoute := "validRoute"
domainID := testsutil.GenerateUUID(t)
cases := []struct {
desc string
retrieveReq *grpcCommonV1.RetrieveIDByRouteReq
svcRes string
svcErr error
retrieveRes *grpcCommonV1.RetrieveEntityRes
err error
}{
{
desc: "retrieve entity by route successfully",
retrieveReq: &grpcCommonV1.RetrieveIDByRouteReq{
Route: validRoute,
DomainId: domainID,
},
svcRes: validID,
retrieveRes: &grpcCommonV1.RetrieveEntityRes{
Entity: &grpcCommonV1.EntityBasic{
Id: validID,
},
},
err: nil,
},
{
desc: "retrieve entity by route with empty route",
retrieveReq: &grpcCommonV1.RetrieveIDByRouteReq{
Route: "",
DomainId: domainID,
},
svcRes: "",
retrieveRes: &grpcCommonV1.RetrieveEntityRes{},
err: apiutil.ErrMissingRoute,
},
{
desc: "retrieve entity by route with empty domain ID",
retrieveReq: &grpcCommonV1.RetrieveIDByRouteReq{
Route: validRoute,
DomainId: "",
},
svcRes: "",
retrieveRes: &grpcCommonV1.RetrieveEntityRes{},
err: apiutil.ErrMissingDomainID,
},
{
desc: "retrieve entity by route with invalid route",
retrieveReq: &grpcCommonV1.RetrieveIDByRouteReq{
Route: "invalidRoute",
DomainId: domainID,
},
svcRes: "",
svcErr: svcerr.ErrNotFound,
retrieveRes: &grpcCommonV1.RetrieveEntityRes{},
err: svcerr.ErrNotFound,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
svcCall := svc.On("RetrieveIDByRoute", mock.Anything, tc.retrieveReq.Route, tc.retrieveReq.DomainId).Return(tc.svcRes, tc.svcErr)
res, err := client.RetrieveIDByRoute(context.Background(), tc.retrieveReq)
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s", tc.desc, tc.err, err))
assert.Equal(t, tc.retrieveRes.Entity, res.Entity)
svcCall.Unset()
})
}
}