mirror of
https://github.com/absmach/magistrala.git
synced 2026-06-23 04:10:28 +00:00
f8410b8940
Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
4132 lines
102 KiB
Go
4132 lines
102 KiB
Go
// Copyright (c) Abstract Machines
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package postgres_test
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/0x6flab/namegenerator"
|
|
"github.com/absmach/supermq/clients"
|
|
"github.com/absmach/supermq/clients/postgres"
|
|
"github.com/absmach/supermq/domains"
|
|
dpostgres "github.com/absmach/supermq/domains/postgres"
|
|
"github.com/absmach/supermq/groups"
|
|
gpostgres "github.com/absmach/supermq/groups/postgres"
|
|
"github.com/absmach/supermq/internal/testsutil"
|
|
"github.com/absmach/supermq/pkg/authn"
|
|
"github.com/absmach/supermq/pkg/connections"
|
|
"github.com/absmach/supermq/pkg/errors"
|
|
repoerr "github.com/absmach/supermq/pkg/errors/repository"
|
|
"github.com/absmach/supermq/pkg/roles"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
const (
|
|
maxNameSize = 1024
|
|
emailSuffix = "@example.com"
|
|
defOrder = "created_at"
|
|
ascDir = "asc"
|
|
descDir = "desc"
|
|
)
|
|
|
|
var (
|
|
invalidName = strings.Repeat("m", maxNameSize+10)
|
|
clientIdentity = "client-identity@example.com"
|
|
clientName = "client name"
|
|
invalidDomainID = strings.Repeat("m", maxNameSize+10)
|
|
namegen = namegenerator.NewGenerator()
|
|
validTimestamp = time.Now().UTC().Truncate(time.Millisecond)
|
|
validClient = clients.Client{
|
|
ID: testsutil.GenerateUUID(&testing.T{}),
|
|
Domain: testsutil.GenerateUUID(&testing.T{}),
|
|
Name: namegen.Generate(),
|
|
Metadata: map[string]any{"key": "value"},
|
|
PrivateMetadata: map[string]any{"key": "value"},
|
|
CreatedAt: time.Now().UTC().Truncate(time.Microsecond),
|
|
Status: clients.EnabledStatus,
|
|
}
|
|
invalidID = strings.Repeat("a", 37)
|
|
directAccess = "direct"
|
|
directGroupAccess = "direct_group"
|
|
domainAccess = "domain"
|
|
availableActions = []string{
|
|
"delete",
|
|
"membership",
|
|
"read",
|
|
"update",
|
|
}
|
|
domainAvailableActions = []string{
|
|
"client_add_role_users",
|
|
"client_connect_to_channel",
|
|
"client_create",
|
|
"client_delete",
|
|
"client_manage_role",
|
|
"client_read",
|
|
"client_remove_role_users",
|
|
"client_set_parent_group",
|
|
"client_update",
|
|
"client_view_role_users",
|
|
}
|
|
groupAvailableActions = []string{
|
|
"client_add_role_users",
|
|
"client_connect_to_channel",
|
|
"client_create",
|
|
"client_delete",
|
|
"client_manage_role",
|
|
"client_read",
|
|
"client_remove_role_users",
|
|
"client_set_parent_group",
|
|
"client_update",
|
|
"client_view_role_users",
|
|
"subgroup_client_add_role_users",
|
|
"subgroup_client_connect_to_channel",
|
|
"subgroup_client_create",
|
|
"subgroup_client_delete",
|
|
"subgroup_client_manage_role",
|
|
"subgroup_client_read",
|
|
"subgroup_client_remove_role_users",
|
|
"subgroup_client_set_parent_group",
|
|
"subgroup_client_update",
|
|
"subgroup_client_view_role_users",
|
|
"subgroup_manage_role",
|
|
"subgroup_membership",
|
|
"subgroup_read",
|
|
"subgroup_remove_role_users",
|
|
"subgroup_set_child",
|
|
"subgroup_set_parent",
|
|
"subgroup_update",
|
|
}
|
|
errClientSecretNotAvailable = errors.New("client key is not available")
|
|
)
|
|
|
|
func TestClientsSave(t *testing.T) {
|
|
t.Cleanup(func() {
|
|
_, err := db.Exec("DELETE FROM clients")
|
|
require.Nil(t, err, fmt.Sprintf("clean clients unexpected error: %s", err))
|
|
})
|
|
repo := postgres.NewRepository(database)
|
|
|
|
uid := testsutil.GenerateUUID(t)
|
|
domainID := testsutil.GenerateUUID(t)
|
|
secret := testsutil.GenerateUUID(t)
|
|
|
|
duplicateClientID := testsutil.GenerateUUID(t)
|
|
|
|
cases := []struct {
|
|
desc string
|
|
clients []clients.Client
|
|
err error
|
|
}{
|
|
{
|
|
desc: "add new client successfully",
|
|
clients: []clients.Client{
|
|
{
|
|
ID: uid,
|
|
Domain: domainID,
|
|
Name: clientName,
|
|
Credentials: clients.Credentials{
|
|
Identity: clientIdentity,
|
|
Secret: secret,
|
|
},
|
|
PrivateMetadata: map[string]any{"key": "value"},
|
|
Metadata: map[string]any{"key": "value"},
|
|
Status: clients.EnabledStatus,
|
|
},
|
|
},
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "add multiple clients successfully",
|
|
clients: []clients.Client{
|
|
{
|
|
ID: testsutil.GenerateUUID(t),
|
|
Domain: testsutil.GenerateUUID(t),
|
|
Name: namegen.Generate(),
|
|
Credentials: clients.Credentials{
|
|
Secret: testsutil.GenerateUUID(t),
|
|
},
|
|
PrivateMetadata: map[string]any{"key": "value"},
|
|
Metadata: map[string]any{"key": "value"},
|
|
Status: clients.EnabledStatus,
|
|
},
|
|
{
|
|
ID: testsutil.GenerateUUID(t),
|
|
Domain: testsutil.GenerateUUID(t),
|
|
Name: namegen.Generate(),
|
|
Credentials: clients.Credentials{
|
|
Secret: testsutil.GenerateUUID(t),
|
|
},
|
|
PrivateMetadata: map[string]any{"key": "value"},
|
|
Metadata: map[string]any{"key": "value"},
|
|
Status: clients.EnabledStatus,
|
|
},
|
|
{
|
|
ID: testsutil.GenerateUUID(t),
|
|
Domain: testsutil.GenerateUUID(t),
|
|
Name: namegen.Generate(),
|
|
Credentials: clients.Credentials{
|
|
Secret: testsutil.GenerateUUID(t),
|
|
},
|
|
PrivateMetadata: map[string]any{"key": "value"},
|
|
Metadata: map[string]any{"key": "value"},
|
|
Status: clients.EnabledStatus,
|
|
},
|
|
},
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "add new client with duplicate secret",
|
|
clients: []clients.Client{
|
|
{
|
|
ID: testsutil.GenerateUUID(t),
|
|
Domain: domainID,
|
|
Name: namegen.Generate(),
|
|
Credentials: clients.Credentials{
|
|
Identity: clientIdentity,
|
|
Secret: secret,
|
|
},
|
|
PrivateMetadata: map[string]any{"key": "value"},
|
|
Metadata: map[string]any{"key": "value"},
|
|
Status: clients.EnabledStatus,
|
|
},
|
|
},
|
|
err: errClientSecretNotAvailable,
|
|
},
|
|
{
|
|
desc: "add multiple clients with one client having duplicate secret",
|
|
clients: []clients.Client{
|
|
{
|
|
ID: testsutil.GenerateUUID(t),
|
|
Domain: testsutil.GenerateUUID(t),
|
|
Name: namegen.Generate(),
|
|
Credentials: clients.Credentials{
|
|
Secret: testsutil.GenerateUUID(t),
|
|
},
|
|
PrivateMetadata: map[string]any{"key": "value"},
|
|
Metadata: map[string]any{"key": "value"},
|
|
Status: clients.EnabledStatus,
|
|
},
|
|
{
|
|
ID: testsutil.GenerateUUID(t),
|
|
Domain: domainID,
|
|
Name: namegen.Generate(),
|
|
Credentials: clients.Credentials{
|
|
Identity: clientIdentity,
|
|
Secret: secret,
|
|
},
|
|
PrivateMetadata: map[string]any{"key": "value"},
|
|
Metadata: map[string]any{"key": "value"},
|
|
Status: clients.EnabledStatus,
|
|
},
|
|
},
|
|
err: errClientSecretNotAvailable,
|
|
},
|
|
{
|
|
desc: "add new client without domain id",
|
|
clients: []clients.Client{
|
|
{
|
|
ID: testsutil.GenerateUUID(t),
|
|
Name: clientName,
|
|
Credentials: clients.Credentials{
|
|
Identity: "withoutdomain-client@example.com",
|
|
Secret: testsutil.GenerateUUID(t),
|
|
},
|
|
PrivateMetadata: map[string]any{"key": "value"},
|
|
Metadata: map[string]any{"key": "value"},
|
|
Status: clients.EnabledStatus,
|
|
},
|
|
},
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "add client with invalid client id",
|
|
clients: []clients.Client{
|
|
{
|
|
ID: invalidName,
|
|
Domain: domainID,
|
|
Name: clientName,
|
|
Credentials: clients.Credentials{
|
|
Identity: "invalidid-client@example.com",
|
|
Secret: testsutil.GenerateUUID(t),
|
|
},
|
|
PrivateMetadata: map[string]any{"key": "value"},
|
|
Metadata: map[string]any{"key": "value"},
|
|
Status: clients.EnabledStatus,
|
|
},
|
|
},
|
|
err: repoerr.ErrCreateEntity,
|
|
},
|
|
{
|
|
desc: "add multiple clients with one client having invalid client id",
|
|
clients: []clients.Client{
|
|
{
|
|
ID: testsutil.GenerateUUID(t),
|
|
Domain: testsutil.GenerateUUID(t),
|
|
Name: namegen.Generate(),
|
|
Credentials: clients.Credentials{
|
|
Secret: testsutil.GenerateUUID(t),
|
|
},
|
|
PrivateMetadata: map[string]any{"key": "value"},
|
|
Metadata: map[string]any{"key": "value"},
|
|
Status: clients.EnabledStatus,
|
|
},
|
|
{
|
|
ID: invalidName,
|
|
Domain: testsutil.GenerateUUID(t),
|
|
Name: namegen.Generate(),
|
|
Credentials: clients.Credentials{
|
|
Secret: testsutil.GenerateUUID(t),
|
|
},
|
|
PrivateMetadata: map[string]any{"key": "value"},
|
|
Metadata: map[string]any{"key": "value"},
|
|
Status: clients.EnabledStatus,
|
|
},
|
|
},
|
|
err: repoerr.ErrCreateEntity,
|
|
},
|
|
{
|
|
desc: "add client with invalid client name",
|
|
clients: []clients.Client{
|
|
{
|
|
ID: testsutil.GenerateUUID(t),
|
|
Name: invalidName,
|
|
Domain: domainID,
|
|
Credentials: clients.Credentials{
|
|
Identity: "invalidname-client@example.com",
|
|
Secret: testsutil.GenerateUUID(t),
|
|
},
|
|
PrivateMetadata: map[string]any{"key": "value"},
|
|
Metadata: map[string]any{"key": "value"},
|
|
Status: clients.EnabledStatus,
|
|
},
|
|
},
|
|
err: repoerr.ErrCreateEntity,
|
|
},
|
|
{
|
|
desc: "add client with invalid client domain id",
|
|
clients: []clients.Client{
|
|
{
|
|
ID: testsutil.GenerateUUID(t),
|
|
Domain: invalidDomainID,
|
|
Credentials: clients.Credentials{
|
|
Identity: "invaliddomainid-client@example.com",
|
|
Secret: testsutil.GenerateUUID(t),
|
|
},
|
|
PrivateMetadata: map[string]any{"key": "value"},
|
|
Metadata: map[string]any{"key": "value"},
|
|
Status: clients.EnabledStatus,
|
|
},
|
|
},
|
|
err: repoerr.ErrCreateEntity,
|
|
},
|
|
{
|
|
desc: "add client with invalid client identity",
|
|
clients: []clients.Client{
|
|
{
|
|
ID: testsutil.GenerateUUID(t),
|
|
Name: clientName,
|
|
Credentials: clients.Credentials{
|
|
Identity: invalidName,
|
|
Secret: testsutil.GenerateUUID(t),
|
|
},
|
|
PrivateMetadata: map[string]any{"key": "value"},
|
|
Metadata: map[string]any{"key": "value"},
|
|
Status: clients.EnabledStatus,
|
|
},
|
|
},
|
|
err: repoerr.ErrCreateEntity,
|
|
},
|
|
{
|
|
desc: "add client with a missing client identity",
|
|
clients: []clients.Client{
|
|
{
|
|
ID: testsutil.GenerateUUID(t),
|
|
Domain: testsutil.GenerateUUID(t),
|
|
Name: "missing-client-identity",
|
|
Credentials: clients.Credentials{
|
|
Identity: "",
|
|
Secret: testsutil.GenerateUUID(t),
|
|
},
|
|
PrivateMetadata: map[string]any{"key": "value"},
|
|
Metadata: map[string]any{"key": "value"},
|
|
},
|
|
},
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "add client with a missing client secret",
|
|
clients: []clients.Client{
|
|
{
|
|
ID: testsutil.GenerateUUID(t),
|
|
Domain: testsutil.GenerateUUID(t),
|
|
Credentials: clients.Credentials{
|
|
Identity: "missing-client-secret@example.com",
|
|
Secret: "",
|
|
},
|
|
PrivateMetadata: map[string]any{"key": "value"},
|
|
Metadata: map[string]any{"key": "value"},
|
|
},
|
|
},
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "add a client with invalid private metadata",
|
|
clients: []clients.Client{
|
|
{
|
|
ID: testsutil.GenerateUUID(t),
|
|
Name: namegen.Generate(),
|
|
Credentials: clients.Credentials{
|
|
Identity: fmt.Sprintf("%s@example.com", namegen.Generate()),
|
|
Secret: testsutil.GenerateUUID(t),
|
|
},
|
|
PrivateMetadata: map[string]any{
|
|
"key": make(chan int),
|
|
},
|
|
},
|
|
},
|
|
err: errors.ErrMalformedEntity,
|
|
},
|
|
{
|
|
desc: "add a client with invalid metadata",
|
|
clients: []clients.Client{
|
|
{
|
|
ID: testsutil.GenerateUUID(t),
|
|
Name: namegen.Generate(),
|
|
Credentials: clients.Credentials{
|
|
Identity: fmt.Sprintf("%s@example.com", namegen.Generate()),
|
|
Secret: testsutil.GenerateUUID(t),
|
|
},
|
|
PrivateMetadata: map[string]any{
|
|
"key": make(chan int),
|
|
},
|
|
},
|
|
},
|
|
err: errors.ErrMalformedEntity,
|
|
},
|
|
{
|
|
desc: "add client with duplicate name",
|
|
clients: []clients.Client{
|
|
{
|
|
ID: duplicateClientID,
|
|
Domain: validClient.Domain,
|
|
Name: validClient.Name,
|
|
PrivateMetadata: map[string]any{"key": "different_value"},
|
|
Metadata: map[string]any{},
|
|
CreatedAt: validTimestamp,
|
|
Status: clients.EnabledStatus,
|
|
},
|
|
},
|
|
err: nil,
|
|
},
|
|
}
|
|
for _, tc := range cases {
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
rClients, err := repo.Save(context.Background(), tc.clients...)
|
|
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
|
if err == nil {
|
|
for i := range rClients {
|
|
tc.clients[i].Credentials.Secret = rClients[i].Credentials.Secret
|
|
}
|
|
assert.Equal(t, tc.clients, rClients, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.clients, rClients))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestClientsRetrieveBySecret(t *testing.T) {
|
|
t.Cleanup(func() {
|
|
_, err := db.Exec("DELETE FROM clients")
|
|
require.Nil(t, err, fmt.Sprintf("clean clients unexpected error: %s", err))
|
|
})
|
|
repo := postgres.NewRepository(database)
|
|
|
|
client := clients.Client{
|
|
ID: testsutil.GenerateUUID(t),
|
|
Name: clientName,
|
|
Credentials: clients.Credentials{
|
|
Identity: clientIdentity,
|
|
Secret: testsutil.GenerateUUID(t),
|
|
},
|
|
Domain: testsutil.GenerateUUID(t),
|
|
Metadata: clients.Metadata{},
|
|
PrivateMetadata: clients.Metadata{},
|
|
Status: clients.EnabledStatus,
|
|
}
|
|
|
|
_, err := repo.Save(context.Background(), client)
|
|
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
|
|
|
cases := []struct {
|
|
desc string
|
|
secret string
|
|
id string
|
|
response clients.Client
|
|
prefix authn.AuthPrefix
|
|
err error
|
|
}{
|
|
{
|
|
desc: "retrieve client by secret with no id",
|
|
secret: client.Credentials.Secret,
|
|
response: clients.Client{},
|
|
err: repoerr.ErrNotFound,
|
|
},
|
|
{
|
|
desc: "retrieve client by client ID and secret successfully",
|
|
secret: client.Credentials.Secret,
|
|
id: client.ID,
|
|
prefix: authn.BasicAuth,
|
|
response: client,
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "retrieve client by client ID invalid secret",
|
|
secret: "non-existent-secret",
|
|
response: clients.Client{},
|
|
err: repoerr.ErrNotFound,
|
|
},
|
|
{
|
|
desc: "retrieve client by empty secret",
|
|
secret: "",
|
|
response: clients.Client{},
|
|
err: repoerr.ErrNotFound,
|
|
},
|
|
{
|
|
desc: "retrieve client by client ID and secret with an invalid ID type",
|
|
secret: client.Credentials.Secret,
|
|
id: client.ID,
|
|
prefix: authn.DomainAuth,
|
|
response: clients.Client{},
|
|
err: repoerr.ErrNotFound,
|
|
},
|
|
{
|
|
desc: "retrieve client by domain ID and secret successfully",
|
|
secret: client.Credentials.Secret,
|
|
id: client.Domain,
|
|
prefix: authn.DomainAuth,
|
|
response: client,
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "retrieve client by domain ID and secret with an invalid ID type",
|
|
secret: client.Credentials.Secret,
|
|
id: client.Domain,
|
|
prefix: authn.BasicAuth,
|
|
response: clients.Client{},
|
|
err: repoerr.ErrNotFound,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
res, err := repo.RetrieveBySecret(context.Background(), tc.secret, tc.id, tc.prefix)
|
|
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
|
assert.Equal(t, res, tc.response, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.response, res))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRetrieveByID(t *testing.T) {
|
|
t.Cleanup(func() {
|
|
_, err := db.Exec("DELETE FROM clients")
|
|
require.Nil(t, err, fmt.Sprintf("clean clients unexpected error: %s", err))
|
|
})
|
|
repo := postgres.NewRepository(database)
|
|
|
|
client := clients.Client{
|
|
ID: testsutil.GenerateUUID(t),
|
|
Name: clientName,
|
|
Credentials: clients.Credentials{
|
|
Identity: clientIdentity,
|
|
Secret: testsutil.GenerateUUID(t),
|
|
},
|
|
PrivateMetadata: clients.Metadata{
|
|
"key": "value",
|
|
},
|
|
Metadata: clients.Metadata{
|
|
"key": "value",
|
|
},
|
|
Status: clients.EnabledStatus,
|
|
}
|
|
|
|
_, err := repo.Save(context.Background(), client)
|
|
require.Nil(t, err, fmt.Sprintf("unexpected error: %s", err))
|
|
|
|
cases := []struct {
|
|
desc string
|
|
id string
|
|
response clients.Client
|
|
err error
|
|
}{
|
|
{
|
|
desc: "successfully",
|
|
id: client.ID,
|
|
response: client,
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "with invalid id",
|
|
id: testsutil.GenerateUUID(t),
|
|
response: clients.Client{},
|
|
err: repoerr.ErrNotFound,
|
|
},
|
|
{
|
|
desc: "with empty id",
|
|
id: "",
|
|
response: clients.Client{},
|
|
err: repoerr.ErrNotFound,
|
|
},
|
|
}
|
|
for _, c := range cases {
|
|
t.Run(c.desc, func(t *testing.T) {
|
|
cli, err := repo.RetrieveByID(context.Background(), c.id)
|
|
assert.True(t, errors.Contains(err, c.err), fmt.Sprintf("expected %s got %s\n", c.err, err))
|
|
if err == nil {
|
|
assert.Equal(t, client.ID, cli.ID)
|
|
assert.Equal(t, client.Name, cli.Name)
|
|
assert.Equal(t, client.PrivateMetadata, cli.PrivateMetadata)
|
|
assert.Equal(t, client.Metadata, cli.Metadata)
|
|
assert.Equal(t, client.Credentials.Identity, cli.Credentials.Identity)
|
|
assert.Equal(t, client.Credentials.Secret, cli.Credentials.Secret)
|
|
assert.Equal(t, client.Status, cli.Status)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUpdate(t *testing.T) {
|
|
t.Cleanup(func() {
|
|
_, err := db.Exec("DELETE FROM clients")
|
|
require.Nil(t, err, fmt.Sprintf("clean clients unexpected error: %s", err))
|
|
})
|
|
|
|
repo := postgres.NewRepository(database)
|
|
|
|
_, err := repo.Save(context.Background(), validClient)
|
|
require.Nil(t, err, fmt.Sprintf("save client unexpected error: %s", err))
|
|
|
|
cases := []struct {
|
|
desc string
|
|
update string
|
|
client clients.Client
|
|
err error
|
|
}{
|
|
{
|
|
desc: "update client successfully",
|
|
update: "all",
|
|
client: clients.Client{
|
|
ID: validClient.ID,
|
|
Name: namegen.Generate(),
|
|
PrivateMetadata: map[string]any{"key": "value"},
|
|
Metadata: map[string]any{"key": "value"},
|
|
UpdatedAt: validTimestamp,
|
|
UpdatedBy: testsutil.GenerateUUID(t),
|
|
},
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "update client name",
|
|
update: "name",
|
|
client: clients.Client{
|
|
ID: validClient.ID,
|
|
Name: namegen.Generate(),
|
|
UpdatedAt: validTimestamp,
|
|
UpdatedBy: testsutil.GenerateUUID(t),
|
|
},
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "update client private metadata",
|
|
update: "private_metadata",
|
|
client: clients.Client{
|
|
ID: validClient.ID,
|
|
PrivateMetadata: map[string]any{"key1": "value1"},
|
|
UpdatedAt: validTimestamp,
|
|
UpdatedBy: testsutil.GenerateUUID(t),
|
|
},
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "update client metadata",
|
|
update: "metadata",
|
|
client: clients.Client{
|
|
ID: validClient.ID,
|
|
Metadata: map[string]any{"key1": "value1"},
|
|
UpdatedAt: validTimestamp,
|
|
UpdatedBy: testsutil.GenerateUUID(t),
|
|
},
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "update client with invalid ID",
|
|
update: "all",
|
|
client: clients.Client{
|
|
ID: testsutil.GenerateUUID(t),
|
|
Name: namegen.Generate(),
|
|
PrivateMetadata: map[string]any{"key": "value"},
|
|
Metadata: map[string]any{"key": "value"},
|
|
UpdatedAt: validTimestamp,
|
|
UpdatedBy: testsutil.GenerateUUID(t),
|
|
},
|
|
err: repoerr.ErrNotFound,
|
|
},
|
|
{
|
|
desc: "update client with empty ID",
|
|
update: "all",
|
|
client: clients.Client{
|
|
Name: namegen.Generate(),
|
|
PrivateMetadata: map[string]any{"key": "value"},
|
|
Metadata: map[string]any{"key": "value"},
|
|
UpdatedAt: validTimestamp,
|
|
UpdatedBy: testsutil.GenerateUUID(t),
|
|
},
|
|
err: repoerr.ErrNotFound,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
client, err := repo.Update(context.Background(), tc.client)
|
|
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
|
if err == nil {
|
|
assert.Equal(t, tc.client.ID, client.ID, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.client.ID, client.ID))
|
|
assert.Equal(t, tc.client.UpdatedAt, client.UpdatedAt, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.client.UpdatedAt, client.UpdatedAt))
|
|
assert.Equal(t, tc.client.UpdatedBy, client.UpdatedBy, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.client.UpdatedBy, client.UpdatedBy))
|
|
switch tc.update {
|
|
case "all":
|
|
assert.Equal(t, tc.client.Name, client.Name, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.client.Name, client.Name))
|
|
assert.Equal(t, tc.client.PrivateMetadata, client.PrivateMetadata, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.client.PrivateMetadata, client.PrivateMetadata))
|
|
assert.Equal(t, tc.client.Metadata, client.Metadata, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.client.Metadata, client.Metadata))
|
|
case "name":
|
|
assert.Equal(t, tc.client.Name, client.Name, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.client.Name, client.Name))
|
|
case "private_metadata":
|
|
assert.Equal(t, tc.client.PrivateMetadata, client.PrivateMetadata, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.client.PrivateMetadata, client.PrivateMetadata))
|
|
case "metadata":
|
|
assert.Equal(t, tc.client.Metadata, client.Metadata, fmt.Sprintf("%s: expected %v got %v\n", tc.desc, tc.client.Metadata, client.Metadata))
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUpdateTags(t *testing.T) {
|
|
t.Cleanup(func() {
|
|
_, err := db.Exec("DELETE FROM clients")
|
|
require.Nil(t, err, fmt.Sprintf("clean clients unexpected error: %s", err))
|
|
})
|
|
|
|
repo := postgres.NewRepository(database)
|
|
|
|
client1 := generateClient(t, clients.EnabledStatus, repo)
|
|
client2 := generateClient(t, clients.DisabledStatus, repo)
|
|
|
|
cases := []struct {
|
|
desc string
|
|
client clients.Client
|
|
err error
|
|
}{
|
|
{
|
|
desc: "for enabled client",
|
|
client: clients.Client{
|
|
ID: client1.ID,
|
|
Tags: namegen.GenerateMultiple(5),
|
|
},
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "for disabled client",
|
|
client: clients.Client{
|
|
ID: client2.ID,
|
|
Tags: namegen.GenerateMultiple(5),
|
|
},
|
|
err: repoerr.ErrNotFound,
|
|
},
|
|
{
|
|
desc: "for invalid client",
|
|
client: clients.Client{
|
|
ID: testsutil.GenerateUUID(t),
|
|
Tags: namegen.GenerateMultiple(5),
|
|
},
|
|
err: repoerr.ErrNotFound,
|
|
},
|
|
{
|
|
desc: "for empty client",
|
|
client: clients.Client{},
|
|
err: repoerr.ErrNotFound,
|
|
},
|
|
}
|
|
for _, c := range cases {
|
|
t.Run(c.desc, func(t *testing.T) {
|
|
c.client.UpdatedAt = time.Now().UTC().Truncate(time.Millisecond)
|
|
c.client.UpdatedBy = testsutil.GenerateUUID(t)
|
|
expected, err := repo.UpdateTags(context.Background(), c.client)
|
|
assert.True(t, errors.Contains(err, c.err), fmt.Sprintf("expected %s to contain %s\n", err, c.err))
|
|
if err == nil {
|
|
assert.Equal(t, c.client.Tags, expected.Tags)
|
|
assert.Equal(t, c.client.UpdatedAt, expected.UpdatedAt)
|
|
assert.Equal(t, c.client.UpdatedBy, expected.UpdatedBy)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUpdateIdentity(t *testing.T) {
|
|
t.Cleanup(func() {
|
|
_, err := db.Exec("DELETE FROM clients")
|
|
require.Nil(t, err, fmt.Sprintf("clean clients unexpected error: %s", err))
|
|
})
|
|
|
|
repo := postgres.NewRepository(database)
|
|
|
|
client1 := generateClient(t, clients.EnabledStatus, repo)
|
|
client2 := generateClient(t, clients.DisabledStatus, repo)
|
|
|
|
cases := []struct {
|
|
desc string
|
|
client clients.Client
|
|
err error
|
|
}{
|
|
{
|
|
desc: "for enabled client",
|
|
client: clients.Client{
|
|
ID: client1.ID,
|
|
Credentials: clients.Credentials{
|
|
Identity: namegen.Generate() + emailSuffix,
|
|
},
|
|
},
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "for disabled client",
|
|
client: clients.Client{
|
|
ID: client2.ID,
|
|
Credentials: clients.Credentials{
|
|
Identity: namegen.Generate() + emailSuffix,
|
|
},
|
|
},
|
|
err: repoerr.ErrNotFound,
|
|
},
|
|
{
|
|
desc: "for invalid client",
|
|
client: clients.Client{
|
|
ID: testsutil.GenerateUUID(t),
|
|
Credentials: clients.Credentials{
|
|
Identity: namegen.Generate() + emailSuffix,
|
|
},
|
|
},
|
|
err: repoerr.ErrNotFound,
|
|
},
|
|
{
|
|
desc: "for empty client",
|
|
client: clients.Client{},
|
|
err: repoerr.ErrNotFound,
|
|
},
|
|
}
|
|
for _, c := range cases {
|
|
t.Run(c.desc, func(t *testing.T) {
|
|
c.client.UpdatedAt = time.Now().UTC().Truncate(time.Millisecond)
|
|
c.client.UpdatedBy = testsutil.GenerateUUID(t)
|
|
expected, err := repo.UpdateIdentity(context.Background(), c.client)
|
|
assert.True(t, errors.Contains(err, c.err), fmt.Sprintf("expected %s to contain %s\n", err, c.err))
|
|
if err == nil {
|
|
assert.Equal(t, c.client.Credentials.Identity, expected.Credentials.Identity)
|
|
assert.Equal(t, c.client.UpdatedAt, expected.UpdatedAt)
|
|
assert.Equal(t, c.client.UpdatedBy, expected.UpdatedBy)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUpdateSecret(t *testing.T) {
|
|
t.Cleanup(func() {
|
|
_, err := db.Exec("DELETE FROM clients")
|
|
require.Nil(t, err, fmt.Sprintf("clean clients unexpected error: %s", err))
|
|
})
|
|
|
|
repo := postgres.NewRepository(database)
|
|
|
|
client1 := generateClient(t, clients.EnabledStatus, repo)
|
|
client2 := generateClient(t, clients.DisabledStatus, repo)
|
|
|
|
cases := []struct {
|
|
desc string
|
|
client clients.Client
|
|
err error
|
|
}{
|
|
{
|
|
desc: "for enabled client",
|
|
client: clients.Client{
|
|
ID: client1.ID,
|
|
Credentials: clients.Credentials{
|
|
Secret: "newpassword",
|
|
},
|
|
},
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "for disabled client",
|
|
client: clients.Client{
|
|
ID: client2.ID,
|
|
Credentials: clients.Credentials{
|
|
Secret: "newpassword",
|
|
},
|
|
},
|
|
err: repoerr.ErrNotFound,
|
|
},
|
|
{
|
|
desc: "for invalid client",
|
|
client: clients.Client{
|
|
ID: testsutil.GenerateUUID(t),
|
|
Credentials: clients.Credentials{
|
|
Secret: "newpassword",
|
|
},
|
|
},
|
|
err: repoerr.ErrNotFound,
|
|
},
|
|
{
|
|
desc: "for empty client",
|
|
client: clients.Client{},
|
|
err: repoerr.ErrNotFound,
|
|
},
|
|
}
|
|
for _, c := range cases {
|
|
t.Run(c.desc, func(t *testing.T) {
|
|
c.client.UpdatedAt = time.Now().UTC().Truncate(time.Millisecond)
|
|
c.client.UpdatedBy = testsutil.GenerateUUID(t)
|
|
_, err := repo.UpdateSecret(context.Background(), c.client)
|
|
assert.True(t, errors.Contains(err, c.err), fmt.Sprintf("expected %s to contain %s\n", err, c.err))
|
|
if err == nil {
|
|
rc, err := repo.RetrieveByID(context.Background(), c.client.ID)
|
|
require.Nil(t, err, fmt.Sprintf("retrieve client by id during update of secret unexpected error: %s", err))
|
|
assert.Equal(t, c.client.Credentials.Secret, rc.Credentials.Secret)
|
|
assert.Equal(t, c.client.UpdatedAt, rc.UpdatedAt)
|
|
assert.Equal(t, c.client.UpdatedBy, rc.UpdatedBy)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestChangeStatus(t *testing.T) {
|
|
t.Cleanup(func() {
|
|
_, err := db.Exec("DELETE FROM clients")
|
|
require.Nil(t, err, fmt.Sprintf("clean clients unexpected error: %s", err))
|
|
})
|
|
|
|
repo := postgres.NewRepository(database)
|
|
|
|
client1 := generateClient(t, clients.EnabledStatus, repo)
|
|
client2 := generateClient(t, clients.DisabledStatus, repo)
|
|
|
|
cases := []struct {
|
|
desc string
|
|
client clients.Client
|
|
err error
|
|
}{
|
|
{
|
|
desc: "for an enabled client",
|
|
client: clients.Client{
|
|
ID: client1.ID,
|
|
Status: clients.DisabledStatus,
|
|
},
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "for a disabled client",
|
|
client: clients.Client{
|
|
ID: client2.ID,
|
|
Status: clients.EnabledStatus,
|
|
},
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "for invalid client",
|
|
client: clients.Client{
|
|
ID: testsutil.GenerateUUID(t),
|
|
Status: clients.DisabledStatus,
|
|
},
|
|
err: repoerr.ErrNotFound,
|
|
},
|
|
{
|
|
desc: "for empty client",
|
|
client: clients.Client{},
|
|
err: repoerr.ErrNotFound,
|
|
},
|
|
}
|
|
|
|
for _, c := range cases {
|
|
t.Run(c.desc, func(t *testing.T) {
|
|
c.client.UpdatedAt = time.Now().UTC().Truncate(time.Millisecond)
|
|
c.client.UpdatedBy = testsutil.GenerateUUID(t)
|
|
expected, err := repo.ChangeStatus(context.Background(), c.client)
|
|
assert.True(t, errors.Contains(err, c.err), fmt.Sprintf("expected %s to contain %s\n", err, c.err))
|
|
if err == nil {
|
|
assert.Equal(t, c.client.Status, expected.Status)
|
|
assert.Equal(t, c.client.UpdatedAt, expected.UpdatedAt)
|
|
assert.Equal(t, c.client.UpdatedBy, expected.UpdatedBy)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRetrieveByIDsWithRoles(t *testing.T) {
|
|
t.Cleanup(func() {
|
|
_, err := db.Exec("DELETE FROM clients")
|
|
require.Nil(t, err, fmt.Sprintf("clean clients unexpected error: %s", err))
|
|
})
|
|
|
|
repo := postgres.NewRepository(database)
|
|
|
|
nClients := uint64(10)
|
|
|
|
domainID := testsutil.GenerateUUID(t)
|
|
userID := testsutil.GenerateUUID(t)
|
|
expectedClients := []clients.Client{}
|
|
for range nClients {
|
|
client := clients.Client{
|
|
ID: testsutil.GenerateUUID(t),
|
|
Domain: domainID,
|
|
Name: namegen.Generate(),
|
|
Credentials: clients.Credentials{
|
|
Identity: namegen.Generate() + emailSuffix,
|
|
Secret: testsutil.GenerateUUID(t),
|
|
},
|
|
Tags: namegen.GenerateMultiple(5),
|
|
Metadata: clients.Metadata{
|
|
"department": namegen.Generate(),
|
|
},
|
|
Status: clients.EnabledStatus,
|
|
CreatedAt: time.Now().UTC().Truncate(time.Microsecond),
|
|
}
|
|
_, err := repo.Save(context.Background(), client)
|
|
require.Nil(t, err, fmt.Sprintf("add new client: expected nil got %s\n", err))
|
|
newRolesProvision := []roles.RoleProvision{
|
|
{
|
|
Role: roles.Role{
|
|
ID: testsutil.GenerateUUID(t) + "_" + client.ID,
|
|
Name: "admin",
|
|
EntityID: client.ID,
|
|
CreatedAt: validTimestamp,
|
|
CreatedBy: userID,
|
|
},
|
|
OptionalActions: availableActions,
|
|
OptionalMembers: []string{userID},
|
|
},
|
|
}
|
|
npr, err := repo.AddRoles(context.Background(), newRolesProvision)
|
|
require.Nil(t, err, fmt.Sprintf("add roles unexpected error: %s", err))
|
|
expectedClient := client
|
|
expectedClient.Roles = []roles.MemberRoleActions{
|
|
{
|
|
RoleID: npr[0].Role.ID,
|
|
RoleName: npr[0].Role.Name,
|
|
Actions: npr[0].OptionalActions,
|
|
AccessType: directAccess,
|
|
},
|
|
}
|
|
expectedClients = append(expectedClients, expectedClient)
|
|
}
|
|
|
|
cases := []struct {
|
|
desc string
|
|
clientID string
|
|
userID string
|
|
response clients.Client
|
|
err error
|
|
}{
|
|
{
|
|
desc: "retrieve client with role successfully",
|
|
clientID: expectedClients[0].ID,
|
|
userID: userID,
|
|
response: expectedClients[0],
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "retrieve another client with role successfully",
|
|
clientID: expectedClients[1].ID,
|
|
userID: userID,
|
|
response: expectedClients[1],
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "retrieve client with invalid client id",
|
|
clientID: testsutil.GenerateUUID(t),
|
|
userID: userID,
|
|
response: clients.Client{},
|
|
err: repoerr.ErrNotFound,
|
|
},
|
|
{
|
|
desc: "retrieve client with empty client id",
|
|
clientID: "",
|
|
userID: userID,
|
|
response: clients.Client{},
|
|
err: repoerr.ErrNotFound,
|
|
},
|
|
{
|
|
desc: "retrieve client with invalid user id",
|
|
clientID: expectedClients[0].ID,
|
|
userID: testsutil.GenerateUUID(t),
|
|
response: clients.Client{},
|
|
err: repoerr.ErrNotFound,
|
|
},
|
|
{
|
|
desc: "retrieve client with empty user id",
|
|
clientID: expectedClients[0].ID,
|
|
userID: "",
|
|
response: clients.Client{},
|
|
err: repoerr.ErrNotFound,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
client, err := repo.RetrieveByIDWithRoles(context.Background(), tc.clientID, tc.userID)
|
|
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("expected %s to contain %s\n", err, tc.err))
|
|
if err == nil {
|
|
assert.Equal(t, tc.response, client, fmt.Sprintf("expected %v got %v\n", tc.response, client))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRetrieveAll(t *testing.T) {
|
|
t.Cleanup(func() {
|
|
_, err := db.Exec("DELETE FROM clients")
|
|
require.Nil(t, err, fmt.Sprintf("clean clients unexpected error: %s", err))
|
|
})
|
|
|
|
repo := postgres.NewRepository(database)
|
|
|
|
nClients := uint64(200)
|
|
connectedClient := clients.Client{}
|
|
|
|
channelID := testsutil.GenerateUUID(t)
|
|
expectedClients := []clients.Client{}
|
|
disabledClients := []clients.Client{}
|
|
reversedClients := []clients.Client{}
|
|
baseTime := time.Now().UTC().Truncate(time.Millisecond)
|
|
for i := uint64(0); i < nClients; i++ {
|
|
client := clients.Client{
|
|
ID: testsutil.GenerateUUID(t),
|
|
Domain: testsutil.GenerateUUID(t),
|
|
Name: namegen.Generate(),
|
|
Credentials: clients.Credentials{
|
|
Identity: namegen.Generate() + emailSuffix,
|
|
Secret: testsutil.GenerateUUID(t),
|
|
},
|
|
Tags: []string{"tag1", "tag2"},
|
|
Metadata: clients.Metadata{
|
|
"department": namegen.Generate(),
|
|
},
|
|
Status: clients.EnabledStatus,
|
|
CreatedAt: baseTime.Add(time.Duration(i) * time.Millisecond),
|
|
UpdatedAt: baseTime.Add(time.Duration(i) * time.Millisecond),
|
|
}
|
|
if i%50 == 0 {
|
|
client.Status = clients.DisabledStatus
|
|
}
|
|
if i%99 == 0 {
|
|
client.Tags = []string{"tag1", "tag3"}
|
|
}
|
|
_, err := repo.Save(context.Background(), client)
|
|
if i == 0 {
|
|
conn := clients.Connection{
|
|
ClientID: client.ID,
|
|
ChannelID: channelID,
|
|
DomainID: client.Domain,
|
|
Type: connections.Publish,
|
|
}
|
|
err = repo.AddConnections(context.Background(), []clients.Connection{conn})
|
|
assert.Nil(t, err, fmt.Sprintf("add connection unexpected error: %s", err))
|
|
connectedClient = client
|
|
connectedClient.ConnectionTypes = []connections.ConnType{connections.Publish}
|
|
}
|
|
require.Nil(t, err, fmt.Sprintf("add new client: expected nil got %s\n", err))
|
|
expectedClients = append(expectedClients, client)
|
|
if client.Status == clients.DisabledStatus {
|
|
disabledClients = append(disabledClients, client)
|
|
}
|
|
}
|
|
|
|
for i := len(expectedClients) - 1; i >= 0; i-- {
|
|
reversedClients = append(reversedClients, expectedClients[i])
|
|
}
|
|
|
|
cases := []struct {
|
|
desc string
|
|
pm clients.Page
|
|
response clients.ClientsPage
|
|
err error
|
|
}{
|
|
{
|
|
desc: "with empty page",
|
|
pm: clients.Page{},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 196,
|
|
Offset: 0,
|
|
Limit: 0,
|
|
},
|
|
Clients: []clients.Client(nil),
|
|
},
|
|
},
|
|
{
|
|
desc: "with offset only",
|
|
pm: clients.Page{
|
|
Offset: 50,
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: nClients,
|
|
Offset: 50,
|
|
Limit: 0,
|
|
},
|
|
Clients: []clients.Client(nil),
|
|
},
|
|
},
|
|
{
|
|
desc: "with limit only",
|
|
pm: clients.Page{
|
|
Limit: 10,
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: nClients,
|
|
Offset: 0,
|
|
Limit: 10,
|
|
},
|
|
Clients: expectedClients[:10],
|
|
},
|
|
},
|
|
{
|
|
desc: "retrieve all clients",
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: nClients,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: expectedClients,
|
|
},
|
|
},
|
|
{
|
|
desc: "with offset and limit",
|
|
pm: clients.Page{
|
|
Offset: 50,
|
|
Limit: 50,
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: nClients,
|
|
Offset: 50,
|
|
Limit: 50,
|
|
},
|
|
Clients: expectedClients[50:100],
|
|
},
|
|
},
|
|
{
|
|
desc: "with offset out of range and limit",
|
|
pm: clients.Page{
|
|
Offset: 1000,
|
|
Limit: 50,
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: nClients,
|
|
Offset: 1000,
|
|
Limit: 50,
|
|
},
|
|
Clients: []clients.Client(nil),
|
|
},
|
|
},
|
|
{
|
|
desc: "with offset and limit out of range",
|
|
pm: clients.Page{
|
|
Offset: 170,
|
|
Limit: 50,
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: nClients,
|
|
Offset: 170,
|
|
Limit: 50,
|
|
},
|
|
Clients: expectedClients[170:200],
|
|
},
|
|
},
|
|
{
|
|
desc: "with metadata",
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
Metadata: expectedClients[0].Metadata,
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 1,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: []clients.Client{expectedClients[0]},
|
|
},
|
|
},
|
|
{
|
|
desc: "with wrong metadata",
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
Metadata: clients.Metadata{
|
|
"faculty": namegen.Generate(),
|
|
},
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 0,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: []clients.Client(nil),
|
|
},
|
|
},
|
|
{
|
|
desc: "with invalid metadata",
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
Metadata: clients.Metadata{
|
|
"faculty": make(chan int),
|
|
},
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: uint64(nClients),
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: []clients.Client(nil),
|
|
},
|
|
err: repoerr.ErrViewEntity,
|
|
},
|
|
{
|
|
desc: "with name",
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
Name: expectedClients[0].Name,
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 1,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: []clients.Client{expectedClients[0]},
|
|
},
|
|
},
|
|
{
|
|
desc: "with wrong name",
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
Name: namegen.Generate(),
|
|
Status: clients.AllStatus,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 0,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: []clients.Client(nil),
|
|
},
|
|
},
|
|
{
|
|
desc: "with identity",
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
Identity: expectedClients[0].Credentials.Identity,
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 1,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: []clients.Client{expectedClients[0]},
|
|
},
|
|
},
|
|
{
|
|
desc: "with wrong identity",
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
Identity: namegen.Generate(),
|
|
Status: clients.AllStatus,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 0,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: []clients.Client(nil),
|
|
},
|
|
},
|
|
{
|
|
desc: "with domain",
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
Domain: expectedClients[0].Domain,
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 1,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: []clients.Client{expectedClients[0]},
|
|
},
|
|
},
|
|
{
|
|
desc: "with wrong domain",
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
Domain: testsutil.GenerateUUID(t),
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 0,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: []clients.Client(nil),
|
|
},
|
|
},
|
|
{
|
|
desc: "with enabled status",
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: 10,
|
|
Status: clients.EnabledStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 196,
|
|
Offset: 0,
|
|
Limit: 10,
|
|
},
|
|
Clients: expectedClients[1:11],
|
|
},
|
|
},
|
|
{
|
|
desc: "with disabled status",
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
Status: clients.DisabledStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 4,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: disabledClients,
|
|
},
|
|
},
|
|
{
|
|
desc: "with combined status",
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: nClients,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: expectedClients,
|
|
},
|
|
},
|
|
{
|
|
desc: "with the wrong status",
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
Status: 10,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 0,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: []clients.Client(nil),
|
|
},
|
|
},
|
|
{
|
|
desc: "with single tag",
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
Tags: clients.TagsQuery{Elements: []string{"tag1"}, Operator: clients.OrOp},
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 200,
|
|
Offset: 0,
|
|
Limit: uint64(nClients),
|
|
},
|
|
Clients: expectedClients,
|
|
},
|
|
},
|
|
{
|
|
desc: "with multiple tags and OR operator",
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
Tags: clients.TagsQuery{Elements: []string{"tag2", "tag3"}, Operator: clients.OrOp},
|
|
Status: clients.AllStatus,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 200,
|
|
Offset: 0,
|
|
Limit: uint64(nClients),
|
|
},
|
|
Clients: expectedClients,
|
|
},
|
|
},
|
|
{
|
|
desc: "with multiple tags and AND operator",
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
Tags: clients.TagsQuery{Elements: []string{"tag1", "tag3"}, Operator: clients.AndOp},
|
|
Status: clients.AllStatus,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 3,
|
|
Offset: 0,
|
|
Limit: uint64(nClients),
|
|
},
|
|
Clients: []clients.Client{expectedClients[0], expectedClients[99], expectedClients[198]},
|
|
},
|
|
},
|
|
{
|
|
desc: "with wrong tags",
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
Tags: clients.TagsQuery{Elements: []string{namegen.Generate(), namegen.Generate()}, Operator: clients.OrOp},
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 0,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: []clients.Client(nil),
|
|
},
|
|
},
|
|
{
|
|
desc: "with multiple parameters",
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
Metadata: expectedClients[0].Metadata,
|
|
Name: expectedClients[0].Name,
|
|
Tags: clients.TagsQuery{Elements: []string{expectedClients[0].Tags[0]}, Operator: clients.OrOp},
|
|
Identity: expectedClients[0].Credentials.Identity,
|
|
Domain: expectedClients[0].Domain,
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 1,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: []clients.Client{expectedClients[0]},
|
|
},
|
|
},
|
|
{
|
|
desc: "with id",
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
ID: expectedClients[0].ID,
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 1,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: []clients.Client{expectedClients[0]},
|
|
},
|
|
},
|
|
{
|
|
desc: "with wrong id",
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
ID: testsutil.GenerateUUID(t),
|
|
Status: clients.AllStatus,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 0,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: []clients.Client(nil),
|
|
},
|
|
},
|
|
{
|
|
desc: "with channel id",
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
Channel: channelID,
|
|
Status: clients.AllStatus,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 1,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: []clients.Client{connectedClient},
|
|
},
|
|
},
|
|
{
|
|
desc: "with order by name ascending",
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: 10,
|
|
Order: "name",
|
|
Dir: ascDir,
|
|
Status: clients.AllStatus,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: nClients,
|
|
Offset: 0,
|
|
Limit: 10,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "with order by name descending",
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: 10,
|
|
Order: "name",
|
|
Dir: descDir,
|
|
Status: clients.AllStatus,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: nClients,
|
|
Offset: 0,
|
|
Limit: 10,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "with order by identity ascending",
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: 10,
|
|
Order: "identity",
|
|
Dir: ascDir,
|
|
Status: clients.AllStatus,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: nClients,
|
|
Offset: 0,
|
|
Limit: 10,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "with order by identity descending",
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: 10,
|
|
Order: "identity",
|
|
Dir: descDir,
|
|
Status: clients.AllStatus,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: nClients,
|
|
Offset: 0,
|
|
Limit: 10,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "with order by created_at ascending",
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: 10,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
Status: clients.AllStatus,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: nClients,
|
|
Offset: 0,
|
|
Limit: 10,
|
|
},
|
|
Clients: expectedClients[:10],
|
|
},
|
|
},
|
|
{
|
|
desc: "with order by created_at descending",
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: 10,
|
|
Order: defOrder,
|
|
Dir: descDir,
|
|
Status: clients.AllStatus,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: nClients,
|
|
Offset: 0,
|
|
Limit: 10,
|
|
},
|
|
Clients: reversedClients[:10],
|
|
},
|
|
},
|
|
{
|
|
desc: "with order by updated_at ascending",
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: 10,
|
|
Order: "updated_at",
|
|
Dir: ascDir,
|
|
Status: clients.AllStatus,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: nClients,
|
|
Offset: 0,
|
|
Limit: 10,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "with order by updated_at descending",
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: 10,
|
|
Order: "updated_at",
|
|
Dir: descDir,
|
|
Status: clients.AllStatus,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: nClients,
|
|
Offset: 0,
|
|
Limit: 10,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "with created_from",
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
Status: clients.AllStatus,
|
|
CreatedFrom: baseTime.Add(100 * time.Millisecond),
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 100,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: expectedClients[100:],
|
|
},
|
|
},
|
|
{
|
|
desc: "with created_to",
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
Status: clients.AllStatus,
|
|
CreatedTo: baseTime.Add(99 * time.Millisecond),
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 100,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: expectedClients[:100],
|
|
},
|
|
},
|
|
{
|
|
desc: "with both created_from and created_to",
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
Status: clients.AllStatus,
|
|
CreatedFrom: baseTime.Add(50 * time.Millisecond),
|
|
CreatedTo: baseTime.Add(149 * time.Millisecond),
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 100,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: expectedClients[50:150],
|
|
},
|
|
},
|
|
{
|
|
desc: "with created_from returning no results",
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
Status: clients.AllStatus,
|
|
CreatedFrom: baseTime.Add(500 * time.Millisecond),
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 0,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: []clients.Client(nil),
|
|
},
|
|
},
|
|
{
|
|
desc: "with created_to returning no results",
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
Status: clients.AllStatus,
|
|
CreatedTo: baseTime.Add(-10 * time.Millisecond),
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 0,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: []clients.Client(nil),
|
|
},
|
|
},
|
|
}
|
|
for _, c := range cases {
|
|
t.Run(c.desc, func(t *testing.T) {
|
|
page, err := repo.RetrieveAll(context.Background(), c.pm)
|
|
assert.True(t, errors.Contains(err, c.err), fmt.Sprintf("expected %s to contain %s\n", err, c.err))
|
|
if err == nil {
|
|
assert.Equal(t, c.response.Total, page.Total)
|
|
assert.Equal(t, c.response.Offset, page.Offset)
|
|
assert.Equal(t, c.response.Limit, page.Limit)
|
|
if len(c.response.Clients) > 0 {
|
|
expected := stripClientDetails(c.response.Clients)
|
|
got := stripClientDetails(page.Clients)
|
|
assert.ElementsMatch(t, expected, got, fmt.Sprintf("expected %v got %v\n", expected, got))
|
|
}
|
|
verifyClientsOrdering(t, page.Clients, c.pm.Order, c.pm.Dir)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRetrieveUserClients(t *testing.T) {
|
|
t.Cleanup(func() {
|
|
_, err := db.Exec("DELETE FROM clients")
|
|
require.Nil(t, err, fmt.Sprintf("clean clients unexpected error: %s", err))
|
|
_, err = db.Exec("DELETE FROM groups")
|
|
require.Nil(t, err, fmt.Sprintf("clean groups unexpected error: %s", err))
|
|
_, err = db.Exec("DELETE FROM domains")
|
|
require.Nil(t, err, fmt.Sprintf("clean clients unexpected error: %s", err))
|
|
})
|
|
|
|
repo := postgres.NewRepository(database)
|
|
|
|
nClients := uint64(10)
|
|
|
|
emptyGroupParam := ""
|
|
userID := testsutil.GenerateUUID(t)
|
|
domainMemberID := testsutil.GenerateUUID(t)
|
|
groupMemberID := testsutil.GenerateUUID(t)
|
|
channelID := testsutil.GenerateUUID(t)
|
|
domain := generateDomain(t, userID, domainMemberID)
|
|
group := generateGroup(t, userID, groupMemberID, domain.ID)
|
|
groupClient := clients.Client{}
|
|
parentGroupClient := clients.Client{}
|
|
connectedClient := clients.Client{}
|
|
directClients := []clients.Client{}
|
|
domainClients := []clients.Client{}
|
|
baseTime := time.Now().UTC().Truncate(time.Microsecond)
|
|
for i := range nClients {
|
|
client := clients.Client{
|
|
ID: testsutil.GenerateUUID(t),
|
|
Domain: domain.ID,
|
|
Name: namegen.Generate(),
|
|
Credentials: clients.Credentials{
|
|
Identity: namegen.Generate() + emailSuffix,
|
|
Secret: testsutil.GenerateUUID(t),
|
|
},
|
|
Tags: namegen.GenerateMultiple(5),
|
|
Metadata: clients.Metadata{
|
|
"department": namegen.Generate(),
|
|
},
|
|
Status: clients.EnabledStatus,
|
|
CreatedAt: baseTime.Add(time.Duration(i) * time.Microsecond),
|
|
UpdatedAt: baseTime.Add(time.Duration(i) * time.Microsecond),
|
|
}
|
|
if i == 1 {
|
|
client.ParentGroup = group.ID
|
|
}
|
|
_, err := repo.Save(context.Background(), client)
|
|
require.Nil(t, err, fmt.Sprintf("add new client: expected nil got %s\n", err))
|
|
newRolesProvision := []roles.RoleProvision{
|
|
{
|
|
Role: roles.Role{
|
|
ID: testsutil.GenerateUUID(t) + "_" + client.ID,
|
|
Name: "admin",
|
|
EntityID: client.ID,
|
|
CreatedAt: validTimestamp,
|
|
CreatedBy: userID,
|
|
},
|
|
OptionalActions: availableActions,
|
|
OptionalMembers: []string{userID},
|
|
},
|
|
}
|
|
npr, err := repo.AddRoles(context.Background(), newRolesProvision)
|
|
require.Nil(t, err, fmt.Sprintf("add roles unexpected error: %s", err))
|
|
directClient := client
|
|
directClient.RoleID = npr[0].Role.ID
|
|
directClient.RoleName = npr[0].Role.Name
|
|
directClient.AccessType = directAccess
|
|
directClient.AccessProviderRoleActions = []string{}
|
|
if i == 1 {
|
|
directClient.ParentGroupPath = group.ID
|
|
}
|
|
directClients = append(directClients, directClient)
|
|
if i == 1 {
|
|
parentGroupClient = directClient
|
|
parentGroupClient.ParentGroupPath = group.ID
|
|
client.ParentGroupPath = group.ID
|
|
groupClient = client
|
|
groupClient.AccessType = directGroupAccess
|
|
groupClient.AccessProviderId = group.ID
|
|
groupClient.AccessProviderRoleId = group.Roles[0].RoleID
|
|
groupClient.AccessProviderRoleName = group.Roles[0].RoleName
|
|
groupClient.AccessProviderRoleActions = groupAvailableActions
|
|
}
|
|
if i == 2 {
|
|
conn := clients.Connection{
|
|
ClientID: client.ID,
|
|
ChannelID: channelID,
|
|
DomainID: client.Domain,
|
|
Type: connections.Publish,
|
|
}
|
|
err = repo.AddConnections(context.Background(), []clients.Connection{conn})
|
|
assert.Nil(t, err, fmt.Sprintf("add connection unexpected error: %s", err))
|
|
connectedClient = client
|
|
connectedClient.RoleID = npr[0].Role.ID
|
|
connectedClient.RoleName = npr[0].Role.Name
|
|
connectedClient.AccessType = directAccess
|
|
connectedClient.AccessProviderRoleActions = []string{}
|
|
connectedClient.ConnectionTypes = []connections.ConnType{connections.Publish}
|
|
}
|
|
domainClient := client
|
|
domainClient.AccessType = domainAccess
|
|
domainClient.AccessProviderId = domain.ID
|
|
domainClient.AccessProviderRoleId = domain.Roles[0].RoleID
|
|
domainClient.AccessProviderRoleName = domain.Roles[0].RoleName
|
|
domainClient.AccessProviderRoleActions = domainAvailableActions
|
|
domainClients = append(domainClients, domainClient)
|
|
}
|
|
|
|
reversedDirectClients := []clients.Client{}
|
|
for i := len(directClients) - 1; i >= 0; i-- {
|
|
reversedDirectClients = append(reversedDirectClients, directClients[i])
|
|
}
|
|
|
|
cases := []struct {
|
|
desc string
|
|
domainID string
|
|
userID string
|
|
pm clients.Page
|
|
response clients.ClientsPage
|
|
err error
|
|
}{
|
|
{
|
|
desc: "retrieve clients with empty page",
|
|
domainID: domain.ID,
|
|
userID: userID,
|
|
pm: clients.Page{},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 10,
|
|
Offset: 0,
|
|
Limit: 0,
|
|
},
|
|
Clients: []clients.Client(nil),
|
|
},
|
|
},
|
|
{
|
|
desc: "retrieve clients with offset and limit",
|
|
domainID: domain.ID,
|
|
userID: userID,
|
|
pm: clients.Page{
|
|
Offset: 5,
|
|
Limit: 10,
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: nClients,
|
|
Offset: 5,
|
|
Limit: 10,
|
|
},
|
|
Clients: directClients[5:10],
|
|
},
|
|
},
|
|
{
|
|
desc: "retrieve clients with member id of parent group wth direct group access",
|
|
domainID: domain.ID,
|
|
userID: groupMemberID,
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: 10,
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 1,
|
|
Offset: 0,
|
|
Limit: 10,
|
|
},
|
|
Clients: []clients.Client{groupClient},
|
|
},
|
|
},
|
|
{
|
|
desc: "retrieve clients with member id of domain with domain access",
|
|
domainID: domain.ID,
|
|
userID: domainMemberID,
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: 10,
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 10,
|
|
Offset: 0,
|
|
Limit: 10,
|
|
},
|
|
Clients: domainClients,
|
|
},
|
|
},
|
|
{
|
|
desc: "retrieve clients connected to a channel",
|
|
domainID: domain.ID,
|
|
userID: userID,
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: 10,
|
|
Channel: channelID,
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 1,
|
|
Offset: 0,
|
|
Limit: 10,
|
|
},
|
|
Clients: []clients.Client{connectedClient},
|
|
},
|
|
},
|
|
{
|
|
desc: "retrieve clients with offset out of range and limit",
|
|
domainID: domain.ID,
|
|
userID: userID,
|
|
pm: clients.Page{
|
|
Offset: 1000,
|
|
Limit: 50,
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: nClients,
|
|
Offset: 1000,
|
|
Limit: 50,
|
|
},
|
|
Clients: []clients.Client(nil),
|
|
},
|
|
},
|
|
{
|
|
desc: "retrieve clients with metadata",
|
|
domainID: domain.ID,
|
|
userID: userID,
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
Metadata: directClients[0].Metadata,
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 1,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: []clients.Client{directClients[0]},
|
|
},
|
|
},
|
|
{
|
|
desc: "retrieve clients with wrong metadata",
|
|
domainID: domain.ID,
|
|
userID: userID,
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
Metadata: clients.Metadata{
|
|
"faculty": namegen.Generate(),
|
|
},
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 0,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: []clients.Client(nil),
|
|
},
|
|
},
|
|
{
|
|
desc: "retrieve clients with invalid metadata",
|
|
domainID: domain.ID,
|
|
userID: userID,
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
Metadata: clients.Metadata{
|
|
"faculty": make(chan int),
|
|
},
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: uint64(nClients),
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: []clients.Client(nil),
|
|
},
|
|
err: repoerr.ErrViewEntity,
|
|
},
|
|
{
|
|
desc: "retrieve clients with name",
|
|
domainID: domain.ID,
|
|
userID: userID,
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
Name: directClients[0].Name,
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 1,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: []clients.Client{directClients[0]},
|
|
},
|
|
},
|
|
{
|
|
desc: "retrieve clients with wrong name",
|
|
domainID: domain.ID,
|
|
userID: userID,
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
Name: namegen.Generate(),
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 0,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: []clients.Client(nil),
|
|
},
|
|
},
|
|
{
|
|
desc: "retrieve cliens with identity",
|
|
domainID: domain.ID,
|
|
userID: userID,
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
Identity: directClients[0].Credentials.Identity,
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 1,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: []clients.Client{directClients[0]},
|
|
},
|
|
},
|
|
{
|
|
desc: "retrieve clients with wrong identity",
|
|
domainID: domain.ID,
|
|
userID: userID,
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
Identity: namegen.Generate(),
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 0,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: []clients.Client(nil),
|
|
},
|
|
},
|
|
{
|
|
desc: "retrieve clients with tag",
|
|
domainID: domain.ID,
|
|
userID: userID,
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
Tags: clients.TagsQuery{Elements: []string{directClients[0].Tags[0]}, Operator: clients.OrOp},
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 1,
|
|
Offset: 0,
|
|
Limit: uint64(nClients),
|
|
},
|
|
Clients: []clients.Client{directClients[0]},
|
|
},
|
|
},
|
|
{
|
|
desc: "retrieve clients with wrong tags",
|
|
domainID: domain.ID,
|
|
userID: userID,
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
Tags: clients.TagsQuery{Elements: []string{namegen.Generate()}, Operator: clients.OrOp},
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 0,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: []clients.Client(nil),
|
|
},
|
|
},
|
|
{
|
|
desc: "retrieve clients with multiple parameters",
|
|
domainID: domain.ID,
|
|
userID: userID,
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
Metadata: directClients[0].Metadata,
|
|
Name: directClients[0].Name,
|
|
Tags: clients.TagsQuery{Elements: []string{directClients[0].Tags[0]}, Operator: clients.OrOp},
|
|
Identity: directClients[0].Credentials.Identity,
|
|
Status: clients.AllStatus,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 1,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: []clients.Client{directClients[0]},
|
|
},
|
|
},
|
|
{
|
|
desc: "retrieve clients with id",
|
|
domainID: domain.ID,
|
|
userID: userID,
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
ID: directClients[0].ID,
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 1,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: []clients.Client{directClients[0]},
|
|
},
|
|
},
|
|
{
|
|
desc: "retrieve clients with wrong id",
|
|
domainID: domain.ID,
|
|
userID: userID,
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
ID: testsutil.GenerateUUID(t),
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 0,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: []clients.Client(nil),
|
|
},
|
|
},
|
|
{
|
|
desc: "retrieve clients with wrong domain id",
|
|
domainID: testsutil.GenerateUUID(t),
|
|
userID: userID,
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 0,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: []clients.Client(nil),
|
|
},
|
|
},
|
|
{
|
|
desc: "retrieve clients with wrong user id",
|
|
domainID: domain.ID,
|
|
userID: testsutil.GenerateUUID(t),
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 0,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: []clients.Client(nil),
|
|
},
|
|
},
|
|
{
|
|
desc: "retrieve clients with parent group",
|
|
domainID: domain.ID,
|
|
userID: userID,
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
Group: &group.ID,
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 1,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: []clients.Client{parentGroupClient},
|
|
},
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "retrieve clients with no parent group",
|
|
domainID: domain.ID,
|
|
userID: userID,
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
Group: &emptyGroupParam,
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 0,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: []clients.Client{},
|
|
},
|
|
},
|
|
{
|
|
desc: "retrieve clients with access type",
|
|
domainID: domain.ID,
|
|
userID: domainMemberID,
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: 10,
|
|
AccessType: domainAccess,
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 10,
|
|
Offset: 0,
|
|
Limit: 10,
|
|
},
|
|
Clients: domainClients,
|
|
},
|
|
},
|
|
{
|
|
desc: "retrieve clients with wrong access type",
|
|
domainID: domain.ID,
|
|
userID: userID,
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
AccessType: domainAccess,
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 0,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: []clients.Client{},
|
|
},
|
|
},
|
|
{
|
|
desc: "retrieve clients with role ID",
|
|
domainID: domain.ID,
|
|
userID: userID,
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
RoleID: directClients[0].RoleID,
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 1,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: []clients.Client{directClients[0]},
|
|
},
|
|
},
|
|
{
|
|
desc: "retrieve clients with wrong role ID",
|
|
domainID: domain.ID,
|
|
userID: userID,
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
RoleID: testsutil.GenerateUUID(t),
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 0,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: []clients.Client(nil),
|
|
},
|
|
},
|
|
{
|
|
desc: "retrieve clients with role name",
|
|
domainID: domain.ID,
|
|
userID: userID,
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: 1,
|
|
RoleName: directClients[0].RoleName,
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 10,
|
|
Offset: 0,
|
|
Limit: 1,
|
|
},
|
|
Clients: directClients[0:1],
|
|
},
|
|
},
|
|
{
|
|
desc: "retrieve clients with wrong role name",
|
|
domainID: domain.ID,
|
|
userID: userID,
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
RoleName: namegen.Generate(),
|
|
Status: clients.AllStatus,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 0,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: []clients.Client(nil),
|
|
},
|
|
},
|
|
{
|
|
desc: "retrieve clients with order by name ascending",
|
|
domainID: domain.ID,
|
|
userID: userID,
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: 5,
|
|
Order: "name",
|
|
Dir: ascDir,
|
|
Status: clients.AllStatus,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: nClients,
|
|
Offset: 0,
|
|
Limit: 5,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "retrieve clients with order by name descending",
|
|
domainID: domain.ID,
|
|
userID: userID,
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: 5,
|
|
Order: "name",
|
|
Dir: descDir,
|
|
Status: clients.AllStatus,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: nClients,
|
|
Offset: 0,
|
|
Limit: 5,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "retrieve clients with order by identity ascending",
|
|
domainID: domain.ID,
|
|
userID: userID,
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: 5,
|
|
Order: "identity",
|
|
Dir: ascDir,
|
|
Status: clients.AllStatus,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: nClients,
|
|
Offset: 0,
|
|
Limit: 5,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "retrieve clients with order by identity descending",
|
|
domainID: domain.ID,
|
|
userID: userID,
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: 5,
|
|
Order: "identity",
|
|
Dir: descDir,
|
|
Status: clients.AllStatus,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: nClients,
|
|
Offset: 0,
|
|
Limit: 5,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "retrieve clients with order by created_at ascending",
|
|
domainID: domain.ID,
|
|
userID: userID,
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: 5,
|
|
Order: defOrder,
|
|
Dir: ascDir,
|
|
Status: clients.AllStatus,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: nClients,
|
|
Offset: 0,
|
|
Limit: 5,
|
|
},
|
|
Clients: directClients[:5],
|
|
},
|
|
},
|
|
{
|
|
desc: "retrieve clients with order by created_at descending",
|
|
domainID: domain.ID,
|
|
userID: userID,
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: 5,
|
|
Order: defOrder,
|
|
Dir: descDir,
|
|
Status: clients.AllStatus,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: nClients,
|
|
Offset: 0,
|
|
Limit: 5,
|
|
},
|
|
Clients: reversedDirectClients[:5],
|
|
},
|
|
},
|
|
{
|
|
desc: "retrieve clients with order by updated_at ascending",
|
|
domainID: domain.ID,
|
|
userID: userID,
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: 5,
|
|
Order: "updated_at",
|
|
Dir: ascDir,
|
|
Status: clients.AllStatus,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: nClients,
|
|
Offset: 0,
|
|
Limit: 5,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
desc: "retrieve clients with order by updated_at descending",
|
|
domainID: domain.ID,
|
|
userID: userID,
|
|
pm: clients.Page{
|
|
Offset: 0,
|
|
Limit: 5,
|
|
Order: "updated_at",
|
|
Dir: descDir,
|
|
Status: clients.AllStatus,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: nClients,
|
|
Offset: 0,
|
|
Limit: 5,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
page, err := repo.RetrieveUserClients(context.Background(), tc.domainID, tc.userID, tc.pm)
|
|
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("expected %s to contain %s\n", err, tc.err))
|
|
if err == nil {
|
|
assert.Equal(t, tc.response.Total, page.Total)
|
|
assert.Equal(t, tc.response.Offset, page.Offset)
|
|
assert.Equal(t, tc.response.Limit, page.Limit)
|
|
if len(tc.response.Clients) > 0 {
|
|
expected := stripClientDetails(tc.response.Clients)
|
|
got := stripClientDetails(page.Clients)
|
|
assert.ElementsMatch(t, expected, got, fmt.Sprintf("expected %+v got %+v\n", expected, got))
|
|
}
|
|
verifyClientsOrdering(t, page.Clients, tc.pm.Order, tc.pm.Dir)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSearchClients(t *testing.T) {
|
|
t.Cleanup(func() {
|
|
_, err := db.Exec("DELETE FROM clients")
|
|
require.Nil(t, err, fmt.Sprintf("clean clients unexpected error: %s", err))
|
|
})
|
|
|
|
repo := postgres.NewRepository(database)
|
|
|
|
name := namegen.Generate()
|
|
|
|
nClients := uint64(200)
|
|
expectedClients := []clients.Client{}
|
|
baseTime := time.Now().UTC().Truncate(time.Microsecond)
|
|
for i := 0; i < int(nClients); i++ {
|
|
username := name + strconv.Itoa(i) + emailSuffix
|
|
client := clients.Client{
|
|
ID: testsutil.GenerateUUID(t),
|
|
Name: username,
|
|
Credentials: clients.Credentials{
|
|
Identity: username,
|
|
Secret: testsutil.GenerateUUID(t),
|
|
},
|
|
Metadata: clients.Metadata{
|
|
"department": namegen.Generate(),
|
|
},
|
|
PrivateMetadata: clients.Metadata{},
|
|
Status: clients.EnabledStatus,
|
|
CreatedAt: baseTime.Add(time.Duration(i) * time.Microsecond),
|
|
}
|
|
_, err := repo.Save(context.Background(), client)
|
|
require.Nil(t, err, fmt.Sprintf("save client unexpected error: %s", err))
|
|
|
|
expectedClients = append(expectedClients, clients.Client{
|
|
ID: client.ID,
|
|
Name: client.Name,
|
|
Metadata: client.Metadata,
|
|
CreatedAt: client.CreatedAt,
|
|
})
|
|
}
|
|
|
|
page, err := repo.RetrieveAll(context.Background(), clients.Page{Offset: 0, Limit: nClients})
|
|
require.Nil(t, err, fmt.Sprintf("retrieve all clients unexpected error: %s", err))
|
|
assert.Equal(t, nClients, page.Total)
|
|
|
|
cases := []struct {
|
|
desc string
|
|
page clients.Page
|
|
response clients.ClientsPage
|
|
err error
|
|
}{
|
|
{
|
|
desc: "with empty page",
|
|
page: clients.Page{},
|
|
response: clients.ClientsPage{
|
|
Clients: []clients.Client(nil),
|
|
Page: clients.Page{
|
|
Total: nClients,
|
|
Offset: 0,
|
|
Limit: 0,
|
|
},
|
|
},
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "with offset only",
|
|
page: clients.Page{
|
|
Offset: 50,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Clients: []clients.Client(nil),
|
|
Page: clients.Page{
|
|
Total: nClients,
|
|
Offset: 50,
|
|
Limit: 0,
|
|
},
|
|
},
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "with limit only",
|
|
page: clients.Page{
|
|
Limit: 10,
|
|
Order: "name",
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Clients: expectedClients[0:10],
|
|
Page: clients.Page{
|
|
Total: nClients,
|
|
Offset: 0,
|
|
Limit: 10,
|
|
},
|
|
},
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "retrieve all clients",
|
|
page: clients.Page{
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: nClients,
|
|
Offset: 0,
|
|
Limit: nClients,
|
|
},
|
|
Clients: expectedClients,
|
|
},
|
|
},
|
|
{
|
|
desc: "with offset and limit",
|
|
page: clients.Page{
|
|
Offset: 10,
|
|
Limit: 10,
|
|
Order: "name",
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Clients: expectedClients[10:20],
|
|
Page: clients.Page{
|
|
Total: nClients,
|
|
Offset: 10,
|
|
Limit: 10,
|
|
},
|
|
},
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "with offset out of range and limit",
|
|
page: clients.Page{
|
|
Offset: 1000,
|
|
Limit: 50,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: nClients,
|
|
Offset: 1000,
|
|
Limit: 50,
|
|
},
|
|
Clients: []clients.Client(nil),
|
|
},
|
|
},
|
|
{
|
|
desc: "with offset and limit out of range",
|
|
page: clients.Page{
|
|
Offset: 190,
|
|
Limit: 50,
|
|
Order: "name",
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: nClients,
|
|
Offset: 190,
|
|
Limit: 50,
|
|
},
|
|
Clients: expectedClients[190:200],
|
|
},
|
|
},
|
|
{
|
|
desc: "with shorter name",
|
|
page: clients.Page{
|
|
Name: expectedClients[0].Name[:4],
|
|
Offset: 0,
|
|
Limit: 10,
|
|
Order: "name",
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Clients: findClients(expectedClients, expectedClients[0].Name[:4], 0, 10),
|
|
Page: clients.Page{
|
|
Total: nClients,
|
|
Offset: 0,
|
|
Limit: 10,
|
|
},
|
|
},
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "with longer name",
|
|
page: clients.Page{
|
|
Name: expectedClients[0].Name,
|
|
Offset: 0,
|
|
Limit: 10,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Clients: []clients.Client{expectedClients[0]},
|
|
Page: clients.Page{
|
|
Total: 1,
|
|
Offset: 0,
|
|
Limit: 10,
|
|
},
|
|
},
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "with name SQL injected",
|
|
page: clients.Page{
|
|
Name: fmt.Sprintf("%s' OR '1'='1", expectedClients[0].Name[:1]),
|
|
Offset: 0,
|
|
Limit: 10,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Clients: []clients.Client(nil),
|
|
Page: clients.Page{
|
|
Total: 0,
|
|
Offset: 0,
|
|
Limit: 10,
|
|
},
|
|
},
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "with shorter Identity",
|
|
page: clients.Page{
|
|
Identity: expectedClients[0].Name[:4],
|
|
Offset: 0,
|
|
Limit: 10,
|
|
Order: "name",
|
|
Dir: ascDir,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Clients: findClients(expectedClients, expectedClients[0].Name[:4], 0, 10),
|
|
Page: clients.Page{
|
|
Total: nClients,
|
|
Offset: 0,
|
|
Limit: 10,
|
|
},
|
|
},
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "with longer Identity",
|
|
page: clients.Page{
|
|
Identity: expectedClients[0].Name,
|
|
Offset: 0,
|
|
Limit: 10,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Clients: []clients.Client{expectedClients[0]},
|
|
Page: clients.Page{
|
|
Total: 1,
|
|
Offset: 0,
|
|
Limit: 10,
|
|
},
|
|
},
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "with Identity SQL injected",
|
|
page: clients.Page{
|
|
Identity: fmt.Sprintf("%s' OR '1'='1", expectedClients[0].Name[:1]),
|
|
Offset: 0,
|
|
Limit: 10,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Clients: []clients.Client(nil),
|
|
Page: clients.Page{
|
|
Total: 0,
|
|
Offset: 0,
|
|
Limit: 10,
|
|
},
|
|
},
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "with unknown name",
|
|
page: clients.Page{
|
|
Name: namegen.Generate(),
|
|
Offset: 0,
|
|
Limit: 10,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Clients: []clients.Client(nil),
|
|
Page: clients.Page{
|
|
Total: 0,
|
|
Offset: 0,
|
|
Limit: 10,
|
|
},
|
|
},
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "with unknown name SQL injected",
|
|
page: clients.Page{
|
|
Name: fmt.Sprintf("%s' OR '1'='1", namegen.Generate()),
|
|
Offset: 0,
|
|
Limit: 10,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Clients: []clients.Client(nil),
|
|
Page: clients.Page{
|
|
Total: 0,
|
|
Offset: 0,
|
|
Limit: 10,
|
|
},
|
|
},
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "with unknown identity",
|
|
page: clients.Page{
|
|
Identity: namegen.Generate(),
|
|
Offset: 0,
|
|
Limit: 10,
|
|
},
|
|
response: clients.ClientsPage{
|
|
Clients: []clients.Client(nil),
|
|
Page: clients.Page{
|
|
Total: 0,
|
|
Offset: 0,
|
|
Limit: 10,
|
|
},
|
|
},
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "with name in asc order",
|
|
page: clients.Page{
|
|
Order: "name",
|
|
Dir: ascDir,
|
|
Name: expectedClients[0].Name[:1],
|
|
Offset: 0,
|
|
Limit: 10,
|
|
},
|
|
response: clients.ClientsPage{},
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "with name in desc order",
|
|
page: clients.Page{
|
|
Order: "name",
|
|
Dir: descDir,
|
|
Name: expectedClients[0].Name[:1],
|
|
Offset: 0,
|
|
Limit: 10,
|
|
},
|
|
response: clients.ClientsPage{},
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "with identity in asc order",
|
|
page: clients.Page{
|
|
Order: "identity",
|
|
Dir: ascDir,
|
|
Identity: expectedClients[0].Name[:1],
|
|
Offset: 0,
|
|
Limit: 10,
|
|
},
|
|
response: clients.ClientsPage{},
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "with identity in desc order",
|
|
page: clients.Page{
|
|
Order: "identity",
|
|
Dir: descDir,
|
|
Identity: expectedClients[0].Name[:1],
|
|
Offset: 0,
|
|
Limit: 10,
|
|
},
|
|
response: clients.ClientsPage{},
|
|
err: nil,
|
|
},
|
|
}
|
|
for _, c := range cases {
|
|
t.Run(c.desc, func(t *testing.T) {
|
|
switch response, err := repo.SearchClients(context.Background(), c.page); {
|
|
case err == nil:
|
|
if c.page.Order != "" && c.page.Dir != "" {
|
|
c.response = response
|
|
}
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, c.response.Total, response.Total)
|
|
assert.Equal(t, c.response.Limit, response.Limit)
|
|
assert.Equal(t, c.response.Offset, response.Offset)
|
|
assert.ElementsMatch(t, response.Clients, c.response.Clients)
|
|
default:
|
|
assert.True(t, errors.Contains(err, c.err), fmt.Sprintf("expected %s to contain %s\n", err, c.err))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRetrieveByIDs(t *testing.T) {
|
|
t.Cleanup(func() {
|
|
_, err := db.Exec("DELETE FROM clients")
|
|
require.Nil(t, err, fmt.Sprintf("clean clients unexpected error: %s", err))
|
|
})
|
|
|
|
repo := postgres.NewRepository(database)
|
|
|
|
num := 10
|
|
|
|
var items []clients.Client
|
|
baseTime := time.Now().UTC().Truncate(time.Microsecond)
|
|
for i := 0; i < num; i++ {
|
|
name := namegen.Generate()
|
|
client := clients.Client{
|
|
ID: testsutil.GenerateUUID(t),
|
|
Domain: testsutil.GenerateUUID(t),
|
|
Name: name,
|
|
Credentials: clients.Credentials{
|
|
Identity: name + emailSuffix,
|
|
Secret: testsutil.GenerateUUID(t),
|
|
},
|
|
Tags: namegen.GenerateMultiple(5),
|
|
Metadata: map[string]any{"name": name},
|
|
CreatedAt: baseTime.Add(time.Duration(i) * time.Microsecond),
|
|
Status: clients.EnabledStatus,
|
|
}
|
|
_, err := repo.Save(context.Background(), client)
|
|
require.Nil(t, err, fmt.Sprintf("add new client: expected nil got %s\n", err))
|
|
items = append(items, client)
|
|
}
|
|
|
|
cases := []struct {
|
|
desc string
|
|
ids []string
|
|
response clients.ClientsPage
|
|
err error
|
|
}{
|
|
{
|
|
desc: "successfully",
|
|
ids: getIDs(items[0:3]),
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 3,
|
|
},
|
|
Clients: items[0:3],
|
|
},
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "successfully",
|
|
ids: getIDs(items[3:6]),
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 3,
|
|
},
|
|
Clients: items[3:6],
|
|
},
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "with empty ids",
|
|
ids: []string{},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 0,
|
|
},
|
|
Clients: []clients.Client(nil),
|
|
},
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "with valid and invalid ids",
|
|
ids: append(getIDs(items[0:3]), testsutil.GenerateUUID(t)),
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 3,
|
|
},
|
|
Clients: items[0:3],
|
|
},
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "with invalid ids",
|
|
ids: []string{testsutil.GenerateUUID(t)},
|
|
response: clients.ClientsPage{
|
|
Page: clients.Page{
|
|
Total: 0,
|
|
},
|
|
Clients: []clients.Client(nil),
|
|
},
|
|
err: nil,
|
|
},
|
|
}
|
|
|
|
for _, c := range cases {
|
|
response, err := repo.RetrieveByIds(context.Background(), c.ids)
|
|
assert.True(t, errors.Contains(err, c.err), fmt.Sprintf("%s: expected %s got %s\n", c.desc, c.err, err))
|
|
if err == nil {
|
|
assert.Equal(t, c.response.Total, response.Total)
|
|
expected := stripClientDetails(c.response.Clients)
|
|
got := stripClientDetails(response.Clients)
|
|
assert.ElementsMatch(t, expected, got)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAddConnection(t *testing.T) {
|
|
t.Cleanup(func() {
|
|
_, err := db.Exec("DELETE FROM connections")
|
|
require.Nil(t, err, fmt.Sprintf("clean connections unexpected error: %s", err))
|
|
_, err = db.Exec("DELETE FROM clients")
|
|
require.Nil(t, err, fmt.Sprintf("clean clients unexpected error: %s", err))
|
|
})
|
|
|
|
repo := postgres.NewRepository(database)
|
|
|
|
client := generateClient(t, clients.EnabledStatus, repo)
|
|
|
|
validConnection := clients.Connection{
|
|
ClientID: client.ID,
|
|
ChannelID: testsutil.GenerateUUID(t),
|
|
DomainID: client.Domain,
|
|
Type: connections.Publish,
|
|
}
|
|
|
|
cases := []struct {
|
|
desc string
|
|
connection clients.Connection
|
|
err error
|
|
}{
|
|
{
|
|
desc: "add connection successfully",
|
|
connection: validConnection,
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "add connection with non-existent client",
|
|
connection: clients.Connection{
|
|
ClientID: testsutil.GenerateUUID(t),
|
|
ChannelID: testsutil.GenerateUUID(t),
|
|
DomainID: client.Domain,
|
|
Type: connections.Publish,
|
|
},
|
|
err: repoerr.ErrCreateEntity,
|
|
},
|
|
{
|
|
desc: "add connection with non-existent domain",
|
|
connection: clients.Connection{
|
|
ClientID: client.ID,
|
|
ChannelID: testsutil.GenerateUUID(t),
|
|
DomainID: testsutil.GenerateUUID(t),
|
|
Type: connections.Publish,
|
|
},
|
|
err: repoerr.ErrCreateEntity,
|
|
},
|
|
|
|
{
|
|
desc: "add connection with invalid client ID",
|
|
connection: clients.Connection{
|
|
ClientID: invalidID,
|
|
ChannelID: testsutil.GenerateUUID(t),
|
|
DomainID: testsutil.GenerateUUID(t),
|
|
Type: connections.Publish,
|
|
},
|
|
err: repoerr.ErrMalformedEntity,
|
|
},
|
|
{
|
|
desc: "add connection with invalid channel ID",
|
|
connection: clients.Connection{
|
|
ClientID: client.ID,
|
|
ChannelID: invalidID,
|
|
DomainID: testsutil.GenerateUUID(t),
|
|
Type: connections.Publish,
|
|
},
|
|
err: repoerr.ErrMalformedEntity,
|
|
},
|
|
{
|
|
desc: "add connection with invalid domain ID",
|
|
connection: clients.Connection{
|
|
ClientID: client.ID,
|
|
ChannelID: testsutil.GenerateUUID(t),
|
|
DomainID: invalidID,
|
|
Type: connections.Publish,
|
|
},
|
|
err: repoerr.ErrMalformedEntity,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
err := repo.AddConnections(context.Background(), []clients.Connection{tc.connection})
|
|
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRemoveConnection(t *testing.T) {
|
|
t.Cleanup(func() {
|
|
_, err := db.Exec("DELETE FROM connections")
|
|
require.Nil(t, err, fmt.Sprintf("clean connections unexpected error: %s", err))
|
|
_, err = db.Exec("DELETE FROM clients")
|
|
require.Nil(t, err, fmt.Sprintf("clean clients unexpected error: %s", err))
|
|
})
|
|
|
|
repo := postgres.NewRepository(database)
|
|
|
|
client := generateClient(t, clients.EnabledStatus, repo)
|
|
|
|
validConnection := clients.Connection{
|
|
ClientID: client.ID,
|
|
ChannelID: testsutil.GenerateUUID(t),
|
|
DomainID: client.Domain,
|
|
Type: connections.Publish,
|
|
}
|
|
|
|
err := repo.AddConnections(context.Background(), []clients.Connection{validConnection})
|
|
require.Nil(t, err, fmt.Sprintf("add connection unexpected error: %s", err))
|
|
|
|
cases := []struct {
|
|
desc string
|
|
connection clients.Connection
|
|
err error
|
|
}{
|
|
{
|
|
desc: "remove connection successfully",
|
|
connection: validConnection,
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "remove connection with non-existent channel",
|
|
connection: clients.Connection{
|
|
ClientID: client.ID,
|
|
ChannelID: testsutil.GenerateUUID(t),
|
|
DomainID: client.Domain,
|
|
Type: connections.Publish,
|
|
},
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "remove connection with non-existent domain",
|
|
connection: clients.Connection{
|
|
ClientID: client.ID,
|
|
ChannelID: testsutil.GenerateUUID(t),
|
|
DomainID: testsutil.GenerateUUID(t),
|
|
Type: connections.Publish,
|
|
},
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "remove connection with non-existent client",
|
|
connection: clients.Connection{
|
|
ClientID: testsutil.GenerateUUID(t),
|
|
ChannelID: testsutil.GenerateUUID(t),
|
|
DomainID: client.Domain,
|
|
Type: connections.Publish,
|
|
},
|
|
err: nil,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
err := repo.RemoveConnections(context.Background(), []clients.Connection{tc.connection})
|
|
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDelete(t *testing.T) {
|
|
t.Cleanup(func() {
|
|
_, err := db.Exec("DELETE FROM clients")
|
|
require.Nil(t, err, fmt.Sprintf("clean clients unexpected error: %s", err))
|
|
})
|
|
|
|
repo := postgres.NewRepository(database)
|
|
|
|
client := generateClient(t, clients.EnabledStatus, repo)
|
|
|
|
cases := []struct {
|
|
desc string
|
|
id string
|
|
err error
|
|
}{
|
|
{
|
|
desc: "delete client successfully",
|
|
id: client.ID,
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "delete client with invalid id",
|
|
id: testsutil.GenerateUUID(t),
|
|
err: repoerr.ErrNotFound,
|
|
},
|
|
{
|
|
desc: "delete client with empty id",
|
|
id: "",
|
|
err: repoerr.ErrNotFound,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
err := repo.Delete(context.Background(), tc.id)
|
|
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
|
}
|
|
}
|
|
|
|
func TestSetParentGroup(t *testing.T) {
|
|
t.Cleanup(func() {
|
|
_, err := db.Exec("DELETE FROM clients")
|
|
require.Nil(t, err, fmt.Sprintf("clean clients unexpected error: %s", err))
|
|
})
|
|
|
|
repo := postgres.NewRepository(database)
|
|
|
|
validClient := generateClient(t, clients.EnabledStatus, repo)
|
|
|
|
cases := []struct {
|
|
desc string
|
|
id string
|
|
parentGroupID string
|
|
err error
|
|
}{
|
|
{
|
|
desc: "set parent group successfully",
|
|
id: validClient.ID,
|
|
parentGroupID: testsutil.GenerateUUID(t),
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "set parent group with invalid ID",
|
|
id: invalidID,
|
|
parentGroupID: testsutil.GenerateUUID(t),
|
|
err: repoerr.ErrNotFound,
|
|
},
|
|
{
|
|
desc: "set parent group with empty ID",
|
|
id: "",
|
|
parentGroupID: testsutil.GenerateUUID(t),
|
|
err: repoerr.ErrNotFound,
|
|
},
|
|
{
|
|
desc: "set parent group with invalid parent group ID",
|
|
id: validClient.ID,
|
|
parentGroupID: invalidID,
|
|
err: repoerr.ErrMalformedEntity,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
err := repo.SetParentGroup(context.Background(), clients.Client{
|
|
ID: tc.id,
|
|
ParentGroup: tc.parentGroupID,
|
|
})
|
|
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
|
if err == nil {
|
|
resp, err := repo.RetrieveByID(context.Background(), tc.id)
|
|
require.Nil(t, err, fmt.Sprintf("retrieve client unexpected error: %s", err))
|
|
assert.Equal(t, tc.id, resp.ID, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.id, resp.ID))
|
|
assert.Equal(t, tc.parentGroupID, resp.ParentGroup, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.parentGroupID, resp.ParentGroup))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRemoveParentGroup(t *testing.T) {
|
|
t.Cleanup(func() {
|
|
_, err := db.Exec("DELETE FROM clients")
|
|
require.Nil(t, err, fmt.Sprintf("clean clients unexpected error: %s", err))
|
|
})
|
|
|
|
repo := postgres.NewRepository(database)
|
|
|
|
validClient := generateClient(t, clients.EnabledStatus, repo)
|
|
|
|
cases := []struct {
|
|
desc string
|
|
id string
|
|
err error
|
|
}{
|
|
{
|
|
desc: "remove parent group successfully",
|
|
id: validClient.ID,
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "remove parent group with invalid ID",
|
|
id: invalidID,
|
|
err: repoerr.ErrNotFound,
|
|
},
|
|
{
|
|
desc: "remove parent group with empty ID",
|
|
id: "",
|
|
err: repoerr.ErrNotFound,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
err := repo.RemoveParentGroup(context.Background(), clients.Client{
|
|
ID: tc.id,
|
|
})
|
|
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
|
if err == nil {
|
|
resp, err := repo.RetrieveByID(context.Background(), tc.id)
|
|
require.Nil(t, err, fmt.Sprintf("retrieve client unexpected error: %s", err))
|
|
assert.Equal(t, tc.id, resp.ID, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.id, resp.ID))
|
|
assert.Equal(t, "", resp.ParentGroup, fmt.Sprintf("%s: expected %s got %s\n", tc.desc, "", resp.ParentGroup))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestClientConnectionsCount(t *testing.T) {
|
|
t.Cleanup(func() {
|
|
_, err := db.Exec("DELETE FROM connections")
|
|
require.Nil(t, err, fmt.Sprintf("clean connections unexpected error: %s", err))
|
|
_, err = db.Exec("DELETE FROM clients")
|
|
require.Nil(t, err, fmt.Sprintf("clean clients unexpected error: %s", err))
|
|
})
|
|
|
|
repo := postgres.NewRepository(database)
|
|
|
|
validClient := generateClient(t, clients.EnabledStatus, repo)
|
|
|
|
rConnections := []clients.Connection{}
|
|
for i := 0; i < 10; i++ {
|
|
connection := clients.Connection{
|
|
ClientID: validClient.ID,
|
|
ChannelID: testsutil.GenerateUUID(t),
|
|
DomainID: validClient.Domain,
|
|
Type: connections.Publish,
|
|
}
|
|
rConnections = append(rConnections, connection)
|
|
}
|
|
|
|
err := repo.AddConnections(context.Background(), rConnections)
|
|
require.Nil(t, err, fmt.Sprintf("add connection unexpected error: %s", err))
|
|
|
|
cases := []struct {
|
|
desc string
|
|
clientID string
|
|
count uint64
|
|
err error
|
|
}{
|
|
{
|
|
desc: "get client connections count successfully",
|
|
clientID: validClient.ID,
|
|
count: 10,
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "get client connections count with non-existent client",
|
|
clientID: testsutil.GenerateUUID(t),
|
|
count: 0,
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "get client connections count with empty client ID",
|
|
clientID: "",
|
|
count: 0,
|
|
err: nil,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
count, err := repo.ClientConnectionsCount(context.Background(), tc.clientID)
|
|
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
|
assert.Equal(t, tc.count, count, fmt.Sprintf("%s: expected %d got %d\n", tc.desc, tc.count, count))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDoesClientHaveConnections(t *testing.T) {
|
|
t.Cleanup(func() {
|
|
_, err := db.Exec("DELETE FROM connections")
|
|
require.Nil(t, err, fmt.Sprintf("clean connections unexpected error: %s", err))
|
|
_, err = db.Exec("DELETE FROM clients")
|
|
require.Nil(t, err, fmt.Sprintf("clean clients unexpected error: %s", err))
|
|
})
|
|
|
|
repo := postgres.NewRepository(database)
|
|
|
|
validClient := generateClient(t, clients.EnabledStatus, repo)
|
|
|
|
validConnection := clients.Connection{
|
|
ClientID: validClient.ID,
|
|
ChannelID: testsutil.GenerateUUID(t),
|
|
DomainID: validClient.Domain,
|
|
Type: connections.Publish,
|
|
}
|
|
|
|
err := repo.AddConnections(context.Background(), []clients.Connection{validConnection})
|
|
require.Nil(t, err, fmt.Sprintf("add connection unexpected error: %s", err))
|
|
|
|
cases := []struct {
|
|
desc string
|
|
clientID string
|
|
has bool
|
|
err error
|
|
}{
|
|
{
|
|
desc: "check if client has connections successfully",
|
|
clientID: validClient.ID,
|
|
has: true,
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "check if client has connections with non-existent channel",
|
|
clientID: testsutil.GenerateUUID(t),
|
|
has: false,
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "check if client has connections with empty channel ID",
|
|
clientID: "",
|
|
has: false,
|
|
err: nil,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
has, err := repo.DoesClientHaveConnections(context.Background(), tc.clientID)
|
|
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
|
assert.Equal(t, tc.has, has, fmt.Sprintf("%s: expected %t got %t\n", tc.desc, tc.has, has))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRemoveClientConnections(t *testing.T) {
|
|
t.Cleanup(func() {
|
|
_, err := db.Exec("DELETE FROM connections")
|
|
require.Nil(t, err, fmt.Sprintf("clean connections unexpected error: %s", err))
|
|
_, err = db.Exec("DELETE FROM clients")
|
|
require.Nil(t, err, fmt.Sprintf("clean clients unexpected error: %s", err))
|
|
})
|
|
|
|
repo := postgres.NewRepository(database)
|
|
|
|
validClient := generateClient(t, clients.EnabledStatus, repo)
|
|
|
|
validConnection := clients.Connection{
|
|
ClientID: validClient.ID,
|
|
ChannelID: testsutil.GenerateUUID(t),
|
|
DomainID: validClient.Domain,
|
|
Type: connections.Publish,
|
|
}
|
|
|
|
err := repo.AddConnections(context.Background(), []clients.Connection{validConnection})
|
|
require.Nil(t, err, fmt.Sprintf("add connection unexpected error: %s", err))
|
|
|
|
cases := []struct {
|
|
desc string
|
|
clientID string
|
|
err error
|
|
}{
|
|
{
|
|
desc: "remove client connections successfully",
|
|
clientID: validConnection.ClientID,
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "remove client connections with non-existent client",
|
|
clientID: testsutil.GenerateUUID(t),
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "remove client connections with empty client ID",
|
|
clientID: "",
|
|
err: nil,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
err := repo.RemoveClientConnections(context.Background(), tc.clientID)
|
|
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRemoveChannelConnections(t *testing.T) {
|
|
t.Cleanup(func() {
|
|
_, err := db.Exec("DELETE FROM connections")
|
|
require.Nil(t, err, fmt.Sprintf("clean connections unexpected error: %s", err))
|
|
_, err = db.Exec("DELETE FROM clients")
|
|
require.Nil(t, err, fmt.Sprintf("clean clients unexpected error: %s", err))
|
|
})
|
|
|
|
repo := postgres.NewRepository(database)
|
|
|
|
validClient := generateClient(t, clients.EnabledStatus, repo)
|
|
|
|
validConnection := clients.Connection{
|
|
ClientID: validClient.ID,
|
|
ChannelID: testsutil.GenerateUUID(t),
|
|
DomainID: validClient.Domain,
|
|
Type: connections.Publish,
|
|
}
|
|
|
|
err := repo.AddConnections(context.Background(), []clients.Connection{validConnection})
|
|
require.Nil(t, err, fmt.Sprintf("add connection unexpected error: %s", err))
|
|
|
|
cases := []struct {
|
|
desc string
|
|
channelID string
|
|
err error
|
|
}{
|
|
{
|
|
desc: "remove channel connections successfully",
|
|
channelID: validConnection.ChannelID,
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "remove channel connections with non-existent channel",
|
|
channelID: testsutil.GenerateUUID(t),
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "remove channel connections with empty channel ID",
|
|
channelID: "",
|
|
err: nil,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
err := repo.RemoveChannelConnections(context.Background(), tc.channelID)
|
|
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRetrieveParentGroupClients(t *testing.T) {
|
|
t.Cleanup(func() {
|
|
_, err := db.Exec("DELETE FROM clients")
|
|
require.Nil(t, err, fmt.Sprintf("clean clients unexpected error: %s", err))
|
|
})
|
|
|
|
repo := postgres.NewRepository(database)
|
|
|
|
var items []clients.Client
|
|
parentID := testsutil.GenerateUUID(t)
|
|
baseTime := time.Now().UTC().Truncate(time.Microsecond)
|
|
for i := 0; i < 10; i++ {
|
|
name := namegen.Generate()
|
|
client := clients.Client{
|
|
ID: testsutil.GenerateUUID(t),
|
|
Domain: testsutil.GenerateUUID(t),
|
|
ParentGroup: parentID,
|
|
Name: name,
|
|
Metadata: map[string]any{"name": name},
|
|
CreatedAt: baseTime.Add(time.Duration(i) * time.Microsecond),
|
|
Status: clients.EnabledStatus,
|
|
}
|
|
items = append(items, client)
|
|
}
|
|
|
|
_, err := repo.Save(context.Background(), items...)
|
|
require.Nil(t, err, fmt.Sprintf("create client unexpected error: %s", err))
|
|
|
|
cases := []struct {
|
|
desc string
|
|
parentGroupID string
|
|
resp []clients.Client
|
|
err error
|
|
}{
|
|
{
|
|
desc: "retrieve parent group clients successfully",
|
|
parentGroupID: parentID,
|
|
resp: items[:10],
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "retrieve parent group clients with non-existent client",
|
|
parentGroupID: testsutil.GenerateUUID(t),
|
|
resp: []clients.Client(nil),
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "retrieve parent group clients with empty client ID",
|
|
parentGroupID: "",
|
|
resp: []clients.Client(nil),
|
|
err: nil,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
clients, err := repo.RetrieveParentGroupClients(context.Background(), tc.parentGroupID)
|
|
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
|
if err == nil {
|
|
got := stripClientDetails(clients)
|
|
expected := stripClientDetails(tc.resp)
|
|
assert.Equal(t, len(tc.resp), len(clients), fmt.Sprintf("%s: expected %d got %d\n", tc.desc, len(tc.resp), len(clients)))
|
|
assert.ElementsMatch(t, expected, got, fmt.Sprintf("%s: expected %+v got %+v\n", tc.desc, expected, got))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUnsetParentGroupFromClients(t *testing.T) {
|
|
t.Cleanup(func() {
|
|
_, err := db.Exec("DELETE FROM clients")
|
|
require.Nil(t, err, fmt.Sprintf("clean clients unexpected error: %s", err))
|
|
})
|
|
|
|
repo := postgres.NewRepository(database)
|
|
|
|
var items []clients.Client
|
|
parentID := testsutil.GenerateUUID(t)
|
|
baseTime := time.Now().UTC().Truncate(time.Microsecond)
|
|
for i := 0; i < 10; i++ {
|
|
name := namegen.Generate()
|
|
client := clients.Client{
|
|
ID: testsutil.GenerateUUID(t),
|
|
Domain: testsutil.GenerateUUID(t),
|
|
ParentGroup: parentID,
|
|
Name: name,
|
|
Metadata: map[string]any{"name": name},
|
|
CreatedAt: baseTime.Add(time.Duration(i) * time.Microsecond),
|
|
Status: clients.EnabledStatus,
|
|
}
|
|
items = append(items, client)
|
|
}
|
|
|
|
_, err := repo.Save(context.Background(), items...)
|
|
require.Nil(t, err, fmt.Sprintf("create client unexpected error: %s", err))
|
|
|
|
cases := []struct {
|
|
desc string
|
|
parentGroupID string
|
|
err error
|
|
}{
|
|
{
|
|
desc: "unset parent group from clients successfully",
|
|
parentGroupID: parentID,
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "unset parent group from clients with non-existent id",
|
|
parentGroupID: testsutil.GenerateUUID(t),
|
|
err: nil,
|
|
},
|
|
{
|
|
desc: "unset parent group from clients with empty client ID",
|
|
parentGroupID: "",
|
|
err: nil,
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
err := repo.UnsetParentGroupFromClient(context.Background(), tc.parentGroupID)
|
|
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
|
})
|
|
}
|
|
}
|
|
|
|
func generateClient(t *testing.T, status clients.Status, repo clients.Repository) clients.Client {
|
|
client := clients.Client{
|
|
ID: testsutil.GenerateUUID(t),
|
|
Name: namegen.Generate(),
|
|
Credentials: clients.Credentials{
|
|
Identity: namegen.Generate() + emailSuffix,
|
|
Secret: testsutil.GenerateUUID(t),
|
|
},
|
|
Tags: namegen.GenerateMultiple(5),
|
|
PrivateMetadata: clients.Metadata{
|
|
"name": namegen.Generate(),
|
|
},
|
|
Metadata: clients.Metadata{
|
|
"name": namegen.Generate(),
|
|
},
|
|
Status: status,
|
|
CreatedAt: time.Now().UTC().Truncate(time.Millisecond),
|
|
}
|
|
_, err := repo.Save(context.Background(), client)
|
|
require.Nil(t, err, fmt.Sprintf("add new client: expected nil got %s\n", err))
|
|
|
|
return client
|
|
}
|
|
|
|
func generateDomain(t *testing.T, userID, memberID string) domains.Domain {
|
|
domain := domains.Domain{
|
|
ID: testsutil.GenerateUUID(t),
|
|
Route: namegen.Generate(),
|
|
Status: domains.EnabledStatus,
|
|
CreatedAt: time.Now().UTC().Truncate(time.Microsecond),
|
|
CreatedBy: userID,
|
|
}
|
|
|
|
drepo := dpostgres.NewRepository(ddatabase)
|
|
_, err := drepo.SaveDomain(context.Background(), domain)
|
|
require.Nil(t, err, fmt.Sprintf("add new domain: expected nil got %s\n", err))
|
|
newRolesProvision := []roles.RoleProvision{
|
|
{
|
|
Role: roles.Role{
|
|
ID: testsutil.GenerateUUID(t) + "_" + domain.ID,
|
|
Name: "admin",
|
|
EntityID: domain.ID,
|
|
CreatedAt: validTimestamp,
|
|
CreatedBy: userID,
|
|
},
|
|
OptionalActions: domainAvailableActions,
|
|
OptionalMembers: []string{userID, memberID},
|
|
},
|
|
}
|
|
_, err = drepo.AddRoles(context.Background(), newRolesProvision)
|
|
require.Nil(t, err, fmt.Sprintf("add new role: expected nil got %s\n", err))
|
|
domain.Roles = []roles.MemberRoleActions{
|
|
{
|
|
RoleID: newRolesProvision[0].Role.ID,
|
|
RoleName: newRolesProvision[0].Role.Name,
|
|
Actions: newRolesProvision[0].OptionalActions,
|
|
},
|
|
}
|
|
|
|
return domain
|
|
}
|
|
|
|
func generateGroup(t *testing.T, userID, memberID, domainID string) groups.Group {
|
|
group := groups.Group{
|
|
ID: testsutil.GenerateUUID(t),
|
|
Name: namegen.Generate(),
|
|
Domain: domainID,
|
|
Status: groups.EnabledStatus,
|
|
CreatedAt: time.Now().UTC().Truncate(time.Microsecond),
|
|
}
|
|
|
|
grepo := gpostgres.New(gdatabase)
|
|
_, err := grepo.Save(context.Background(), group)
|
|
require.Nil(t, err, fmt.Sprintf("add new domain: expected nil got %s\n", err))
|
|
newRolesProvision := []roles.RoleProvision{
|
|
{
|
|
Role: roles.Role{
|
|
ID: testsutil.GenerateUUID(t) + "_" + group.ID,
|
|
Name: "admin",
|
|
EntityID: group.ID,
|
|
CreatedAt: validTimestamp,
|
|
CreatedBy: userID,
|
|
},
|
|
OptionalActions: groupAvailableActions,
|
|
OptionalMembers: []string{userID, memberID},
|
|
},
|
|
}
|
|
_, err = grepo.AddRoles(context.Background(), newRolesProvision)
|
|
require.Nil(t, err, fmt.Sprintf("add new role: expected nil got %s\n", err))
|
|
group.Roles = []roles.MemberRoleActions{
|
|
{
|
|
RoleID: newRolesProvision[0].Role.ID,
|
|
RoleName: newRolesProvision[0].Role.Name,
|
|
Actions: newRolesProvision[0].OptionalActions,
|
|
},
|
|
}
|
|
|
|
return group
|
|
}
|
|
|
|
func getIDs(clis []clients.Client) []string {
|
|
var ids []string
|
|
for _, client := range clis {
|
|
ids = append(ids, client.ID)
|
|
}
|
|
|
|
return ids
|
|
}
|
|
|
|
func stripClientDetails(clients []clients.Client) []clients.Client {
|
|
for i := range clients {
|
|
clients[i].CreatedAt = validTimestamp
|
|
clients[i].Credentials.Secret = ""
|
|
clients[i].Actions = []string{}
|
|
}
|
|
|
|
return clients
|
|
}
|
|
|
|
func findClients(clis []clients.Client, query string, offset, limit uint64) []clients.Client {
|
|
rclients := []clients.Client{}
|
|
for _, client := range clis {
|
|
if strings.Contains(client.Name, query) {
|
|
rclients = append(rclients, client)
|
|
}
|
|
}
|
|
|
|
if offset > uint64(len(rclients)) {
|
|
return []clients.Client{}
|
|
}
|
|
|
|
if limit > uint64(len(rclients)) {
|
|
return rclients[offset:]
|
|
}
|
|
|
|
return rclients[offset:limit]
|
|
}
|
|
|
|
func verifyClientsOrdering(t *testing.T, clients []clients.Client, order, dir string) {
|
|
if order == "" || len(clients) <= 1 {
|
|
return
|
|
}
|
|
|
|
switch order {
|
|
case "name":
|
|
for i := 1; i < len(clients); i++ {
|
|
if dir == ascDir {
|
|
assert.LessOrEqual(t, clients[i-1].Name, clients[i].Name)
|
|
continue
|
|
}
|
|
assert.GreaterOrEqual(t, clients[i-1].Name, clients[i].Name)
|
|
}
|
|
case "identity":
|
|
for i := 1; i < len(clients); i++ {
|
|
if dir == ascDir {
|
|
assert.LessOrEqual(t, clients[i-1].Credentials.Identity, clients[i].Credentials.Identity)
|
|
continue
|
|
}
|
|
assert.GreaterOrEqual(t, clients[i-1].Credentials.Identity, clients[i].Credentials.Identity)
|
|
}
|
|
case "created_at":
|
|
for i := 1; i < len(clients); i++ {
|
|
if dir == ascDir {
|
|
assert.True(t, !clients[i-1].CreatedAt.After(clients[i].CreatedAt))
|
|
continue
|
|
}
|
|
assert.True(t, !clients[i-1].CreatedAt.Before(clients[i].CreatedAt))
|
|
}
|
|
case "updated_at":
|
|
for i := 1; i < len(clients); i++ {
|
|
if dir == ascDir {
|
|
assert.True(t, !clients[i-1].UpdatedAt.After(clients[i].UpdatedAt))
|
|
continue
|
|
}
|
|
assert.True(t, !clients[i-1].UpdatedAt.Before(clients[i].UpdatedAt))
|
|
}
|
|
}
|
|
}
|