snapshot of https://github.com/cortezaproject/corteza.git (2024.9.x, 2026-09-18; blobs > 131072B omitted)
Some checks failed
SonarQube / SonarQube (push) Failing after 5m28s
E2e test on main branch push / server and client test (map[name:admin port:8080]) (push) Failing after 3m33s
Server and lib tests / Library test (js) (push) Failing after 1m36s
Server and lib tests / Library test (vue) (push) Successful in 2m24s
Server and lib tests / Web client test (admin) (push) Successful in 2m52s
Server and lib tests / Web client test (compose) (push) Successful in 3m23s
Server and lib tests / Web client test (discovery) (push) Successful in 2m49s
Server and lib tests / Web client test (one) (push) Successful in 2m52s
Server and lib tests / Web client test (privacy) (push) Successful in 2m44s
Server and lib tests / Web client test (reporter) (push) Successful in 2m56s
Server and lib tests / Web client test (workflow) (push) Successful in 3m0s
Server and lib tests / Server tests (push) Failing after 4m55s
E2e test on main branch push / notify-failure (push) Failing after 9s
Server and lib tests / Send matrix testing notification (push) Successful in 2s
Mark stale issues and pull requests / stale (push) Successful in 40s

This commit is contained in:
upstream-mirror
2026-09-18 01:22:23 +05:00
commit 7e385fc126
8391 changed files with 1766236 additions and 0 deletions

1
server/store/tests/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
.env

View File

@@ -0,0 +1,129 @@
package tests
import (
"context"
"strconv"
"testing"
"time"
"github.com/cortezaproject/corteza/server/pkg/actionlog"
"github.com/cortezaproject/corteza/server/store"
_ "github.com/joho/godotenv/autoload"
"github.com/stretchr/testify/require"
)
func testActionlogs(t *testing.T, s store.Actionlogs) {
var (
ctx = context.Background()
makeNew = func(id uint64) *actionlog.Action {
// minimum data set for new user
return &actionlog.Action{
ID: id,
Timestamp: *now(),
Action: "test-action",
Resource: "test-resource",
}
}
stringifySetRange = func(set actionlog.ActionSet) string {
if len(set) == 0 {
return ""
}
var out = strconv.FormatUint(set[0].ID, 10)
if len(set) > 1 {
out += ".." + strconv.FormatUint(set[len(set)-1].ID, 10)
}
return out
}
truncAndFill = func(t *testing.T, l int) (*require.Assertions, actionlog.ActionSet) {
req := require.New(t)
req.NoError(s.TruncateActionlogs(ctx))
set := make([]*actionlog.Action, l)
for i := 0; i < l; i++ {
set[i] = makeNew(uint64(i))
}
req.NoError(s.CreateActionlog(ctx, set...))
return req, set
}
)
t.Run("create", func(t *testing.T) {
req := require.New(t)
req.NoError(s.TruncateActionlogs(ctx))
action := &actionlog.Action{
ID: 42,
Timestamp: time.Now(),
Resource: "resource",
Action: "action",
}
req.NoError(s.CreateActionlog(ctx, action))
})
t.Run("search", func(t *testing.T) {
t.Run("by resource", func(t *testing.T) {
req, set := truncAndFill(t, 5)
set, _, err := s.SearchActionlogs(ctx, actionlog.Filter{Resource: "test-resource"})
req.NoError(err)
req.Len(set, 5)
})
t.Run("by action", func(t *testing.T) {
req, set := truncAndFill(t, 5)
set, _, err := s.SearchActionlogs(ctx, actionlog.Filter{Action: "test-action"})
req.NoError(err)
req.Len(set, 5)
})
t.Run("with paging", func(t *testing.T) {
req := require.New(t)
req.NoError(s.TruncateActionlogs(ctx))
set := []*actionlog.Action{
makeNew(1),
makeNew(2),
makeNew(3),
makeNew(4),
makeNew(5),
makeNew(6),
makeNew(7),
makeNew(8),
makeNew(9),
}
req.NoError(s.CreateActionlog(ctx, set...))
f := actionlog.Filter{}
// Fetch first page
f.Limit = 1
set, f, err := store.SearchActionlogs(ctx, s, f)
req.NoError(err)
req.Len(set, int(f.Limit))
req.Equal("9", stringifySetRange(set))
f.Limit = 3
f.BeforeActionID = set[0].ID
set, f, err = store.SearchActionlogs(ctx, s, f)
req.NoError(err)
req.Len(set, int(f.Limit))
req.Equal("8..6", stringifySetRange(set))
f.Limit = 9
f.BeforeActionID = set[2].ID
set, f, err = store.SearchActionlogs(ctx, s, f)
req.NoError(err)
req.Len(set, 5)
req.Equal("5..1", stringifySetRange(set))
})
})
}

View File

@@ -0,0 +1,155 @@
package tests
// This file is auto-generated.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
//
import (
"testing"
"github.com/cortezaproject/corteza/server/store"
)
func testAllGenerated(t *testing.T, s store.Storer) {
t.Run("actionlog", func(t *testing.T) {
testActionlogs(t, s)
})
t.Run("apigwFilter", func(t *testing.T) {
testApigwFilters(t, s)
})
t.Run("apigwRoute", func(t *testing.T) {
testApigwRoutes(t, s)
})
t.Run("application", func(t *testing.T) {
testApplications(t, s)
})
t.Run("attachment", func(t *testing.T) {
testAttachments(t, s)
})
t.Run("authClient", func(t *testing.T) {
testAuthClients(t, s)
})
t.Run("authConfirmedClient", func(t *testing.T) {
testAuthConfirmedClients(t, s)
})
t.Run("authOa2token", func(t *testing.T) {
testAuthOa2tokens(t, s)
})
t.Run("authSession", func(t *testing.T) {
testAuthSessions(t, s)
})
t.Run("automationSession", func(t *testing.T) {
testAutomationSessions(t, s)
})
t.Run("automationTrigger", func(t *testing.T) {
testAutomationTriggers(t, s)
})
t.Run("automationWorkflow", func(t *testing.T) {
testAutomationWorkflows(t, s)
})
t.Run("composeAttachment", func(t *testing.T) {
testComposeAttachments(t, s)
})
t.Run("composeChart", func(t *testing.T) {
testComposeCharts(t, s)
})
t.Run("composeModule", func(t *testing.T) {
testComposeModules(t, s)
})
t.Run("composeModuleField", func(t *testing.T) {
testComposeModuleFields(t, s)
})
t.Run("composeNamespace", func(t *testing.T) {
testComposeNamespaces(t, s)
})
t.Run("composePage", func(t *testing.T) {
testComposePages(t, s)
})
t.Run("composePageLayout", func(t *testing.T) {
testComposePageLayouts(t, s)
})
t.Run("credential", func(t *testing.T) {
testCredentials(t, s)
})
t.Run("dalConnection", func(t *testing.T) {
testDalConnections(t, s)
})
t.Run("dalSchemaAlteration", func(t *testing.T) {
testDalSchemaAlterations(t, s)
})
t.Run("dalSensitivityLevel", func(t *testing.T) {
testDalSensitivityLevels(t, s)
})
t.Run("dataPrivacyRequest", func(t *testing.T) {
testDataPrivacyRequests(t, s)
})
t.Run("dataPrivacyRequestComment", func(t *testing.T) {
testDataPrivacyRequestComments(t, s)
})
t.Run("federationExposedModule", func(t *testing.T) {
testFederationExposedModules(t, s)
})
t.Run("federationModuleMapping", func(t *testing.T) {
testFederationModuleMappings(t, s)
})
t.Run("federationNode", func(t *testing.T) {
testFederationNodes(t, s)
})
t.Run("federationNodeSync", func(t *testing.T) {
testFederationNodeSyncs(t, s)
})
t.Run("federationSharedModule", func(t *testing.T) {
testFederationSharedModules(t, s)
})
t.Run("flag", func(t *testing.T) {
testFlags(t, s)
})
t.Run("label", func(t *testing.T) {
testLabels(t, s)
})
t.Run("notification", func(t *testing.T) {
testNotifications(t, s)
})
t.Run("queue", func(t *testing.T) {
testQueues(t, s)
})
t.Run("queueMessage", func(t *testing.T) {
testQueueMessages(t, s)
})
t.Run("rbacRule", func(t *testing.T) {
testRbacRules(t, s)
})
t.Run("reminder", func(t *testing.T) {
testReminders(t, s)
})
t.Run("report", func(t *testing.T) {
testReports(t, s)
})
t.Run("resourceActivity", func(t *testing.T) {
testResourceActivitys(t, s)
})
t.Run("resourceTranslation", func(t *testing.T) {
testResourceTranslations(t, s)
})
t.Run("role", func(t *testing.T) {
testRoles(t, s)
})
t.Run("roleMember", func(t *testing.T) {
testRoleMembers(t, s)
})
t.Run("settingValue", func(t *testing.T) {
testSettingValues(t, s)
})
t.Run("template", func(t *testing.T) {
testTemplates(t, s)
})
t.Run("user", func(t *testing.T) {
testUsers(t, s)
})
t.Run("userGroup", func(t *testing.T) {
testUserGroups(t, s)
})
}

View File

@@ -0,0 +1,85 @@
package tests
import (
"context"
"testing"
"time"
"github.com/cortezaproject/corteza/server/pkg/filter"
"github.com/cortezaproject/corteza/server/store"
"github.com/cortezaproject/corteza/server/system/types"
_ "github.com/joho/godotenv/autoload"
"github.com/stretchr/testify/require"
)
func testApigwFilters(t *testing.T, s store.ApigwFilters) {
var (
ctx = context.Background()
new = &types.ApigwFilter{
ID: 42,
Enabled: true,
CreatedAt: time.Now(),
CreatedBy: 1}
disabled = &types.ApigwFilter{
ID: 4242,
Enabled: false,
CreatedAt: time.Now(),
CreatedBy: 1}
)
t.Run("create", func(t *testing.T) {
req := require.New(t)
req.NoError(s.TruncateApigwFilters(ctx))
req.NoError(s.CreateApigwFilter(ctx, new))
})
t.Run("update", func(t *testing.T) {
req := require.New(t)
req.NoError(s.TruncateApigwFilters(ctx))
req.NoError(s.UpdateApigwFilter(ctx, new))
})
t.Run("search", func(t *testing.T) {
req := require.New(t)
req.NoError(s.TruncateApigwFilters(ctx))
req.NoError(s.CreateApigwFilter(ctx,
new,
))
set, _, err := s.SearchApigwFilters(ctx, types.ApigwFilterFilter{})
req.NoError(err)
req.Len(set, 1)
})
t.Run("search only disabled", func(t *testing.T) {
req := require.New(t)
req.NoError(s.TruncateApigwFilters(ctx))
req.NoError(s.CreateApigwFilter(ctx,
disabled,
))
set, _, err := s.SearchApigwFilters(ctx, types.ApigwFilterFilter{
Disabled: filter.StateExclusive,
})
req.NoError(err)
req.Len(set, 1)
req.Equal(set[0].ID, disabled.ID)
})
t.Run("search enabled and disabled", func(t *testing.T) {
req := require.New(t)
req.NoError(s.TruncateApigwFilters(ctx))
req.NoError(s.CreateApigwFilter(ctx,
new,
disabled,
))
set, _, err := s.SearchApigwFilters(ctx, types.ApigwFilterFilter{
Disabled: filter.StateInclusive,
})
req.NoError(err)
req.Len(set, 2)
})
}

View File

@@ -0,0 +1,113 @@
package tests
import (
"context"
"testing"
"github.com/cortezaproject/corteza/server/pkg/filter"
"github.com/cortezaproject/corteza/server/store"
"github.com/cortezaproject/corteza/server/system/types"
_ "github.com/joho/godotenv/autoload"
"github.com/stretchr/testify/require"
)
func testApigwRoutes(t *testing.T, s store.ApigwRoutes) {
var (
ctx = context.Background()
new = &types.ApigwRoute{
CreatedAt: *now(),
ID: 42,
Endpoint: "/foo",
Enabled: true,
CreatedBy: 1}
disabled = &types.ApigwRoute{
CreatedAt: *now(),
ID: 4242,
Endpoint: "/foo_disabled",
Enabled: false,
CreatedBy: 1}
)
t.Run("create", func(t *testing.T) {
req := require.New(t)
req.NoError(s.TruncateApigwRoutes(ctx))
req.NoError(s.CreateApigwRoute(ctx, new))
})
t.Run("lookup by ID", func(t *testing.T) {
req := require.New(t)
req.NoError(s.TruncateApigwRoutes(ctx))
req.NoError(s.CreateApigwRoute(ctx, new))
fetched, err := s.LookupApigwRouteByID(ctx, new.ID)
req.NoError(err)
req.Equal(new.ID, fetched.ID)
req.Equal(new.Endpoint, fetched.Endpoint)
req.NotNil(fetched.CreatedAt)
req.Nil(fetched.UpdatedAt)
req.Nil(fetched.DeletedAt)
})
t.Run("lookup by endpoint", func(t *testing.T) {
req := require.New(t)
req.NoError(s.TruncateApigwRoutes(ctx))
req.NoError(s.CreateApigwRoute(ctx, new))
fetched, err := s.LookupApigwRouteByEndpoint(ctx, new.Endpoint)
req.NoError(err)
req.Equal(new.ID, fetched.ID)
req.Equal(new.Endpoint, fetched.Endpoint)
req.NotNil(fetched.CreatedAt)
req.Nil(fetched.UpdatedAt)
req.Nil(fetched.DeletedAt)
})
t.Run("update", func(t *testing.T) {
req := require.New(t)
req.NoError(s.TruncateApigwRoutes(ctx))
req.NoError(s.UpdateApigwRoute(ctx, new))
})
t.Run("search", func(t *testing.T) {
req := require.New(t)
req.NoError(s.TruncateApigwRoutes(ctx))
req.NoError(s.CreateApigwRoute(ctx,
new,
))
set, _, err := s.SearchApigwRoutes(ctx, types.ApigwRouteFilter{Endpoint: "fo"})
req.NoError(err)
req.Len(set, 1)
})
t.Run("search only disabled", func(t *testing.T) {
req := require.New(t)
req.NoError(s.TruncateApigwRoutes(ctx))
req.NoError(s.CreateApigwRoute(ctx,
disabled,
))
set, _, err := s.SearchApigwRoutes(ctx, types.ApigwRouteFilter{
Disabled: filter.StateExclusive,
})
req.NoError(err)
req.Len(set, 1)
req.Equal(set[0].ID, disabled.ID)
})
t.Run("search enabled and disabled", func(t *testing.T) {
req := require.New(t)
req.NoError(s.TruncateApigwRoutes(ctx))
req.NoError(s.CreateApigwRoute(ctx,
new,
disabled,
))
set, _, err := s.SearchApigwRoutes(ctx, types.ApigwRouteFilter{
Disabled: filter.StateInclusive,
})
req.NoError(err)
req.Len(set, 2)
})
}

View File

@@ -0,0 +1,172 @@
package tests
import (
"context"
"github.com/cortezaproject/corteza/server/pkg/filter"
"github.com/cortezaproject/corteza/server/pkg/id"
"github.com/cortezaproject/corteza/server/pkg/rand"
"github.com/cortezaproject/corteza/server/store"
"github.com/cortezaproject/corteza/server/system/types"
"github.com/stretchr/testify/require"
"testing"
"time"
)
func testApplications(t *testing.T, s store.Applications) {
var (
ctx = context.Background()
req = require.New(t)
makeNew = func(name string) *types.Application {
// minimum data set for new application
return &types.Application{
ID: id.Next(),
CreatedAt: time.Now(),
Name: name,
Unify: &types.ApplicationUnify{},
}
}
truncAndCreate = func(t *testing.T) (*require.Assertions, *types.Application) {
req := require.New(t)
req.NoError(s.TruncateApplications(ctx))
res := makeNew(string(rand.Bytes(10)))
req.NoError(s.CreateApplication(ctx, res))
return req, res
}
)
t.Run("create", func(t *testing.T) {
application := makeNew("ApplicationCRUD")
req.NoError(s.CreateApplication(ctx, application))
})
t.Run("lookup by ID", func(t *testing.T) {
req, application := truncAndCreate(t)
fetched, err := s.LookupApplicationByID(ctx, application.ID)
req.NoError(err)
req.Equal(application.Name, fetched.Name)
req.Equal(application.ID, fetched.ID)
req.NotNil(fetched.CreatedAt)
req.Nil(fetched.UpdatedAt)
req.Nil(fetched.DeletedAt)
})
t.Run("update", func(t *testing.T) {
req, application := truncAndCreate(t)
application.Name = "ApplicationCRUD+2"
req.NoError(s.UpdateApplication(ctx, application))
updated, err := s.LookupApplicationByID(ctx, application.ID)
req.NoError(err)
req.Equal(application.Name, updated.Name)
})
t.Run("upsert", func(t *testing.T) {
t.Run("existing", func(t *testing.T) {
req, application := truncAndCreate(t)
application.Name = "ApplicationCRUD+2"
req.NoError(s.UpsertApplication(ctx, application))
updated, err := s.LookupApplicationByID(ctx, application.ID)
req.NoError(err)
req.Equal(application.Name, updated.Name)
})
t.Run("new", func(t *testing.T) {
application := makeNew("upsert me")
application.Name = "ComposeChartCRUD+2"
req.NoError(s.UpsertApplication(ctx, application))
upserted, err := s.LookupApplicationByID(ctx, application.ID)
req.NoError(err)
req.Equal(application.Name, upserted.Name)
})
})
t.Run("delete", func(t *testing.T) {
t.Run("by Application", func(t *testing.T) {
req, application := truncAndCreate(t)
req.NoError(s.DeleteApplication(ctx, application))
_, err := s.LookupApplicationByID(ctx, application.ID)
req.EqualError(err, store.ErrNotFound.Error())
})
t.Run("by ID", func(t *testing.T) {
req, application := truncAndCreate(t)
req.NoError(s.DeleteApplicationByID(ctx, application.ID))
_, err := s.LookupApplicationByID(ctx, application.ID)
req.EqualError(err, store.ErrNotFound.Error())
})
})
t.Run("search", func(t *testing.T) {
prefill := []*types.Application{
makeNew("/one-one"),
makeNew("/one-two"),
makeNew("/two-one"),
makeNew("/two-two"),
makeNew("/two-deleted"),
}
count := len(prefill)
prefill[4].DeletedAt = &prefill[4].CreatedAt
valid := count - 1
req.NoError(s.TruncateApplications(ctx))
req.NoError(s.CreateApplication(ctx, prefill...))
// search for all valid
set, f, err := s.SearchApplications(ctx, types.ApplicationFilter{})
req.NoError(err)
req.Len(set, valid) // we've deleted one
// search for ALL
set, f, err = s.SearchApplications(ctx, types.ApplicationFilter{Deleted: filter.StateInclusive})
req.NoError(err)
req.Len(set, count) // we've deleted one
// search for deleted only
set, f, err = s.SearchApplications(ctx, types.ApplicationFilter{Deleted: filter.StateExclusive})
req.NoError(err)
req.Len(set, 1) // we've deleted one
set, f, err = s.SearchApplications(ctx, types.ApplicationFilter{Name: "/two-one"})
req.NoError(err)
req.Len(set, 1)
// find all prefixed
set, f, err = s.SearchApplications(ctx, types.ApplicationFilter{Query: "/two"})
req.NoError(err)
req.Len(set, 2)
_ = f // dummy
})
t.Run("metrics", func(t *testing.T) {
var (
req = require.New(t)
e = &types.ApplicationMetrics{
Total: 5,
Valid: 2,
Deleted: 3,
}
)
req.NoError(s.TruncateApplications(ctx))
req.NoError(s.CreateApplication(ctx, &types.Application{ID: id.Next(), CreatedAt: *now(), UpdatedAt: now(), Unify: &types.ApplicationUnify{}}))
req.NoError(s.CreateApplication(ctx, &types.Application{ID: id.Next(), CreatedAt: *now(), UpdatedAt: now(), Unify: &types.ApplicationUnify{}}))
req.NoError(s.CreateApplication(ctx, &types.Application{ID: id.Next(), CreatedAt: *now(), DeletedAt: now(), Unify: &types.ApplicationUnify{}}))
req.NoError(s.CreateApplication(ctx, &types.Application{ID: id.Next(), CreatedAt: *now(), DeletedAt: now(), Unify: &types.ApplicationUnify{}}))
req.NoError(s.CreateApplication(ctx, &types.Application{ID: id.Next(), CreatedAt: *now(), DeletedAt: now(), Unify: &types.ApplicationUnify{}}))
m, err := store.ApplicationMetrics(ctx, s)
req.NoError(err)
req.Equal(e, m)
})
}

View File

@@ -0,0 +1,147 @@
package tests
import (
"context"
"strings"
"testing"
"time"
"github.com/cortezaproject/corteza/server/pkg/id"
"github.com/cortezaproject/corteza/server/pkg/rand"
"github.com/cortezaproject/corteza/server/store"
"github.com/cortezaproject/corteza/server/system/types"
_ "github.com/joho/godotenv/autoload"
"github.com/stretchr/testify/require"
)
func testAttachments(t *testing.T, s store.Attachments) {
var (
ctx = context.Background()
req = require.New(t)
makeNew = func(nn ...string) *types.Attachment {
name := strings.Join(nn, "")
return &types.Attachment{
ID: id.Next(),
Name: "handle_" + name,
Kind: "test-kind" + name,
CreatedAt: time.Now(),
}
}
truncAndCreate = func(t *testing.T) (*require.Assertions, *types.Attachment) {
req := require.New(t)
req.NoError(s.TruncateAttachments(ctx))
attachment := makeNew()
req.NoError(s.CreateAttachment(ctx, attachment))
return req, attachment
}
truncAndFill = func(t *testing.T, l int) (*require.Assertions, types.AttachmentSet) {
req := require.New(t)
req.NoError(s.TruncateAttachments(ctx))
set := make([]*types.Attachment, l)
for i := 0; i < l; i++ {
set[i] = makeNew(string(rand.Bytes(10)))
}
req.NoError(s.CreateAttachment(ctx, set...))
return req, set
}
)
t.Run("create", func(t *testing.T) {
req := require.New(t)
req.NoError(s.CreateAttachment(ctx, makeNew()))
})
t.Run("lookup by ID", func(t *testing.T) {
req, att := truncAndCreate(t)
fetched, err := s.LookupAttachmentByID(ctx, att.ID)
req.NoError(err)
req.Equal(att.ID, fetched.ID)
req.NotNil(fetched.CreatedAt)
req.Nil(fetched.UpdatedAt)
req.Nil(fetched.DeletedAt)
})
t.Run("update", func(t *testing.T) {
req, att := truncAndCreate(t)
att.Url = "url"
req.NoError(s.UpdateAttachment(ctx, att))
fetched, err := s.LookupAttachmentByID(ctx, att.ID)
req.NoError(err)
req.Equal(att.ID, fetched.ID)
req.Equal("url", fetched.Url)
})
t.Run("upsert", func(t *testing.T) {
t.Run("existing", func(t *testing.T) {
req, att := truncAndCreate(t)
att.Url = "url"
req.NoError(s.UpsertAttachment(ctx, att))
upserted, err := s.LookupAttachmentByID(ctx, att.ID)
req.NoError(err)
req.Equal(att.Name, upserted.Name)
})
t.Run("new", func(t *testing.T) {
att := makeNew("upsert me", "upsert-me")
req.NoError(s.UpsertAttachment(ctx, att))
upserted, err := s.LookupAttachmentByID(ctx, att.ID)
req.NoError(err)
req.Equal(att.Name, upserted.Name)
})
})
t.Run("delete", func(t *testing.T) {
t.Run("by Attachment", func(t *testing.T) {
req, att := truncAndCreate(t)
req.NoError(s.DeleteAttachment(ctx, att))
_, err := s.LookupAttachmentByID(ctx, att.ID)
req.EqualError(err, store.ErrNotFound.Error())
})
t.Run("by ID", func(t *testing.T) {
req, att := truncAndCreate(t)
req.NoError(s.DeleteAttachmentByID(ctx, att.ID))
_, err := s.LookupAttachmentByID(ctx, att.ID)
req.EqualError(err, store.ErrNotFound.Error())
})
})
t.Run("search", func(t *testing.T) {
t.Run("by kind", func(t *testing.T) {
req, prefill := truncAndFill(t, 5)
set, f, err := s.SearchAttachments(ctx, types.AttachmentFilter{Kind: prefill[0].Kind})
req.NoError(err)
req.Equal(prefill[0].Kind, f.Kind)
req.Len(set, 1)
})
t.Run("with check", func(t *testing.T) {
req, prefill := truncAndFill(t, 5)
set, _, err := s.SearchAttachments(ctx, types.AttachmentFilter{
Check: func(attachment *types.Attachment) (bool, error) {
return attachment.Kind == prefill[0].Kind, nil
},
})
req.NoError(err)
req.Len(set, 1)
req.Equal(prefill[0].Kind, set[0].Kind)
})
})
t.Run("ordered search", func(t *testing.T) {
t.Skip("not implemented")
})
}

View File

@@ -0,0 +1,145 @@
package tests
import (
"context"
"testing"
"time"
"github.com/cortezaproject/corteza/server/pkg/filter"
"github.com/cortezaproject/corteza/server/pkg/id"
"github.com/cortezaproject/corteza/server/pkg/rand"
"github.com/cortezaproject/corteza/server/store"
"github.com/cortezaproject/corteza/server/system/types"
"github.com/stretchr/testify/require"
)
func testAuthClients(t *testing.T, s store.AuthClients) {
var (
ctx = context.Background()
req = require.New(t)
makeNew = func(handle string) *types.AuthClient {
// minimum data set for new authClient
return &types.AuthClient{
ID: id.Next(),
CreatedAt: time.Now(),
Handle: handle,
}
}
truncAndCreate = func(t *testing.T) (*require.Assertions, *types.AuthClient) {
req := require.New(t)
req.NoError(s.TruncateAuthClients(ctx))
res := makeNew(string(rand.Bytes(10)))
req.NoError(s.CreateAuthClient(ctx, res))
return req, res
}
)
t.Run("create", func(t *testing.T) {
req.NoError(s.TruncateAuthClients(ctx))
authClient := makeNew("AuthClientCRUD")
req.NoError(s.CreateAuthClient(ctx, authClient))
})
t.Run("lookup by ID", func(t *testing.T) {
req, authClient := truncAndCreate(t)
fetched, err := s.LookupAuthClientByID(ctx, authClient.ID)
req.NoError(err)
req.Equal(authClient.Handle, fetched.Handle)
req.Equal(authClient.ID, fetched.ID)
req.NotNil(fetched.CreatedAt)
req.Nil(fetched.UpdatedAt)
req.Nil(fetched.DeletedAt)
})
t.Run("update", func(t *testing.T) {
req, authClient := truncAndCreate(t)
authClient.Handle = "AuthClientCRUD-2"
req.NoError(s.UpdateAuthClient(ctx, authClient))
updated, err := s.LookupAuthClientByID(ctx, authClient.ID)
req.NoError(err)
req.Equal(authClient.Handle, updated.Handle)
})
t.Run("upsert", func(t *testing.T) {
t.Run("existing", func(t *testing.T) {
req, authClient := truncAndCreate(t)
authClient.Handle = "AuthClientCRUD-2"
req.NoError(s.UpsertAuthClient(ctx, authClient))
updated, err := s.LookupAuthClientByID(ctx, authClient.ID)
req.NoError(err)
req.Equal(authClient.Handle, updated.Handle)
})
t.Run("new", func(t *testing.T) {
authClient := makeNew("upsert me")
authClient.Handle = "ComposeChartCRUD-2"
req.NoError(s.UpsertAuthClient(ctx, authClient))
upserted, err := s.LookupAuthClientByID(ctx, authClient.ID)
req.NoError(err)
req.Equal(authClient.Handle, upserted.Handle)
})
})
t.Run("delete", func(t *testing.T) {
t.Run("by AuthClient", func(t *testing.T) {
req, authClient := truncAndCreate(t)
req.NoError(s.DeleteAuthClient(ctx, authClient))
_, err := s.LookupAuthClientByID(ctx, authClient.ID)
req.EqualError(err, store.ErrNotFound.Error())
})
t.Run("by ID", func(t *testing.T) {
req, authClient := truncAndCreate(t)
req.NoError(s.DeleteAuthClientByID(ctx, authClient.ID))
_, err := s.LookupAuthClientByID(ctx, authClient.ID)
req.EqualError(err, store.ErrNotFound.Error())
})
})
t.Run("search", func(t *testing.T) {
prefill := []*types.AuthClient{
makeNew("/one-one"),
makeNew("/one-two"),
makeNew("/two-one"),
makeNew("/two-two"),
makeNew("/two-deleted"),
}
count := len(prefill)
prefill[4].DeletedAt = &prefill[4].CreatedAt
valid := count - 1
req.NoError(s.TruncateAuthClients(ctx))
req.NoError(s.CreateAuthClient(ctx, prefill...))
// search for all valid
set, f, err := s.SearchAuthClients(ctx, types.AuthClientFilter{})
req.NoError(err)
req.Len(set, valid) // we've deleted one
// search for ALL
set, f, err = s.SearchAuthClients(ctx, types.AuthClientFilter{Deleted: filter.StateInclusive})
req.NoError(err)
req.Len(set, count) // we've deleted one
// search for deleted only
set, f, err = s.SearchAuthClients(ctx, types.AuthClientFilter{Deleted: filter.StateExclusive})
req.NoError(err)
req.Len(set, 1) // we've deleted one
set, f, err = s.SearchAuthClients(ctx, types.AuthClientFilter{Handle: "/two-one"})
req.NoError(err)
req.Len(set, 1)
_ = f // dummy
})
}

View File

@@ -0,0 +1,55 @@
package tests
import (
"context"
"github.com/cortezaproject/corteza/server/store"
"github.com/cortezaproject/corteza/server/system/types"
"github.com/stretchr/testify/require"
"testing"
"time"
)
func testAuthConfirmedClients(t *testing.T, s store.AuthConfirmedClients) {
var (
ctx = context.Background()
makeNew = func(c, u uint64) *types.AuthConfirmedClient {
// minimum data set for new authConfirmedClient
return &types.AuthConfirmedClient{
ClientID: c,
UserID: u,
ConfirmedAt: time.Now(),
}
}
truncAndCreate = func(t *testing.T) (*require.Assertions, *types.AuthConfirmedClient) {
req := require.New(t)
req.NoError(s.TruncateAuthConfirmedClients(ctx))
res := makeNew(1, 2)
req.NoError(s.CreateAuthConfirmedClient(ctx, res))
return req, res
}
)
t.Run("lookup by ID", func(t *testing.T) {
req, acc := truncAndCreate(t)
fetched, err := s.LookupAuthConfirmedClientByUserIDClientID(ctx, acc.UserID, acc.ClientID)
req.NoError(err)
req.NotNil(fetched)
})
t.Run("upsert", func(t *testing.T) {
t.Run("existing", func(t *testing.T) {
req, authConfirmedClient := truncAndCreate(t)
req.NoError(s.UpsertAuthConfirmedClient(ctx, authConfirmedClient))
})
})
t.Run("delete", func(t *testing.T) {
t.Run("by client and user ID", func(t *testing.T) {
req, acc := truncAndCreate(t)
req.NoError(s.DeleteAuthConfirmedClientByUserIDClientID(ctx, acc.UserID, acc.ClientID))
})
})
}

View File

@@ -0,0 +1,88 @@
package tests
import (
"context"
"testing"
"time"
"github.com/cortezaproject/corteza/server/pkg/id"
"github.com/cortezaproject/corteza/server/pkg/rand"
"github.com/cortezaproject/corteza/server/store"
"github.com/cortezaproject/corteza/server/system/types"
"github.com/stretchr/testify/require"
)
func testAuthOa2tokens(t *testing.T, s store.AuthOa2tokens) {
var (
ctx = context.Background()
req = require.New(t)
makeNew = func() *types.AuthOa2token {
// minimum data set for new authOa2token
return &types.AuthOa2token{
ID: id.Next(),
CreatedAt: time.Now(),
ExpiresAt: time.Now(),
Access: string(rand.Bytes(5)),
Code: string(rand.Bytes(5)),
Refresh: string(rand.Bytes(5)),
}
}
truncAndCreate = func(t *testing.T) (*require.Assertions, *types.AuthOa2token) {
req := require.New(t)
req.NoError(s.TruncateAuthOa2tokens(ctx))
res := makeNew()
req.NoError(s.CreateAuthOa2token(ctx, res))
return req, res
}
)
t.Run("create", func(t *testing.T) {
authOa2token := makeNew()
req.NoError(s.CreateAuthOa2token(ctx, authOa2token))
})
t.Run("lookup by", func(t *testing.T) {
t.Run("access", func(t *testing.T) {
req, authOa2token := truncAndCreate(t)
fetched, err := s.LookupAuthOa2tokenByAccess(ctx, authOa2token.Access)
req.NoError(err)
req.NotNil(fetched)
})
t.Run("code", func(t *testing.T) {
req, authOa2token := truncAndCreate(t)
fetched, err := s.LookupAuthOa2tokenByCode(ctx, authOa2token.Code)
req.NoError(err)
req.NotNil(fetched)
})
t.Run("refresh", func(t *testing.T) {
req, authOa2token := truncAndCreate(t)
fetched, err := s.LookupAuthOa2tokenByRefresh(ctx, authOa2token.Refresh)
req.NoError(err)
req.NotNil(fetched)
})
})
t.Run("delete", func(t *testing.T) {
t.Run("access", func(t *testing.T) {
req, authOa2token := truncAndCreate(t)
err := s.DeleteAuthOA2TokenByRefresh(ctx, authOa2token.Access)
req.NoError(err)
})
t.Run("code", func(t *testing.T) {
req, authOa2token := truncAndCreate(t)
err := s.DeleteAuthOA2TokenByRefresh(ctx, authOa2token.Code)
req.NoError(err)
})
t.Run("refresh", func(t *testing.T) {
req, authOa2token := truncAndCreate(t)
err := s.DeleteAuthOA2TokenByRefresh(ctx, authOa2token.Refresh)
req.NoError(err)
})
})
}

View File

@@ -0,0 +1,65 @@
package tests
import (
"context"
"testing"
"time"
"github.com/cortezaproject/corteza/server/pkg/rand"
"github.com/cortezaproject/corteza/server/store"
"github.com/cortezaproject/corteza/server/system/types"
"github.com/stretchr/testify/require"
)
func testAuthSessions(t *testing.T, s store.AuthSessions) {
var (
ctx = context.Background()
req = require.New(t)
makeNew = func(handle string) *types.AuthSession {
// minimum data set for new authSession
return &types.AuthSession{
ID: handle,
CreatedAt: time.Now(),
ExpiresAt: time.Now(),
Data: []byte("..."),
}
}
truncAndCreate = func(t *testing.T) (*require.Assertions, *types.AuthSession) {
req := require.New(t)
req.NoError(s.TruncateAuthSessions(ctx))
res := makeNew(string(rand.Bytes(10)))
req.NoError(s.CreateAuthSession(ctx, res))
return req, res
}
)
t.Run("create", func(t *testing.T) {
authSession := makeNew("AuthSessionCRUD")
req.NoError(s.CreateAuthSession(ctx, authSession))
})
t.Run("lookup by ID", func(t *testing.T) {
req, authSession := truncAndCreate(t)
fetched, err := s.LookupAuthSessionByID(ctx, authSession.ID)
req.NoError(err)
req.Equal(authSession.ID, fetched.ID)
req.NotNil(fetched.CreatedAt)
})
t.Run("delete", func(t *testing.T) {
t.Run("by AuthSession", func(t *testing.T) {
req, authSession := truncAndCreate(t)
req.NoError(s.DeleteAuthSession(ctx, authSession))
_, err := s.LookupAuthSessionByID(ctx, authSession.ID)
req.EqualError(err, store.ErrNotFound.Error())
})
t.Run("by ID", func(t *testing.T) {
req, authSession := truncAndCreate(t)
req.NoError(s.DeleteAuthSessionByID(ctx, authSession.ID))
_, err := s.LookupAuthSessionByID(ctx, authSession.ID)
req.EqualError(err, store.ErrNotFound.Error())
})
})
}

View File

@@ -0,0 +1,124 @@
package tests
import (
"context"
"testing"
"github.com/cortezaproject/corteza/server/automation/types"
"github.com/cortezaproject/corteza/server/pkg/filter"
"github.com/cortezaproject/corteza/server/pkg/id"
"github.com/cortezaproject/corteza/server/store"
_ "github.com/joho/godotenv/autoload"
"github.com/stretchr/testify/require"
)
func testAutomationSessions(t *testing.T, s store.AutomationSessions) {
var (
ctx = context.Background()
req = require.New(t)
makeNew = func(wfID uint64, completed bool) *types.Session {
ses := &types.Session{
ID: id.Next(),
WorkflowID: wfID,
CreatedAt: *now(),
}
if completed {
ses.CompletedAt = now()
}
return ses
}
truncAndCreate = func(t *testing.T) (*require.Assertions, *types.Session) {
req := require.New(t)
req.NoError(s.TruncateAutomationSessions(ctx))
res := makeNew(0, false)
req.NoError(s.CreateAutomationSession(ctx, res))
return req, res
}
)
t.Run("create", func(t *testing.T) {
req := require.New(t)
wf := &types.Session{
ID: id.Next(),
CreatedAt: *now(),
}
req.NoError(s.CreateAutomationSession(ctx, wf))
})
t.Run("lookup by ID", func(t *testing.T) {
req, wf := truncAndCreate(t)
fetched, err := s.LookupAutomationSessionByID(ctx, wf.ID)
req.NoError(err)
req.Equal(wf.ID, fetched.ID)
req.NotNil(fetched.CreatedAt)
})
t.Run("update", func(t *testing.T) {
req, wf := truncAndCreate(t)
wf.Status = types.SessionCompleted
req.NoError(s.UpdateAutomationSession(ctx, wf))
fetched, err := s.LookupAutomationSessionByID(ctx, wf.ID)
req.NoError(err)
req.Equal(wf.ID, fetched.ID)
req.Equal(types.SessionCompleted, fetched.Status)
})
t.Run("delete", func(t *testing.T) {
t.Run("by Session", func(t *testing.T) {
req, wf := truncAndCreate(t)
req.NoError(s.DeleteAutomationSession(ctx, wf))
_, err := s.LookupAutomationSessionByID(ctx, wf.ID)
req.EqualError(err, store.ErrNotFound.Error())
})
t.Run("by ID", func(t *testing.T) {
req, wf := truncAndCreate(t)
req.NoError(s.DeleteAutomationSessionByID(ctx, wf.ID))
_, err := s.LookupAutomationSessionByID(ctx, wf.ID)
req.EqualError(err, store.ErrNotFound.Error())
})
})
t.Run("search", func(t *testing.T) {
prefill := []*types.Session{
makeNew(1001, false),
makeNew(1001, false),
makeNew(1001, false),
makeNew(1001, false),
makeNew(1001, true),
}
count := len(prefill)
prefill[4].CompletedAt = &prefill[4].CreatedAt
valid := count - 1
req.NoError(s.TruncateAutomationSessions(ctx))
req.NoError(s.CreateAutomationSession(ctx, prefill...))
// search for all valid
set, f, err := s.SearchAutomationSessions(ctx, types.SessionFilter{})
req.NoError(err)
req.Len(set, valid) // we've deleted one
// search for ALL
set, f, err = s.SearchAutomationSessions(ctx, types.SessionFilter{Completed: filter.StateInclusive})
req.NoError(err)
req.Len(set, count) // we've deleted one
// search for deleted only
set, f, err = s.SearchAutomationSessions(ctx, types.SessionFilter{Completed: filter.StateExclusive})
req.NoError(err)
req.Len(set, 1) // we've deleted one
// find all prefixed
set, f, err = s.SearchAutomationSessions(ctx, types.SessionFilter{WorkflowID: id.Strings(1001)})
req.NoError(err)
req.Len(set, 4)
_ = f // dummy
})
}

View File

@@ -0,0 +1,149 @@
package tests
import (
"context"
"testing"
"github.com/cortezaproject/corteza/server/automation/types"
"github.com/cortezaproject/corteza/server/pkg/filter"
"github.com/cortezaproject/corteza/server/pkg/id"
"github.com/cortezaproject/corteza/server/store"
_ "github.com/joho/godotenv/autoload"
"github.com/stretchr/testify/require"
)
func testAutomationTriggers(t *testing.T, s store.AutomationTriggers) {
var (
ctx = context.Background()
req = require.New(t)
makeNew = func() *types.Trigger {
return &types.Trigger{
ID: id.Next(),
CreatedAt: *now(),
}
}
truncAndCreate = func(t *testing.T) (*require.Assertions, *types.Trigger) {
req := require.New(t)
req.NoError(s.TruncateAutomationTriggers(ctx))
res := makeNew()
req.NoError(s.CreateAutomationTrigger(ctx, res))
return req, res
}
)
t.Run("create", func(t *testing.T) {
req := require.New(t)
tr := &types.Trigger{
ID: id.Next(),
CreatedAt: *now(),
}
req.NoError(s.CreateAutomationTrigger(ctx, tr))
})
t.Run("lookup by ID", func(t *testing.T) {
req, tr := truncAndCreate(t)
fetched, err := s.LookupAutomationTriggerByID(ctx, tr.ID)
req.NoError(err)
req.Equal(tr.ID, fetched.ID)
req.NotNil(fetched.CreatedAt)
req.Nil(fetched.UpdatedAt)
req.Nil(fetched.DeletedAt)
})
t.Run("update", func(t *testing.T) {
req, tr := truncAndCreate(t)
tr.Enabled = true
req.NoError(s.UpdateAutomationTrigger(ctx, tr))
fetched, err := s.LookupAutomationTriggerByID(ctx, tr.ID)
req.NoError(err)
req.Equal(tr.ID, fetched.ID)
req.True(fetched.Enabled)
})
t.Run("delete", func(t *testing.T) {
t.Run("by Trigger", func(t *testing.T) {
req, tr := truncAndCreate(t)
req.NoError(s.DeleteAutomationTrigger(ctx, tr))
_, err := s.LookupAutomationTriggerByID(ctx, tr.ID)
req.EqualError(err, store.ErrNotFound.Error())
})
t.Run("by ID", func(t *testing.T) {
req, tr := truncAndCreate(t)
req.NoError(s.DeleteAutomationTriggerByID(ctx, tr.ID))
_, err := s.LookupAutomationTriggerByID(ctx, tr.ID)
req.EqualError(err, store.ErrNotFound.Error())
})
})
t.Run("search", func(t *testing.T) {
auxWf := id.Next()
// Create test triggers
{
req.NoError(s.CreateAutomationTrigger(ctx, &types.Trigger{
ID: id.Next(),
CreatedAt: *now(),
Enabled: true,
WorkflowID: auxWf,
}))
req.NoError(s.CreateAutomationTrigger(ctx, &types.Trigger{
ID: id.Next(),
CreatedAt: *now(),
Enabled: true,
EventType: "event.test",
}))
req.NoError(s.CreateAutomationTrigger(ctx, &types.Trigger{
ID: id.Next(),
CreatedAt: *now(),
Enabled: true,
ResourceType: "resource:test",
}))
req.NoError(s.CreateAutomationTrigger(ctx, &types.Trigger{
ID: id.Next(),
CreatedAt: *now(),
Enabled: true,
DeletedAt: now(),
}))
req.NoError(s.CreateAutomationTrigger(ctx, &types.Trigger{
ID: id.Next(),
CreatedAt: *now(),
Enabled: false,
}))
}
tt, _, err := store.SearchAutomationTriggers(ctx, s, types.TriggerFilter{
WorkflowID: id.Strings(auxWf, 10),
})
req.NoError(err)
req.Len(tt, 1)
tt, _, err = store.SearchAutomationTriggers(ctx, s, types.TriggerFilter{
EventType: "event.test",
})
req.NoError(err)
req.Len(tt, 1)
tt, _, err = store.SearchAutomationTriggers(ctx, s, types.TriggerFilter{
ResourceType: "resource:test",
})
req.NoError(err)
req.Len(tt, 1)
tt, _, err = store.SearchAutomationTriggers(ctx, s, types.TriggerFilter{
Deleted: filter.StateExclusive,
})
req.NoError(err)
req.Len(tt, 1)
tt, _, err = store.SearchAutomationTriggers(ctx, s, types.TriggerFilter{
Disabled: filter.StateExclusive,
})
req.NoError(err)
req.Len(tt, 1)
})
}

View File

@@ -0,0 +1,137 @@
package tests
import (
"context"
"testing"
"github.com/cortezaproject/corteza/server/automation/types"
"github.com/cortezaproject/corteza/server/pkg/filter"
"github.com/cortezaproject/corteza/server/pkg/id"
"github.com/cortezaproject/corteza/server/pkg/rand"
"github.com/cortezaproject/corteza/server/store"
_ "github.com/joho/godotenv/autoload"
"github.com/stretchr/testify/require"
)
func testAutomationWorkflows(t *testing.T, s store.AutomationWorkflows) {
var (
ctx = context.Background()
req = require.New(t)
makeNew = func(handle string) *types.Workflow {
return &types.Workflow{
ID: id.Next(),
Handle: handle,
CreatedAt: *now(),
Enabled: true,
}
}
truncAndCreate = func(t *testing.T) (*require.Assertions, *types.Workflow) {
req := require.New(t)
req.NoError(s.TruncateAutomationWorkflows(ctx))
res := makeNew(string(rand.Bytes(10)))
req.NoError(s.CreateAutomationWorkflow(ctx, res))
return req, res
}
)
t.Run("create", func(t *testing.T) {
req := require.New(t)
wf := &types.Workflow{
ID: id.Next(),
CreatedAt: *now(),
}
req.NoError(s.CreateAutomationWorkflow(ctx, wf))
})
t.Run("lookup by ID", func(t *testing.T) {
req, wf := truncAndCreate(t)
fetched, err := s.LookupAutomationWorkflowByID(ctx, wf.ID)
req.NoError(err)
req.Equal(wf.ID, fetched.ID)
req.NotNil(fetched.CreatedAt)
req.Nil(fetched.UpdatedAt)
req.Nil(fetched.DeletedAt)
})
t.Run("update", func(t *testing.T) {
req, wf := truncAndCreate(t)
wf.Enabled = true
req.NoError(s.UpdateAutomationWorkflow(ctx, wf))
fetched, err := s.LookupAutomationWorkflowByID(ctx, wf.ID)
req.NoError(err)
req.Equal(wf.ID, fetched.ID)
req.True(fetched.Enabled)
})
t.Run("delete", func(t *testing.T) {
t.Run("by Workflow", func(t *testing.T) {
req, wf := truncAndCreate(t)
req.NoError(s.DeleteAutomationWorkflow(ctx, wf))
_, err := s.LookupAutomationWorkflowByID(ctx, wf.ID)
req.EqualError(err, store.ErrNotFound.Error())
})
t.Run("by ID", func(t *testing.T) {
req, wf := truncAndCreate(t)
req.NoError(s.DeleteAutomationWorkflowByID(ctx, wf.ID))
_, err := s.LookupAutomationWorkflowByID(ctx, wf.ID)
req.EqualError(err, store.ErrNotFound.Error())
})
})
t.Run("search", func(t *testing.T) {
prefill := []*types.Workflow{
makeNew("one-one"),
makeNew("one-two"),
makeNew("two-one"),
makeNew("two-two"),
makeNew("two-deleted"),
func() *types.Workflow {
wf := makeNew("subwf")
wf.Meta = &types.WorkflowMeta{SubWorkflow: true}
return wf
}(),
}
count := len(prefill)
prefill[4].DeletedAt = &prefill[4].CreatedAt
valid := count - 2
req.NoError(s.TruncateAutomationWorkflows(ctx))
req.NoError(s.CreateAutomationWorkflow(ctx, prefill...))
// search for all valid
set, f, err := s.SearchAutomationWorkflows(ctx, types.WorkflowFilter{})
req.NoError(err)
req.Len(set, valid) // all but deleted or workflows
// search for ALL, including deleted and sub-workflows
set, f, err = s.SearchAutomationWorkflows(ctx, types.WorkflowFilter{
Deleted: filter.StateInclusive,
SubWorkflow: filter.StateInclusive,
})
req.NoError(err)
req.Len(set, count)
// search for deleted only
set, f, err = s.SearchAutomationWorkflows(ctx, types.WorkflowFilter{Deleted: filter.StateExclusive})
req.NoError(err)
req.Len(set, 1) // we've deleted one
// find all prefixed
set, f, err = s.SearchAutomationWorkflows(ctx, types.WorkflowFilter{Query: "two-"})
req.NoError(err)
req.Len(set, 2)
// find just sub-workflows (one)
set, f, err = s.SearchAutomationWorkflows(ctx, types.WorkflowFilter{SubWorkflow: filter.StateExclusive})
req.NoError(err)
req.Len(set, 1)
_ = f // dummy
})
}

View File

@@ -0,0 +1,94 @@
package tests
import (
"context"
"github.com/cortezaproject/corteza/server/compose/types"
"github.com/cortezaproject/corteza/server/pkg/id"
"github.com/cortezaproject/corteza/server/store"
_ "github.com/joho/godotenv/autoload"
"github.com/stretchr/testify/require"
"strings"
"testing"
)
func testComposeAttachments(t *testing.T, s store.ComposeAttachments) {
var (
ctx = context.Background()
makeNew = func(nn ...string) *types.Attachment {
// minimum data set for new attachment
name := strings.Join(nn, "")
return &types.Attachment{
ID: id.Next(),
CreatedAt: *now(),
Name: "handle_" + name,
}
}
truncAndCreate = func(t *testing.T) (*require.Assertions, *types.Attachment) {
req := require.New(t)
req.NoError(s.TruncateComposeAttachments(ctx))
res := makeNew()
req.NoError(s.CreateComposeAttachment(ctx, res))
return req, res
}
)
t.Run("create", func(t *testing.T) {
req := require.New(t)
attachment := &types.Attachment{
ID: id.Next(),
CreatedAt: *now(),
}
req.NoError(s.CreateComposeAttachment(ctx, attachment))
})
t.Run("lookup by ID", func(t *testing.T) {
req, att := truncAndCreate(t)
fetched, err := s.LookupComposeAttachmentByID(ctx, att.ID)
req.NoError(err)
req.Equal(att.ID, fetched.ID)
req.NotNil(fetched.CreatedAt)
req.Nil(fetched.UpdatedAt)
req.Nil(fetched.DeletedAt)
})
t.Run("update", func(t *testing.T) {
req, att := truncAndCreate(t)
att.Url = "url"
req.NoError(s.UpdateComposeAttachment(ctx, att))
fetched, err := s.LookupComposeAttachmentByID(ctx, att.ID)
req.NoError(err)
req.Equal(att.ID, fetched.ID)
req.Equal("url", fetched.Url)
})
t.Run("delete", func(t *testing.T) {
t.Run("by Attachment", func(t *testing.T) {
req, att := truncAndCreate(t)
req.NoError(s.DeleteComposeAttachment(ctx, att))
_, err := s.LookupComposeAttachmentByID(ctx, att.ID)
req.EqualError(err, store.ErrNotFound.Error())
})
t.Run("by ID", func(t *testing.T) {
req, att := truncAndCreate(t)
req.NoError(s.DeleteComposeAttachmentByID(ctx, att.ID))
_, err := s.LookupComposeAttachmentByID(ctx, att.ID)
req.EqualError(err, store.ErrNotFound.Error())
})
})
t.Run("search", func(t *testing.T) {
t.Skip("not implemented")
})
t.Run("search by *", func(t *testing.T) {
t.Skip("not implemented")
})
t.Run("ordered search", func(t *testing.T) {
t.Skip("not implemented")
})
}

View File

@@ -0,0 +1,175 @@
package tests
import (
"context"
"github.com/cortezaproject/corteza/server/compose/types"
"github.com/cortezaproject/corteza/server/pkg/filter"
"github.com/cortezaproject/corteza/server/pkg/id"
"github.com/cortezaproject/corteza/server/pkg/rand"
"github.com/cortezaproject/corteza/server/store"
"github.com/stretchr/testify/require"
"testing"
"time"
)
func testComposeCharts(t *testing.T, s store.Storer) {
var (
ctx = context.Background()
req = require.New(t)
namespaceID = id.Next()
makeNew = func(name, handle string) *types.Chart {
// minimum data set for new composeChart
return &types.Chart{
ID: id.Next(),
NamespaceID: namespaceID,
CreatedAt: time.Now(),
Name: name,
Handle: handle,
}
}
truncAndCreate = func(t *testing.T) (*require.Assertions, *types.Chart) {
req := require.New(t)
req.NoError(s.TruncateComposeCharts(ctx))
res := makeNew(string(rand.Bytes(10)), string(rand.Bytes(10)))
req.NoError(s.CreateComposeChart(ctx, res))
return req, res
}
)
t.Run("create", func(t *testing.T) {
composeChart := makeNew("ComposeChartCRUD", "compose-chart-crud")
req.NoError(s.CreateComposeChart(ctx, composeChart))
})
t.Run("create with duplicate handle", func(t *testing.T) {
t.Skip("not implemented")
})
t.Run("lookup", func(t *testing.T) {
t.Run("by ID", func(t *testing.T) {
composeChart := makeNew("look up by id", "look-up-by-id")
req.NoError(s.CreateComposeChart(ctx, composeChart))
fetched, err := s.LookupComposeChartByID(ctx, composeChart.ID)
req.NoError(err)
req.Equal(composeChart.Name, fetched.Name)
req.Equal(composeChart.ID, fetched.ID)
req.NotNil(fetched.CreatedAt)
req.Nil(fetched.UpdatedAt)
req.Nil(fetched.DeletedAt)
})
t.Run("by Namespace ID, Handle", func(t *testing.T) {
composeChart := makeNew("look up by handle", "look-up-by-handle")
req.NoError(s.CreateComposeChart(ctx, composeChart))
fetched, err := s.LookupComposeChartByNamespaceIDHandle(ctx, composeChart.NamespaceID, composeChart.Handle)
req.NoError(err)
req.Equal(composeChart.Name, fetched.Name)
req.Equal(composeChart.ID, fetched.ID)
req.NotNil(fetched.CreatedAt)
req.Nil(fetched.UpdatedAt)
req.Nil(fetched.DeletedAt)
})
})
t.Run("update", func(t *testing.T) {
req, composeChart := truncAndCreate(t)
composeChart.Name = "ComposeChartCRUD+2"
req.NoError(s.UpdateComposeChart(ctx, composeChart))
updated, err := s.LookupComposeChartByID(ctx, composeChart.ID)
req.NoError(err)
req.Equal(composeChart.Name, updated.Name)
})
t.Run("update with duplicate handle", func(t *testing.T) {
t.Skip("not implemented")
})
t.Run("upsert", func(t *testing.T) {
t.Run("existing", func(t *testing.T) {
req, composeChart := truncAndCreate(t)
composeChart.Name = "ComposeChartCRUD+2"
req.NoError(s.UpsertComposeChart(ctx, composeChart))
upserted, err := s.LookupComposeChartByID(ctx, composeChart.ID)
req.NoError(err)
req.Equal(composeChart.Name, upserted.Name)
})
t.Run("new", func(t *testing.T) {
composeChart := makeNew("upsert me", "upsert-me")
composeChart.Name = "ComposeChartCRUD+2"
req.NoError(s.UpsertComposeChart(ctx, composeChart))
upserted, err := s.LookupComposeChartByID(ctx, composeChart.ID)
req.NoError(err)
req.Equal(composeChart.Name, upserted.Name)
})
})
t.Run("delete", func(t *testing.T) {
t.Run("by Chart", func(t *testing.T) {
req, composeChart := truncAndCreate(t)
req.NoError(s.DeleteComposeChart(ctx, composeChart))
_, err := s.LookupComposeChartByID(ctx, composeChart.ID)
req.EqualError(err, store.ErrNotFound.Error())
})
t.Run("by ID", func(t *testing.T) {
req, composeChart := truncAndCreate(t)
req.NoError(s.DeleteComposeChartByID(ctx, composeChart.ID))
_, err := s.LookupComposeChartByID(ctx, composeChart.ID)
req.EqualError(err, store.ErrNotFound.Error())
})
})
t.Run("search", func(t *testing.T) {
prefill := []*types.Chart{
makeNew("/one-one", "chart-1-1"),
makeNew("/one-two", "chart-1-2"),
makeNew("/two-one", "chart-2-1"),
makeNew("/two-two", "chart-2-2"),
makeNew("/two-deleted", "chart-2-d"),
}
count := len(prefill)
prefill[4].DeletedAt = &prefill[4].CreatedAt
valid := count - 1
req.NoError(s.TruncateComposeCharts(ctx))
req.NoError(s.CreateComposeChart(ctx, prefill...))
// search for all valid
set, f, err := s.SearchComposeCharts(ctx, types.ChartFilter{})
req.NoError(err)
req.Len(set, valid) // we've deleted one
// search for ALL
set, f, err = s.SearchComposeCharts(ctx, types.ChartFilter{Deleted: filter.StateInclusive})
req.NoError(err)
req.Len(set, count) // we've deleted one
// search for deleted only
set, f, err = s.SearchComposeCharts(ctx, types.ChartFilter{Deleted: filter.StateExclusive})
req.NoError(err)
req.Len(set, 1) // we've deleted one
set, f, err = s.SearchComposeCharts(ctx, types.ChartFilter{Handle: "chart-2-1"})
req.NoError(err)
req.Len(set, 1)
// find all prefixed
set, f, err = s.SearchComposeCharts(ctx, types.ChartFilter{Query: "/two-"})
req.NoError(err)
req.Len(set, 2)
_ = f // dummy
})
}

View File

@@ -0,0 +1,121 @@
package tests
import (
"context"
"github.com/cortezaproject/corteza/server/compose/types"
"github.com/cortezaproject/corteza/server/pkg/id"
"github.com/cortezaproject/corteza/server/pkg/rand"
"github.com/cortezaproject/corteza/server/store"
"github.com/stretchr/testify/require"
"testing"
"time"
)
func testComposeModuleFields(t *testing.T, s store.ComposeModuleFields) {
var (
ctx = context.Background()
req = require.New(t)
moduleID = id.Next()
makeNew = func(name, label string) *types.ModuleField {
// minimum data set for new composeModuleField
return &types.ModuleField{
ID: id.Next(),
ModuleID: moduleID,
CreatedAt: time.Now(),
Name: name,
Label: label,
}
}
truncAndCreate = func(t *testing.T) (*require.Assertions, *types.ModuleField) {
req := require.New(t)
req.NoError(s.TruncateComposeModuleFields(ctx))
res := makeNew(string(rand.Bytes(10)), string(rand.Bytes(10)))
req.NoError(s.CreateComposeModuleField(ctx, res))
return req, res
}
)
t.Run("create", func(t *testing.T) {
req := require.New(t)
req.NoError(s.TruncateComposeModuleFields(ctx))
composeModuleField := makeNew("ComposeModuleFieldCRUD", "compose-moduleField-crud")
req.NoError(s.CreateComposeModuleField(ctx, composeModuleField))
})
t.Run("create with duplicate name", func(t *testing.T) {
req := require.New(t)
req.NoError(s.TruncateComposeModuleFields(ctx))
t.Skip("not implemented")
})
t.Run("lookup by Module ID, Name", func(t *testing.T) {
req, composeModuleField := truncAndCreate(t)
fetched, err := s.LookupComposeModuleFieldByModuleIDName(ctx, composeModuleField.ModuleID, composeModuleField.Name)
req.NoError(err)
req.Equal(composeModuleField.Name, fetched.Name)
req.Equal(composeModuleField.ID, fetched.ID)
req.NotNil(fetched.CreatedAt)
req.Nil(fetched.UpdatedAt)
req.Nil(fetched.DeletedAt)
})
t.Run("update", func(t *testing.T) {
req, composeModuleField := truncAndCreate(t)
composeModuleField.Name = "ComposeModuleFieldCRUD+2"
req.NoError(s.UpdateComposeModuleField(ctx, composeModuleField))
updated, err := s.LookupComposeModuleFieldByModuleIDName(ctx, composeModuleField.ModuleID, composeModuleField.Name)
req.NoError(err)
req.Equal(composeModuleField.Name, updated.Name)
})
t.Run("update with duplicate handle", func(t *testing.T) {
t.Skip("not implemented")
})
t.Run("upsert", func(t *testing.T) {
t.Run("existing", func(t *testing.T) {
req, composeModuleField := truncAndCreate(t)
composeModuleField.Name = "ComposeModuleFieldCRUD+2"
req.NoError(s.UpsertComposeModuleField(ctx, composeModuleField))
upserted, err := s.LookupComposeModuleFieldByModuleIDName(ctx, composeModuleField.ModuleID, composeModuleField.Name)
req.NoError(err)
req.Equal(composeModuleField.Name, upserted.Name)
})
t.Run("new", func(t *testing.T) {
composeModuleField := makeNew("upsert me", "upsert-me")
composeModuleField.Name = "ComposeModuleFieldCRUD+3"
req.NoError(s.UpsertComposeModuleField(ctx, composeModuleField))
upserted, err := s.LookupComposeModuleFieldByModuleIDName(ctx, composeModuleField.ModuleID, composeModuleField.Name)
req.NoError(err)
req.Equal(composeModuleField.Name, upserted.Name)
})
})
t.Run("delete", func(t *testing.T) {
t.Run("by Field", func(t *testing.T) {
req, fld := truncAndCreate(t)
req.NoError(s.DeleteComposeModuleField(ctx, fld))
fetched, _, err := s.SearchComposeModuleFields(ctx, types.ModuleFieldFilter{ModuleID: []uint64{fld.ModuleID}})
req.NoError(err)
req.Empty(fetched)
})
t.Run("by ID", func(t *testing.T) {
req, fld := truncAndCreate(t)
req.NoError(s.DeleteComposeModuleFieldByID(ctx, fld.ID))
fetched, _, err := s.SearchComposeModuleFields(ctx, types.ModuleFieldFilter{ModuleID: []uint64{fld.ModuleID}})
req.NoError(err)
req.Empty(fetched)
})
})
}

View File

@@ -0,0 +1,187 @@
package tests
import (
"context"
"github.com/cortezaproject/corteza/server/compose/types"
"github.com/cortezaproject/corteza/server/pkg/filter"
"github.com/cortezaproject/corteza/server/pkg/id"
"github.com/cortezaproject/corteza/server/pkg/rand"
"github.com/cortezaproject/corteza/server/store"
"github.com/stretchr/testify/require"
"testing"
"time"
)
func testComposeModules(t *testing.T, s store.ComposeModules) {
var (
ctx = context.Background()
req = require.New(t)
namespaceID = id.Next()
makeNew = func(name, handle string) *types.Module {
// minimum data set for new composeModule
return &types.Module{
ID: id.Next(),
NamespaceID: namespaceID,
CreatedAt: time.Now(),
Name: name,
Handle: handle,
}
}
truncAndCreate = func(t *testing.T) (*require.Assertions, *types.Module) {
req := require.New(t)
req.NoError(s.TruncateComposeModules(ctx))
res := makeNew(string(rand.Bytes(10)), string(rand.Bytes(10)))
req.NoError(s.CreateComposeModule(ctx, res))
return req, res
}
)
t.Run("create", func(t *testing.T) {
composeModule := makeNew("ComposeModuleCRUD", "compose-module-crud")
req.NoError(s.CreateComposeModule(ctx, composeModule))
})
t.Run("create with duplicate handle", func(t *testing.T) {
t.Skip("not implemented")
})
t.Run("lookup", func(t *testing.T) {
t.Run("by ID", func(t *testing.T) {
composeModule := makeNew("look up by id", "look-up-by-id")
req.NoError(s.CreateComposeModule(ctx, composeModule))
fetched, err := s.LookupComposeModuleByID(ctx, composeModule.ID)
req.NoError(err)
req.Equal(composeModule.Name, fetched.Name)
req.Equal(composeModule.ID, fetched.ID)
req.NotNil(fetched.CreatedAt)
req.Nil(fetched.UpdatedAt)
req.Nil(fetched.DeletedAt)
})
t.Run("by NamespaceID, Name", func(t *testing.T) {
composeModule := makeNew("look up by namespaceIDName", "look-up-by-namespaceIDName")
req.NoError(s.CreateComposeModule(ctx, composeModule))
fetched, err := s.LookupComposeModuleByNamespaceIDName(ctx, composeModule.NamespaceID, composeModule.Name)
req.NoError(err)
req.Equal(composeModule.Name, fetched.Name)
req.Equal(composeModule.ID, fetched.ID)
req.NotNil(fetched.CreatedAt)
req.Nil(fetched.UpdatedAt)
req.Nil(fetched.DeletedAt)
})
t.Run("by Handle", func(t *testing.T) {
composeModule := makeNew("look up by namespaceIDHandle", "look-up-by-namespaceIDHandle")
req.NoError(s.CreateComposeModule(ctx, composeModule))
fetched, err := s.LookupComposeModuleByNamespaceIDHandle(ctx, composeModule.NamespaceID, composeModule.Handle)
req.NoError(err)
req.Equal(composeModule.Name, fetched.Name)
req.Equal(composeModule.ID, fetched.ID)
req.NotNil(fetched.CreatedAt)
req.Nil(fetched.UpdatedAt)
req.Nil(fetched.DeletedAt)
})
})
t.Run("update", func(t *testing.T) {
req, composeModule := truncAndCreate(t)
composeModule.Name = "ComposeModuleCRUD+2"
req.NoError(s.UpdateComposeModule(ctx, composeModule))
updated, err := s.LookupComposeModuleByID(ctx, composeModule.ID)
req.NoError(err)
req.Equal(composeModule.Name, updated.Name)
})
t.Run("update with duplicate handle", func(t *testing.T) {
t.Skip("not implemented")
})
t.Run("upsert", func(t *testing.T) {
t.Run("existing", func(t *testing.T) {
req, composeModule := truncAndCreate(t)
composeModule.Name = "ComposeModuleCRUD+2"
req.NoError(s.UpsertComposeModule(ctx, composeModule))
updated, err := s.LookupComposeModuleByID(ctx, composeModule.ID)
req.NoError(err)
req.Equal(composeModule.Name, updated.Name)
})
t.Run("new", func(t *testing.T) {
composeModule := makeNew("upsert me", "upsert-me")
composeModule.Name = "ComposeChartCRUD+2"
req.NoError(s.UpsertComposeModule(ctx, composeModule))
upserted, err := s.LookupComposeModuleByID(ctx, composeModule.ID)
req.NoError(err)
req.Equal(composeModule.Name, upserted.Name)
})
})
t.Run("delete", func(t *testing.T) {
t.Run("by Module", func(t *testing.T) {
req, composeModule := truncAndCreate(t)
req.NoError(s.DeleteComposeModule(ctx, composeModule))
_, err := s.LookupComposeModuleByID(ctx, composeModule.ID)
req.EqualError(err, store.ErrNotFound.Error())
})
t.Run("by ID", func(t *testing.T) {
req, composeModule := truncAndCreate(t)
req.NoError(s.DeleteComposeModuleByID(ctx, composeModule.ID))
_, err := s.LookupComposeModuleByID(ctx, composeModule.ID)
req.EqualError(err, store.ErrNotFound.Error())
})
})
t.Run("search", func(t *testing.T) {
prefill := []*types.Module{
makeNew("/one-one", "module-1-1"),
makeNew("/one-two", "module-1-2"),
makeNew("/two-one", "module-2-1"),
makeNew("/two-two", "module-2-2"),
makeNew("/two-deleted", "module-2-d"),
}
count := len(prefill)
prefill[4].DeletedAt = &prefill[4].CreatedAt
valid := count - 1
req.NoError(s.TruncateComposeModules(ctx))
req.NoError(s.CreateComposeModule(ctx, prefill...))
// search for all valid
set, f, err := s.SearchComposeModules(ctx, types.ModuleFilter{})
req.NoError(err)
req.Len(set, valid) // we've deleted one
// search for ALL
set, f, err = s.SearchComposeModules(ctx, types.ModuleFilter{Deleted: filter.StateInclusive})
req.NoError(err)
req.Len(set, count) // we've deleted one
// search for deleted only
set, f, err = s.SearchComposeModules(ctx, types.ModuleFilter{Deleted: filter.StateExclusive})
req.NoError(err)
req.Len(set, 1) // we've deleted one
set, f, err = s.SearchComposeModules(ctx, types.ModuleFilter{Handle: "module-2-1"})
req.NoError(err)
req.Len(set, 1)
// find all prefixed
set, f, err = s.SearchComposeModules(ctx, types.ModuleFilter{Query: "/two-"})
req.NoError(err)
req.Len(set, 2)
_ = f // dummy
})
}

View File

@@ -0,0 +1,177 @@
package tests
import (
"context"
"testing"
"time"
"github.com/cortezaproject/corteza/server/compose/types"
"github.com/cortezaproject/corteza/server/pkg/filter"
"github.com/cortezaproject/corteza/server/pkg/id"
"github.com/cortezaproject/corteza/server/pkg/rand"
"github.com/cortezaproject/corteza/server/store"
"github.com/stretchr/testify/require"
)
func testComposeNamespaces(t *testing.T, s store.ComposeNamespaces) {
var (
ctx = context.Background()
req = require.New(t)
makeNew = func(name, slug string) *types.Namespace {
// minimum data set for new composeNamespace
return &types.Namespace{
ID: id.Next(),
CreatedAt: time.Now(),
Name: name,
Slug: slug,
}
}
truncAndCreate = func(t *testing.T) (*require.Assertions, *types.Namespace) {
req := require.New(t)
req.NoError(s.TruncateComposeNamespaces(ctx))
res := makeNew(string(rand.Bytes(10)), string(rand.Bytes(10)))
req.NoError(s.CreateComposeNamespace(ctx, res))
return req, res
}
)
t.Run("create", func(t *testing.T) {
req.NoError(s.TruncateComposeNamespaces(ctx))
composeNamespace := makeNew("ComposeNamespaceCRUD", "compose-namespace-crud")
req.NoError(s.CreateComposeNamespace(ctx, composeNamespace))
})
t.Run("create with duplicate slug", func(t *testing.T) {
t.Skip("not implemented")
})
t.Run("lookup", func(t *testing.T) {
t.Run("by ID", func(t *testing.T) {
req, composeNamespace := truncAndCreate(t)
fetched, err := s.LookupComposeNamespaceByID(ctx, composeNamespace.ID)
req.NoError(err)
req.Equal(composeNamespace.Name, fetched.Name)
req.Equal(composeNamespace.ID, fetched.ID)
req.NotNil(fetched.CreatedAt)
req.Nil(fetched.UpdatedAt)
req.Nil(fetched.DeletedAt)
})
t.Run("by Slug", func(t *testing.T) {
req, composeNamespace := truncAndCreate(t)
fetched, err := s.LookupComposeNamespaceBySlug(ctx, composeNamespace.Slug)
req.NoError(err)
req.Equal(composeNamespace.Name, fetched.Name)
req.Equal(composeNamespace.ID, fetched.ID)
req.NotNil(fetched.CreatedAt)
req.Nil(fetched.UpdatedAt)
req.Nil(fetched.DeletedAt)
})
})
t.Run("update", func(t *testing.T) {
composeNamespace := makeNew("update me", "update-me")
req.NoError(s.CreateComposeNamespace(ctx, composeNamespace))
composeNamespace = &types.Namespace{
ID: composeNamespace.ID,
CreatedAt: composeNamespace.CreatedAt,
Name: "ComposeNamespaceCRUD+2",
}
req.NoError(s.UpdateComposeNamespace(ctx, composeNamespace))
updated, err := s.LookupComposeNamespaceByID(ctx, composeNamespace.ID)
req.NoError(err)
req.Equal(composeNamespace.Name, updated.Name)
})
t.Run("update with duplicate slug", func(t *testing.T) {
t.Skip("not implemented")
})
t.Run("upsert", func(t *testing.T) {
t.Run("existing", func(t *testing.T) {
req, composeNamespace := truncAndCreate(t)
composeNamespace.Name = "ComposeNamespaceCRUD+2"
req.NoError(s.UpsertComposeNamespace(ctx, composeNamespace))
upserted, err := s.LookupComposeNamespaceByID(ctx, composeNamespace.ID)
req.NoError(err)
req.Equal(composeNamespace.Name, upserted.Name)
})
t.Run("new", func(t *testing.T) {
composeNamespace := makeNew("upsert me", "upsert-me")
composeNamespace.Name = "ComposeNamespaceCRUD+3"
req.NoError(s.UpsertComposeNamespace(ctx, composeNamespace))
upserted, err := s.LookupComposeNamespaceByID(ctx, composeNamespace.ID)
req.NoError(err)
req.Equal(composeNamespace.Name, upserted.Name)
})
})
t.Run("delete", func(t *testing.T) {
t.Run("by Namespace", func(t *testing.T) {
req, composeNamespace := truncAndCreate(t)
req.NoError(s.DeleteComposeNamespace(ctx, composeNamespace))
_, err := s.LookupComposeNamespaceByID(ctx, composeNamespace.ID)
req.EqualError(err, store.ErrNotFound.Error())
})
t.Run("by ID", func(t *testing.T) {
req, composeNamespace := truncAndCreate(t)
req.NoError(s.DeleteComposeNamespaceByID(ctx, composeNamespace.ID))
_, err := s.LookupComposeNamespaceByID(ctx, composeNamespace.ID)
req.EqualError(err, store.ErrNotFound.Error())
})
})
t.Run("search", func(t *testing.T) {
prefill := []*types.Namespace{
makeNew("/one-one", "namespace-1-1"),
makeNew("/one-two", "namespace-1-2"),
makeNew("/two-one", "namespace-2-1"),
makeNew("/two-two", "namespace-2-2"),
makeNew("/two-deleted", "namespace-2-d"),
}
count := len(prefill)
prefill[4].DeletedAt = &prefill[4].CreatedAt
valid := count - 1
req.NoError(s.TruncateComposeNamespaces(ctx))
req.NoError(s.CreateComposeNamespace(ctx, prefill...))
// search for all valid
set, f, err := s.SearchComposeNamespaces(ctx, types.NamespaceFilter{})
req.NoError(err)
req.Len(set, valid) // we've deleted one
// search for ALL
set, f, err = s.SearchComposeNamespaces(ctx, types.NamespaceFilter{Deleted: filter.StateInclusive})
req.NoError(err)
req.Len(set, count) // we've deleted one
// search for deleted only
set, f, err = s.SearchComposeNamespaces(ctx, types.NamespaceFilter{Deleted: filter.StateExclusive})
req.NoError(err)
req.Len(set, 1) // we've deleted one
set, f, err = s.SearchComposeNamespaces(ctx, types.NamespaceFilter{Slug: "namespace-2-1"})
req.NoError(err)
req.Len(set, 1)
// find all prefixed
set, f, err = s.SearchComposeNamespaces(ctx, types.NamespaceFilter{Query: "/two-"})
req.NoError(err)
req.Len(set, 2)
_ = f // dummy
})
}

View File

@@ -0,0 +1,194 @@
package tests
import (
"context"
"testing"
"time"
"github.com/cortezaproject/corteza/server/compose/types"
"github.com/cortezaproject/corteza/server/pkg/filter"
"github.com/cortezaproject/corteza/server/pkg/id"
"github.com/cortezaproject/corteza/server/pkg/rand"
"github.com/cortezaproject/corteza/server/store"
"github.com/stretchr/testify/require"
)
func testComposePageLayouts(t *testing.T, s store.ComposePageLayouts) {
var (
ctx = context.Background()
req = require.New(t)
namespaceID = id.Next()
makeNew = func(title, handle string) *types.PageLayout {
// minimum data set for new composePageLayout
return &types.PageLayout{
ID: id.Next(),
NamespaceID: namespaceID,
CreatedAt: time.Now(),
Meta: types.PageLayoutMeta{
Title: title,
},
Handle: handle,
}
}
truncAndCreate = func(t *testing.T) (*require.Assertions, *types.PageLayout) {
req := require.New(t)
req.NoError(s.TruncateComposePageLayouts(ctx))
res := makeNew(string(rand.Bytes(10)), string(rand.Bytes(10)))
req.NoError(s.CreateComposePageLayout(ctx, res))
return req, res
}
)
t.Run("create", func(t *testing.T) {
composePageLayout := makeNew("ComposePageLayoutCRUD", "compose-page-crud")
req.NoError(s.CreateComposePageLayout(ctx, composePageLayout))
})
t.Run("create with duplicate handle", func(t *testing.T) {
t.Skip("not implemented")
})
t.Run("lookup", func(t *testing.T) {
t.Run("lookup by ID", func(t *testing.T) {
req, composePageLayout := truncAndCreate(t)
fetched, err := s.LookupComposePageLayoutByID(ctx, composePageLayout.ID)
req.NoError(err)
req.Equal(composePageLayout.Meta.Title, fetched.Meta.Title)
req.Equal(composePageLayout.ID, fetched.ID)
req.NotNil(fetched.CreatedAt)
req.Nil(fetched.UpdatedAt)
req.Nil(fetched.DeletedAt)
})
t.Run("lookup by NamespaceID, PageID, Handle", func(t *testing.T) {
req, composePageLayout := truncAndCreate(t)
fetched, err := s.LookupComposePageLayoutByNamespaceIDPageIDHandle(ctx, composePageLayout.NamespaceID, composePageLayout.PageID, composePageLayout.Handle)
req.NoError(err)
req.Equal(composePageLayout.Meta.Title, fetched.Meta.Title)
req.Equal(composePageLayout.ID, fetched.ID)
req.NotNil(fetched.CreatedAt)
req.Nil(fetched.UpdatedAt)
req.Nil(fetched.DeletedAt)
})
t.Run("lookup by NamespaceID, Handle", func(t *testing.T) {
req, composePageLayout := truncAndCreate(t)
fetched, err := s.LookupComposePageLayoutByNamespaceIDHandle(ctx, composePageLayout.NamespaceID, composePageLayout.Handle)
req.NoError(err)
req.Equal(composePageLayout.Meta.Title, fetched.Meta.Title)
req.Equal(composePageLayout.ID, fetched.ID)
req.NotNil(fetched.CreatedAt)
req.Nil(fetched.UpdatedAt)
req.Nil(fetched.DeletedAt)
})
})
t.Run("update", func(t *testing.T) {
composePageLayout := makeNew("update me", "update-me")
req.NoError(s.CreateComposePageLayout(ctx, composePageLayout))
composePageLayout = &types.PageLayout{
ID: composePageLayout.ID,
CreatedAt: composePageLayout.CreatedAt,
Meta: types.PageLayoutMeta{
Title: "ComposePageLayoutCRUD+2",
},
}
req.NoError(s.UpdateComposePageLayout(ctx, composePageLayout))
updated, err := s.LookupComposePageLayoutByID(ctx, composePageLayout.ID)
req.NoError(err)
req.Equal(composePageLayout.Meta.Title, updated.Meta.Title)
})
t.Run("update with duplicate handle", func(t *testing.T) {
t.Skip("not implemented")
})
t.Run("upsert", func(t *testing.T) {
t.Run("existing", func(t *testing.T) {
req, composePageLayout := truncAndCreate(t)
composePageLayout.Meta.Title = "ComposePageLayoutCRUD+2"
req.NoError(s.UpsertComposePageLayout(ctx, composePageLayout))
upserted, err := s.LookupComposePageLayoutByID(ctx, composePageLayout.ID)
req.NoError(err)
req.Equal(composePageLayout.Meta.Title, upserted.Meta.Title)
})
t.Run("new", func(t *testing.T) {
composePageLayout := makeNew("upsert me", "upsert-me")
composePageLayout.Meta.Title = "ComposePageLayoutCRUD+2"
req.NoError(s.UpsertComposePageLayout(ctx, composePageLayout))
upserted, err := s.LookupComposePageLayoutByID(ctx, composePageLayout.ID)
req.NoError(err)
req.Equal(composePageLayout.Meta.Title, upserted.Meta.Title)
})
})
t.Run("delete", func(t *testing.T) {
t.Run("by PageLayout", func(t *testing.T) {
req, composePageLayout := truncAndCreate(t)
req.NoError(s.DeleteComposePageLayout(ctx, composePageLayout))
_, err := s.LookupComposePageLayoutByID(ctx, composePageLayout.ID)
req.EqualError(err, store.ErrNotFound.Error())
})
t.Run("by ID", func(t *testing.T) {
req, composePageLayout := truncAndCreate(t)
req.NoError(s.DeleteComposePageLayoutByID(ctx, composePageLayout.ID))
_, err := s.LookupComposePageLayoutByID(ctx, composePageLayout.ID)
req.EqualError(err, store.ErrNotFound.Error())
})
})
t.Run("search", func(t *testing.T) {
prefill := []*types.PageLayout{
makeNew("/one-one", "page-1-1"),
makeNew("/one-two", "page-1-2"),
makeNew("/two-one", "page-2-1"),
makeNew("/two-two", "page-2-2"),
makeNew("/two-deleted", "page-2-d"),
}
count := len(prefill)
prefill[4].DeletedAt = &prefill[4].CreatedAt
valid := count - 1
req.NoError(s.TruncateComposePageLayouts(ctx))
req.NoError(s.CreateComposePageLayout(ctx, prefill...))
// search for all valid
set, f, err := s.SearchComposePageLayouts(ctx, types.PageLayoutFilter{})
req.NoError(err)
req.Len(set, valid) // we've deleted one
// search for ALL
set, f, err = s.SearchComposePageLayouts(ctx, types.PageLayoutFilter{Deleted: filter.StateInclusive})
req.NoError(err)
req.Len(set, count) // we've deleted one
// search for deleted only
set, f, err = s.SearchComposePageLayouts(ctx, types.PageLayoutFilter{Deleted: filter.StateExclusive})
req.NoError(err)
req.Len(set, 1) // we've deleted one
set, f, err = s.SearchComposePageLayouts(ctx, types.PageLayoutFilter{Handle: "page-2-1"})
req.NoError(err)
req.Len(set, 1)
// find all prefixed
set, f, err = s.SearchComposePageLayouts(ctx, types.PageLayoutFilter{Query: "/two-"})
req.NoError(err)
req.Len(set, 2)
_ = f // dummy
})
}

View File

@@ -0,0 +1,191 @@
package tests
import (
"context"
"github.com/cortezaproject/corteza/server/compose/types"
"github.com/cortezaproject/corteza/server/pkg/filter"
"github.com/cortezaproject/corteza/server/pkg/id"
"github.com/cortezaproject/corteza/server/pkg/rand"
"github.com/cortezaproject/corteza/server/store"
"github.com/stretchr/testify/require"
"testing"
"time"
)
func testComposePages(t *testing.T, s store.ComposePages) {
var (
ctx = context.Background()
req = require.New(t)
namespaceID = id.Next()
moduleID = id.Next()
makeNew = func(title, handle string) *types.Page {
// minimum data set for new composePage
return &types.Page{
ID: id.Next(),
NamespaceID: namespaceID,
ModuleID: moduleID,
CreatedAt: time.Now(),
Title: title,
Handle: handle,
}
}
truncAndCreate = func(t *testing.T) (*require.Assertions, *types.Page) {
req := require.New(t)
req.NoError(s.TruncateComposePages(ctx))
res := makeNew(string(rand.Bytes(10)), string(rand.Bytes(10)))
req.NoError(s.CreateComposePage(ctx, res))
return req, res
}
)
t.Run("create", func(t *testing.T) {
composePage := makeNew("ComposePageCRUD", "compose-page-crud")
req.NoError(s.CreateComposePage(ctx, composePage))
})
t.Run("create with duplicate handle", func(t *testing.T) {
t.Skip("not implemented")
})
t.Run("lookup", func(t *testing.T) {
t.Run("lookup by ID", func(t *testing.T) {
req, composePage := truncAndCreate(t)
fetched, err := s.LookupComposePageByID(ctx, composePage.ID)
req.NoError(err)
req.Equal(composePage.Title, fetched.Title)
req.Equal(composePage.ID, fetched.ID)
req.NotNil(fetched.CreatedAt)
req.Nil(fetched.UpdatedAt)
req.Nil(fetched.DeletedAt)
})
t.Run("lookup by NamespaceID, ModuleID", func(t *testing.T) {
req, composePage := truncAndCreate(t)
fetched, err := s.LookupComposePageByNamespaceIDModuleID(ctx, composePage.NamespaceID, composePage.ModuleID)
req.NoError(err)
req.Equal(composePage.Title, fetched.Title)
req.Equal(composePage.ID, fetched.ID)
req.NotNil(fetched.CreatedAt)
req.Nil(fetched.UpdatedAt)
req.Nil(fetched.DeletedAt)
})
t.Run("lookup by NamespaceID, Handle", func(t *testing.T) {
req, composePage := truncAndCreate(t)
fetched, err := s.LookupComposePageByNamespaceIDHandle(ctx, composePage.NamespaceID, composePage.Handle)
req.NoError(err)
req.Equal(composePage.Title, fetched.Title)
req.Equal(composePage.ID, fetched.ID)
req.NotNil(fetched.CreatedAt)
req.Nil(fetched.UpdatedAt)
req.Nil(fetched.DeletedAt)
})
})
t.Run("update", func(t *testing.T) {
composePage := makeNew("update me", "update-me")
req.NoError(s.CreateComposePage(ctx, composePage))
composePage = &types.Page{
ID: composePage.ID,
CreatedAt: composePage.CreatedAt,
Title: "ComposePageCRUD+2",
}
req.NoError(s.UpdateComposePage(ctx, composePage))
updated, err := s.LookupComposePageByID(ctx, composePage.ID)
req.NoError(err)
req.Equal(composePage.Title, updated.Title)
})
t.Run("update with duplicate handle", func(t *testing.T) {
t.Skip("not implemented")
})
t.Run("upsert", func(t *testing.T) {
t.Run("existing", func(t *testing.T) {
req, composePage := truncAndCreate(t)
composePage.Title = "ComposePageCRUD+2"
req.NoError(s.UpsertComposePage(ctx, composePage))
upserted, err := s.LookupComposePageByID(ctx, composePage.ID)
req.NoError(err)
req.Equal(composePage.Title, upserted.Title)
})
t.Run("new", func(t *testing.T) {
composePage := makeNew("upsert me", "upsert-me")
composePage.Title = "ComposePageCRUD+2"
req.NoError(s.UpsertComposePage(ctx, composePage))
upserted, err := s.LookupComposePageByID(ctx, composePage.ID)
req.NoError(err)
req.Equal(composePage.Title, upserted.Title)
})
})
t.Run("delete", func(t *testing.T) {
t.Run("by Page", func(t *testing.T) {
req, composePage := truncAndCreate(t)
req.NoError(s.DeleteComposePage(ctx, composePage))
_, err := s.LookupComposePageByID(ctx, composePage.ID)
req.EqualError(err, store.ErrNotFound.Error())
})
t.Run("by ID", func(t *testing.T) {
req, composePage := truncAndCreate(t)
req.NoError(s.DeleteComposePageByID(ctx, composePage.ID))
_, err := s.LookupComposePageByID(ctx, composePage.ID)
req.EqualError(err, store.ErrNotFound.Error())
})
})
t.Run("search", func(t *testing.T) {
prefill := []*types.Page{
makeNew("/one-one", "page-1-1"),
makeNew("/one-two", "page-1-2"),
makeNew("/two-one", "page-2-1"),
makeNew("/two-two", "page-2-2"),
makeNew("/two-deleted", "page-2-d"),
}
count := len(prefill)
prefill[4].DeletedAt = &prefill[4].CreatedAt
valid := count - 1
req.NoError(s.TruncateComposePages(ctx))
req.NoError(s.CreateComposePage(ctx, prefill...))
// search for all valid
set, f, err := s.SearchComposePages(ctx, types.PageFilter{})
req.NoError(err)
req.Len(set, valid) // we've deleted one
// search for ALL
set, f, err = s.SearchComposePages(ctx, types.PageFilter{Deleted: filter.StateInclusive})
req.NoError(err)
req.Len(set, count) // we've deleted one
// search for deleted only
set, f, err = s.SearchComposePages(ctx, types.PageFilter{Deleted: filter.StateExclusive})
req.NoError(err)
req.Len(set, 1) // we've deleted one
set, f, err = s.SearchComposePages(ctx, types.PageFilter{Handle: "page-2-1"})
req.NoError(err)
req.Len(set, 1)
// find all prefixed
set, f, err = s.SearchComposePages(ctx, types.PageFilter{Query: "/two-"})
req.NoError(err)
req.Len(set, 2)
_ = f // dummy
})
}

View File

@@ -0,0 +1,148 @@
package tests
import (
"context"
"strings"
"testing"
"time"
"github.com/cortezaproject/corteza/server/pkg/id"
"github.com/cortezaproject/corteza/server/pkg/rand"
"github.com/cortezaproject/corteza/server/store"
// "github.com/cortezaproject/corteza/server/pkg/rh"
"github.com/cortezaproject/corteza/server/system/types"
_ "github.com/joho/godotenv/autoload"
"github.com/stretchr/testify/require"
)
func testCredentials(t *testing.T, s store.Credentials) {
var (
ctx = context.Background()
makeNew = func(nn ...string) *types.Credential {
name := strings.Join(nn, "")
return &types.Credential{
ID: id.Next(),
OwnerID: id.Next(),
Kind: "test-kind" + name,
Credentials: name,
Label: "CredentialsCRUD" + name,
CreatedAt: time.Now(),
}
}
truncAndCreate = func(t *testing.T) (*require.Assertions, *types.Credential) {
req := require.New(t)
req.NoError(s.TruncateCredentials(ctx))
credentials := makeNew()
req.NoError(s.CreateCredential(ctx, credentials))
return req, credentials
}
truncAndFill = func(t *testing.T, l int) (*require.Assertions, types.CredentialSet) {
req := require.New(t)
req.NoError(s.TruncateCredentials(ctx))
set := make([]*types.Credential, l)
for i := 0; i < l; i++ {
set[i] = makeNew(string(rand.Bytes(10)))
}
req.NoError(s.CreateCredential(ctx, set...))
return req, set
}
)
t.Run("create", func(t *testing.T) {
req := require.New(t)
req.NoError(s.CreateCredential(ctx, makeNew()))
})
t.Run("lookup by ID", func(t *testing.T) {
req, crd := truncAndCreate(t)
fetched, err := s.LookupCredentialByID(ctx, crd.ID)
req.NoError(err)
req.Equal(crd.ID, fetched.ID)
req.NotNil(fetched.CreatedAt)
req.Nil(fetched.UpdatedAt)
req.Nil(fetched.DeletedAt)
})
t.Run("update", func(t *testing.T) {
req, crd := truncAndCreate(t)
crd.Credentials = "new-credentials"
req.NoError(s.UpdateCredential(ctx, crd))
fetched, err := s.LookupCredentialByID(ctx, crd.ID)
req.NoError(err)
req.Equal("new-credentials", fetched.Credentials)
})
t.Run("update", func(t *testing.T) {
req, crd := truncAndCreate(t)
crd.Credentials = "new-credentials"
req.NoError(s.UpdateCredential(ctx, crd))
fetched, err := s.LookupCredentialByID(ctx, crd.ID)
req.NoError(err)
req.Equal("new-credentials", fetched.Credentials)
})
t.Run("delete", func(t *testing.T) {
t.Run("by credentials", func(t *testing.T) {
req, crd := truncAndCreate(t)
req.NoError(s.DeleteCredential(ctx, crd))
set, _, err := s.SearchCredentials(ctx, types.CredentialFilter{OwnerID: crd.OwnerID})
req.NoError(err)
req.Len(set, 0)
})
t.Run("by ID", func(t *testing.T) {
req, crd := truncAndCreate(t)
req.NoError(s.DeleteCredentialByID(ctx, crd.ID))
set, _, err := s.SearchCredentials(ctx, types.CredentialFilter{OwnerID: crd.OwnerID})
req.NoError(err)
req.Len(set, 0)
})
})
t.Run("search", func(t *testing.T) {
t.Run("by owner", func(t *testing.T) {
req, prefill := truncAndFill(t, 5)
set, _, err := s.SearchCredentials(ctx, types.CredentialFilter{OwnerID: prefill[0].OwnerID})
req.NoError(err)
req.Len(set, 1)
})
t.Run("by kind", func(t *testing.T) {
req, prefill := truncAndFill(t, 5)
set, _, err := s.SearchCredentials(ctx, types.CredentialFilter{Kind: prefill[0].Kind})
req.NoError(err)
req.Len(set, 1)
})
// Not sure why this doesnt work
// t.Run("by state", func(t *testing.T) {
// t.Run("deleted", func(t *testing.T) {
// req, prefill := truncAndFill(t, 5)
// time := time.Now()
// prefill[0].DeletedAt = &time
// req.NoError(s.DeleteCredentialsByID(ctx, prefill[0].ID))
// set, _, err := s.SearchCredentials(ctx, types.CredentialFilter{Deleted: filter.StateExcluded})
// req.NoError(err)
// req.Len(set, 4)
// set, _, err = s.SearchCredentials(ctx, types.CredentialFilter{Deleted: filter.StateInclusive})
// req.NoError(err)
// req.Len(set, 5)
// set, _, err = s.SearchCredentials(ctx, types.CredentialFilter{Deleted: filter.StateExclusive})
// req.NoError(err)
// req.Len(set, 1)
// })
// })
})
}

View File

@@ -0,0 +1,143 @@
package tests
import (
"context"
"testing"
"time"
"github.com/cortezaproject/corteza/server/pkg/filter"
"github.com/cortezaproject/corteza/server/pkg/id"
"github.com/cortezaproject/corteza/server/pkg/rand"
"github.com/cortezaproject/corteza/server/store"
"github.com/cortezaproject/corteza/server/system/types"
"github.com/stretchr/testify/require"
)
func testDalConnections(t *testing.T, s store.DalConnections) {
var (
ctx = context.Background()
req = require.New(t)
makeNew = func(handle string) *types.DalConnection {
// minimum data set for new dalConnection
return &types.DalConnection{
ID: id.Next(),
CreatedAt: time.Now(),
Handle: handle,
}
}
truncAndCreate = func(t *testing.T) (*require.Assertions, *types.DalConnection) {
req := require.New(t)
req.NoError(s.TruncateDalConnections(ctx))
res := makeNew(string(rand.Bytes(10)))
req.NoError(s.CreateDalConnection(ctx, res))
return req, res
}
)
t.Run("create", func(t *testing.T) {
req.NoError(s.TruncateDalConnections(ctx))
dalConnection := makeNew("DalConnectionCRUD")
req.NoError(s.CreateDalConnection(ctx, dalConnection))
})
t.Run("lookup by ID", func(t *testing.T) {
req, dalConnection := truncAndCreate(t)
fetched, err := s.LookupDalConnectionByID(ctx, dalConnection.ID)
req.NoError(err)
req.Equal(dalConnection.Handle, fetched.Handle)
req.Equal(dalConnection.ID, fetched.ID)
req.NotNil(fetched.CreatedAt)
req.Nil(fetched.UpdatedAt)
req.Nil(fetched.DeletedAt)
})
t.Run("update", func(t *testing.T) {
req, dalConnection := truncAndCreate(t)
dalConnection.Handle = "DalConnectionCRUD-2"
req.NoError(s.UpdateDalConnection(ctx, dalConnection))
updated, err := s.LookupDalConnectionByID(ctx, dalConnection.ID)
req.NoError(err)
req.Equal(dalConnection.Handle, updated.Handle)
})
t.Run("upsert", func(t *testing.T) {
t.Run("existing", func(t *testing.T) {
req, dalConnection := truncAndCreate(t)
dalConnection.Handle = "DalConnectionCRUD-2"
req.NoError(s.UpsertDalConnection(ctx, dalConnection))
updated, err := s.LookupDalConnectionByID(ctx, dalConnection.ID)
req.NoError(err)
req.Equal(dalConnection.Handle, updated.Handle)
})
t.Run("new", func(t *testing.T) {
dalConnection := makeNew("upsert me")
dalConnection.Handle = "ComposeChartCRUD-2"
req.NoError(s.UpsertDalConnection(ctx, dalConnection))
upserted, err := s.LookupDalConnectionByID(ctx, dalConnection.ID)
req.NoError(err)
req.Equal(dalConnection.Handle, upserted.Handle)
})
})
t.Run("delete", func(t *testing.T) {
t.Run("by DalConnection", func(t *testing.T) {
req, dalConnection := truncAndCreate(t)
req.NoError(s.DeleteDalConnection(ctx, dalConnection))
_, err := s.LookupDalConnectionByID(ctx, dalConnection.ID)
req.EqualError(err, store.ErrNotFound.Error())
})
t.Run("by ID", func(t *testing.T) {
req, dalConnection := truncAndCreate(t)
req.NoError(s.DeleteDalConnectionByID(ctx, dalConnection.ID))
_, err := s.LookupDalConnectionByID(ctx, dalConnection.ID)
req.EqualError(err, store.ErrNotFound.Error())
})
})
t.Run("search", func(t *testing.T) {
prefill := []*types.DalConnection{
makeNew("/one-one"),
makeNew("/one-two"),
makeNew("/two-one"),
makeNew("/two-two"),
makeNew("/two-deleted"),
}
count := len(prefill)
prefill[4].DeletedAt = &prefill[4].CreatedAt
valid := count - 1
req.NoError(s.TruncateDalConnections(ctx))
req.NoError(s.CreateDalConnection(ctx, prefill...))
// search for all valid
set, _, err := s.SearchDalConnections(ctx, types.DalConnectionFilter{})
req.NoError(err)
req.Len(set, valid) // we've deleted one
// search for ALL
set, _, err = s.SearchDalConnections(ctx, types.DalConnectionFilter{Deleted: filter.StateInclusive})
req.NoError(err)
req.Len(set, count) // we've deleted one
// search for deleted only
set, _, err = s.SearchDalConnections(ctx, types.DalConnectionFilter{Deleted: filter.StateExclusive})
req.NoError(err)
req.Len(set, 1) // we've deleted one
set, _, err = s.SearchDalConnections(ctx, types.DalConnectionFilter{Handle: "/two-one"})
req.NoError(err)
req.Len(set, 1)
})
}

View File

@@ -0,0 +1,10 @@
package tests
import (
"testing"
"github.com/cortezaproject/corteza/server/store"
)
func testDalSchemaAlterations(t *testing.T, s store.DalSensitivityLevels) {
}

View File

@@ -0,0 +1,138 @@
package tests
import (
"context"
"testing"
"time"
"github.com/cortezaproject/corteza/server/pkg/filter"
"github.com/cortezaproject/corteza/server/pkg/id"
"github.com/cortezaproject/corteza/server/pkg/rand"
"github.com/cortezaproject/corteza/server/store"
"github.com/cortezaproject/corteza/server/system/types"
"github.com/stretchr/testify/require"
)
func testDalSensitivityLevels(t *testing.T, s store.DalSensitivityLevels) {
var (
ctx = context.Background()
req = require.New(t)
makeNew = func(handle string) *types.DalSensitivityLevel {
// minimum data set for new dalSensitivityLevel
return &types.DalSensitivityLevel{
ID: id.Next(),
CreatedAt: time.Now(),
Handle: handle,
}
}
truncAndCreate = func(t *testing.T) (*require.Assertions, *types.DalSensitivityLevel) {
req := require.New(t)
req.NoError(s.TruncateDalSensitivityLevels(ctx))
res := makeNew(string(rand.Bytes(10)))
req.NoError(s.CreateDalSensitivityLevel(ctx, res))
return req, res
}
)
t.Run("create", func(t *testing.T) {
dalSensitivityLevel := makeNew("DalSensitivityLevelCRUD")
req.NoError(s.CreateDalSensitivityLevel(ctx, dalSensitivityLevel))
})
t.Run("lookup by ID", func(t *testing.T) {
req, dalSensitivityLevel := truncAndCreate(t)
fetched, err := s.LookupDalSensitivityLevelByID(ctx, dalSensitivityLevel.ID)
req.NoError(err)
req.Equal(dalSensitivityLevel.Handle, fetched.Handle)
req.Equal(dalSensitivityLevel.ID, fetched.ID)
req.NotNil(fetched.CreatedAt)
req.Nil(fetched.UpdatedAt)
req.Nil(fetched.DeletedAt)
})
t.Run("update", func(t *testing.T) {
req, dalSensitivityLevel := truncAndCreate(t)
dalSensitivityLevel.Handle = "DalSensitivityLevelCRUD-2"
req.NoError(s.UpdateDalSensitivityLevel(ctx, dalSensitivityLevel))
updated, err := s.LookupDalSensitivityLevelByID(ctx, dalSensitivityLevel.ID)
req.NoError(err)
req.Equal(dalSensitivityLevel.Handle, updated.Handle)
})
t.Run("upsert", func(t *testing.T) {
t.Run("existing", func(t *testing.T) {
req, dalSensitivityLevel := truncAndCreate(t)
dalSensitivityLevel.Handle = "DalSensitivityLevelCRUD-2"
req.NoError(s.UpsertDalSensitivityLevel(ctx, dalSensitivityLevel))
updated, err := s.LookupDalSensitivityLevelByID(ctx, dalSensitivityLevel.ID)
req.NoError(err)
req.Equal(dalSensitivityLevel.Handle, updated.Handle)
})
t.Run("new", func(t *testing.T) {
dalSensitivityLevel := makeNew("upsert me")
dalSensitivityLevel.Handle = "ComposeChartCRUD-2"
req.NoError(s.UpsertDalSensitivityLevel(ctx, dalSensitivityLevel))
upserted, err := s.LookupDalSensitivityLevelByID(ctx, dalSensitivityLevel.ID)
req.NoError(err)
req.Equal(dalSensitivityLevel.Handle, upserted.Handle)
})
})
t.Run("delete", func(t *testing.T) {
t.Run("by DalSensitivityLevel", func(t *testing.T) {
req, dalSensitivityLevel := truncAndCreate(t)
req.NoError(s.DeleteDalSensitivityLevel(ctx, dalSensitivityLevel))
_, err := s.LookupDalSensitivityLevelByID(ctx, dalSensitivityLevel.ID)
req.EqualError(err, store.ErrNotFound.Error())
})
t.Run("by ID", func(t *testing.T) {
req, dalSensitivityLevel := truncAndCreate(t)
req.NoError(s.DeleteDalSensitivityLevelByID(ctx, dalSensitivityLevel.ID))
_, err := s.LookupDalSensitivityLevelByID(ctx, dalSensitivityLevel.ID)
req.EqualError(err, store.ErrNotFound.Error())
})
})
t.Run("search", func(t *testing.T) {
prefill := []*types.DalSensitivityLevel{
makeNew("/one-one"),
makeNew("/one-two"),
makeNew("/two-one"),
makeNew("/two-two"),
makeNew("/two-deleted"),
}
count := len(prefill)
prefill[4].DeletedAt = &prefill[4].CreatedAt
valid := count - 1
req.NoError(s.TruncateDalSensitivityLevels(ctx))
req.NoError(s.CreateDalSensitivityLevel(ctx, prefill...))
// search for all valid
set, _, err := s.SearchDalSensitivityLevels(ctx, types.DalSensitivityLevelFilter{})
req.NoError(err)
req.Len(set, valid) // we've deleted one
// search for ALL
set, _, err = s.SearchDalSensitivityLevels(ctx, types.DalSensitivityLevelFilter{Deleted: filter.StateInclusive})
req.NoError(err)
req.Len(set, count) // we've deleted one
// search for deleted only
set, _, err = s.SearchDalSensitivityLevels(ctx, types.DalSensitivityLevelFilter{Deleted: filter.StateExclusive})
req.NoError(err)
req.Len(set, 1) // we've deleted one
})
}

View File

@@ -0,0 +1,97 @@
package tests
import (
"context"
"testing"
"time"
"github.com/cortezaproject/corteza/server/pkg/id"
"github.com/cortezaproject/corteza/server/pkg/rand"
"github.com/cortezaproject/corteza/server/store"
"github.com/cortezaproject/corteza/server/system/types"
"github.com/stretchr/testify/require"
)
func testDataPrivacyRequestComments(t *testing.T, s store.DataPrivacyRequestComments) {
var (
ctx = context.Background()
req = require.New(t)
makeNew = func(handle string) *types.DataPrivacyRequestComment {
// minimum data set for new dataPrivacyRequestComment
return &types.DataPrivacyRequestComment{
ID: id.Next(),
CreatedAt: time.Now(),
}
}
truncAndCreate = func(t *testing.T) (*require.Assertions, *types.DataPrivacyRequestComment) {
req := require.New(t)
req.NoError(s.TruncateDataPrivacyRequestComments(ctx))
res := makeNew(string(rand.Bytes(10)))
req.NoError(s.CreateDataPrivacyRequestComment(ctx, res))
return req, res
}
)
t.Run("create", func(t *testing.T) {
dataPrivacyRequestComment := makeNew("DataPrivacyRequestCommentCRUD")
req.NoError(s.CreateDataPrivacyRequestComment(ctx, dataPrivacyRequestComment))
})
t.Run("update", func(t *testing.T) {
req, dataPrivacyRequestComment := truncAndCreate(t)
dataPrivacyRequestComment.Comment = "DataPrivacyRequestCommentCRUD-2"
req.NoError(s.UpdateDataPrivacyRequestComment(ctx, dataPrivacyRequestComment))
})
t.Run("upsert", func(t *testing.T) {
t.Run("existing", func(t *testing.T) {
req, dataPrivacyRequestComment := truncAndCreate(t)
dataPrivacyRequestComment.Comment = "DataPrivacyRequestCommentCRUD-2"
req.NoError(s.UpsertDataPrivacyRequestComment(ctx, dataPrivacyRequestComment))
})
t.Run("new", func(t *testing.T) {
dataPrivacyRequestComment := makeNew("upsert me")
dataPrivacyRequestComment.Comment = "ComposeChartCRUD-2"
req.NoError(s.UpsertDataPrivacyRequestComment(ctx, dataPrivacyRequestComment))
})
})
t.Run("delete", func(t *testing.T) {
t.Run("by DataPrivacyRequestComment", func(t *testing.T) {
req, dataPrivacyRequestComment := truncAndCreate(t)
req.NoError(s.DeleteDataPrivacyRequestComment(ctx, dataPrivacyRequestComment))
})
t.Run("by ID", func(t *testing.T) {
req, dataPrivacyRequestComment := truncAndCreate(t)
req.NoError(s.DeleteDataPrivacyRequestCommentByID(ctx, dataPrivacyRequestComment.ID))
})
})
t.Run("search", func(t *testing.T) {
prefill := []*types.DataPrivacyRequestComment{
makeNew("/one-one"),
makeNew("/one-two"),
makeNew("/two-one"),
makeNew("/two-two"),
makeNew("/two-yes"),
}
count := len(prefill)
valid := count
req.NoError(s.TruncateDataPrivacyRequestComments(ctx))
req.NoError(s.CreateDataPrivacyRequestComment(ctx, prefill...))
// search for all valid
set, _, err := s.SearchDataPrivacyRequestComments(ctx, types.DataPrivacyRequestCommentFilter{})
req.NoError(err)
req.Len(set, valid) // we've deleted one
})
}

View File

@@ -0,0 +1,131 @@
package tests
import (
"context"
"testing"
"time"
"github.com/cortezaproject/corteza/server/pkg/id"
"github.com/cortezaproject/corteza/server/pkg/rand"
"github.com/cortezaproject/corteza/server/store"
"github.com/cortezaproject/corteza/server/system/types"
"github.com/stretchr/testify/require"
)
func testDataPrivacyRequests(t *testing.T, s store.DataPrivacyRequests) {
var (
ctx = context.Background()
req = require.New(t)
makeNew = func(handle string) *types.DataPrivacyRequest {
// minimum data set for new dataPrivacyRequest
return &types.DataPrivacyRequest{
ID: id.Next(),
CreatedAt: time.Now(),
RequestedAt: time.Now(),
Kind: types.RequestKindCorrect,
}
}
truncAndCreate = func(t *testing.T) (*require.Assertions, *types.DataPrivacyRequest) {
req := require.New(t)
req.NoError(s.TruncateDataPrivacyRequests(ctx))
res := makeNew(string(rand.Bytes(10)))
req.NoError(s.CreateDataPrivacyRequest(ctx, res))
return req, res
}
)
t.Run("create", func(t *testing.T) {
dataPrivacyRequest := makeNew("DataPrivacyRequestCRUD")
req.NoError(s.CreateDataPrivacyRequest(ctx, dataPrivacyRequest))
})
t.Run("lookup by ID", func(t *testing.T) {
req, dataPrivacyRequest := truncAndCreate(t)
fetched, err := s.LookupDataPrivacyRequestByID(ctx, dataPrivacyRequest.ID)
req.NoError(err)
req.Equal(dataPrivacyRequest.Kind, fetched.Kind)
req.Equal(dataPrivacyRequest.ID, fetched.ID)
req.NotNil(fetched.CreatedAt)
req.Nil(fetched.UpdatedAt)
req.Nil(fetched.DeletedAt)
})
t.Run("update", func(t *testing.T) {
req, dataPrivacyRequest := truncAndCreate(t)
dataPrivacyRequest.Kind = types.RequestKindDelete
req.NoError(s.UpdateDataPrivacyRequest(ctx, dataPrivacyRequest))
updated, err := s.LookupDataPrivacyRequestByID(ctx, dataPrivacyRequest.ID)
req.NoError(err)
req.Equal(dataPrivacyRequest.Kind, updated.Kind)
})
t.Run("upsert", func(t *testing.T) {
t.Run("existing", func(t *testing.T) {
req, dataPrivacyRequest := truncAndCreate(t)
dataPrivacyRequest.Kind = types.RequestKindDelete
req.NoError(s.UpsertDataPrivacyRequest(ctx, dataPrivacyRequest))
updated, err := s.LookupDataPrivacyRequestByID(ctx, dataPrivacyRequest.ID)
req.NoError(err)
req.Equal(dataPrivacyRequest.Kind, updated.Kind)
})
t.Run("new", func(t *testing.T) {
dataPrivacyRequest := makeNew("upsert me")
dataPrivacyRequest.Kind = "ComposeChartCRUD-2"
req.NoError(s.UpsertDataPrivacyRequest(ctx, dataPrivacyRequest))
upserted, err := s.LookupDataPrivacyRequestByID(ctx, dataPrivacyRequest.ID)
req.NoError(err)
req.Equal(dataPrivacyRequest.Kind, upserted.Kind)
})
})
t.Run("delete", func(t *testing.T) {
t.Run("by DataPrivacyRequest", func(t *testing.T) {
req, dataPrivacyRequest := truncAndCreate(t)
req.NoError(s.DeleteDataPrivacyRequest(ctx, dataPrivacyRequest))
_, err := s.LookupDataPrivacyRequestByID(ctx, dataPrivacyRequest.ID)
req.EqualError(err, store.ErrNotFound.Error())
})
t.Run("by ID", func(t *testing.T) {
req, dataPrivacyRequest := truncAndCreate(t)
req.NoError(s.DeleteDataPrivacyRequestByID(ctx, dataPrivacyRequest.ID))
_, err := s.LookupDataPrivacyRequestByID(ctx, dataPrivacyRequest.ID)
req.EqualError(err, store.ErrNotFound.Error())
})
})
t.Run("search", func(t *testing.T) {
prefill := []*types.DataPrivacyRequest{
makeNew("/one-one"),
makeNew("/one-two"),
makeNew("/two-one"),
makeNew("/two-two"),
}
prefill[3].Kind = types.RequestKindDelete
count := len(prefill)
valid := count
req.NoError(s.TruncateDataPrivacyRequests(ctx))
req.NoError(s.CreateDataPrivacyRequest(ctx, prefill...))
// search for all valid
set, _, err := s.SearchDataPrivacyRequests(ctx, types.DataPrivacyRequestFilter{})
req.NoError(err)
req.Len(set, valid) // we've deleted one
set, _, err = s.SearchDataPrivacyRequests(ctx, types.DataPrivacyRequestFilter{Kind: []string{"delete"}})
req.NoError(err)
req.Len(set, 1)
})
}

View File

@@ -0,0 +1,10 @@
package tests
import (
"github.com/cortezaproject/corteza/server/store"
"testing"
)
func testFederationExposedModules(t *testing.T, s store.FederationExposedModules) {
// @todo
}

View File

@@ -0,0 +1,10 @@
package tests
import (
"github.com/cortezaproject/corteza/server/store"
"testing"
)
func testFederationModuleMappings(t *testing.T, s store.FederationModuleMappings) {
// @todo
}

View File

@@ -0,0 +1,11 @@
package tests
import (
"testing"
"github.com/cortezaproject/corteza/server/store"
)
func testFederationNodeSyncs(t *testing.T, s store.FederationNodeSyncs) {
t.Skip("@todo")
}

View File

@@ -0,0 +1,144 @@
package tests
import (
"context"
"github.com/cortezaproject/corteza/server/federation/types"
"github.com/cortezaproject/corteza/server/pkg/filter"
"github.com/cortezaproject/corteza/server/pkg/id"
"github.com/cortezaproject/corteza/server/pkg/rand"
"github.com/cortezaproject/corteza/server/store"
"github.com/stretchr/testify/require"
"testing"
"time"
)
func testFederationNodes(t *testing.T, s store.FederationNodes) {
var (
ctx = context.Background()
req = require.New(t)
makeNew = func(name string) *types.Node {
// minimum data set for new FederationNode
return &types.Node{
ID: id.Next(),
CreatedAt: time.Now(),
Name: name,
}
}
truncAndCreate = func(t *testing.T) (*require.Assertions, *types.Node) {
req := require.New(t)
req.NoError(s.TruncateFederationNodes(ctx))
res := makeNew(string(rand.Bytes(10)))
req.NoError(s.CreateFederationNode(ctx, res))
return req, res
}
)
t.Run("create", func(t *testing.T) {
FederationNode := makeNew("FederationNodeCRUD")
req.NoError(s.CreateFederationNode(ctx, FederationNode))
})
t.Run("lookup by ID", func(t *testing.T) {
req, FederationNode := truncAndCreate(t)
fetched, err := s.LookupFederationNodeByID(ctx, FederationNode.ID)
req.NoError(err)
req.Equal(FederationNode.Name, fetched.Name)
req.Equal(FederationNode.ID, fetched.ID)
req.NotNil(fetched.CreatedAt)
req.Nil(fetched.UpdatedAt)
req.Nil(fetched.DeletedAt)
})
t.Run("update", func(t *testing.T) {
req, FederationNode := truncAndCreate(t)
FederationNode.Name = "FederationNodeCRUD+2"
req.NoError(s.UpdateFederationNode(ctx, FederationNode))
updated, err := s.LookupFederationNodeByID(ctx, FederationNode.ID)
req.NoError(err)
req.Equal(FederationNode.Name, updated.Name)
})
t.Run("upsert", func(t *testing.T) {
t.Run("existing", func(t *testing.T) {
req, FederationNode := truncAndCreate(t)
FederationNode.Name = "FederationNodeCRUD+2"
req.NoError(s.UpsertFederationNode(ctx, FederationNode))
updated, err := s.LookupFederationNodeByID(ctx, FederationNode.ID)
req.NoError(err)
req.Equal(FederationNode.Name, updated.Name)
})
t.Run("new", func(t *testing.T) {
FederationNode := makeNew("upsert me")
FederationNode.Name = "ComposeChartCRUD+2"
req.NoError(s.UpsertFederationNode(ctx, FederationNode))
upserted, err := s.LookupFederationNodeByID(ctx, FederationNode.ID)
req.NoError(err)
req.Equal(FederationNode.Name, upserted.Name)
})
})
t.Run("delete", func(t *testing.T) {
t.Run("by FederationNode", func(t *testing.T) {
req, FederationNode := truncAndCreate(t)
req.NoError(s.DeleteFederationNode(ctx, FederationNode))
_, err := s.LookupFederationNodeByID(ctx, FederationNode.ID)
req.EqualError(err, store.ErrNotFound.Error())
})
t.Run("by ID", func(t *testing.T) {
req, FederationNode := truncAndCreate(t)
req.NoError(s.DeleteFederationNodeByID(ctx, FederationNode.ID))
_, err := s.LookupFederationNodeByID(ctx, FederationNode.ID)
req.EqualError(err, store.ErrNotFound.Error())
})
})
t.Run("search", func(t *testing.T) {
prefill := []*types.Node{
makeNew("/one-one"),
makeNew("/one-two"),
makeNew("/two-one"),
makeNew("/two-two"),
makeNew("/two-deleted"),
}
count := len(prefill)
prefill[4].DeletedAt = &prefill[4].CreatedAt
valid := count - 1
req.NoError(s.TruncateFederationNodes(ctx))
req.NoError(s.CreateFederationNode(ctx, prefill...))
// search for all valid
set, f, err := s.SearchFederationNodes(ctx, types.NodeFilter{})
req.NoError(err)
req.Len(set, valid) // we've deleted one
// search for ALL
set, f, err = s.SearchFederationNodes(ctx, types.NodeFilter{Deleted: filter.StateInclusive})
req.NoError(err)
req.Len(set, count) // we've deleted one
// search for deleted only
set, f, err = s.SearchFederationNodes(ctx, types.NodeFilter{Deleted: filter.StateExclusive})
req.NoError(err)
req.Len(set, 1) // we've deleted one
// find all prefixed
set, f, err = s.SearchFederationNodes(ctx, types.NodeFilter{Query: "/two"})
req.NoError(err)
req.Len(set, 2)
_ = f // dummy
})
}

View File

@@ -0,0 +1,10 @@
package tests
import (
"github.com/cortezaproject/corteza/server/store"
"testing"
)
func testFederationSharedModules(t *testing.T, s store.FederationSharedModules) {
// @todo
}

View File

@@ -0,0 +1,53 @@
package tests
import (
"context"
"testing"
"github.com/cortezaproject/corteza/server/pkg/flag/types"
"github.com/cortezaproject/corteza/server/store"
_ "github.com/joho/godotenv/autoload"
"github.com/stretchr/testify/require"
)
func testFlags(t *testing.T, s store.Flags) {
var (
ctx = context.Background()
)
t.Run("create", func(t *testing.T) {
req := require.New(t)
req.NoError(s.TruncateFlags(ctx))
req.NoError(s.CreateFlag(ctx, &types.Flag{
Kind: "kind",
ResourceID: 1,
OwnedBy: 2,
Name: "fname",
Active: true,
}))
})
t.Run("update", func(t *testing.T) {
req := require.New(t)
req.NoError(s.TruncateFlags(ctx))
req.NoError(s.UpdateFlag(ctx, &types.Flag{
Kind: "kind",
ResourceID: 1,
OwnedBy: 2,
Name: "fname",
Active: false,
}))
})
t.Run("upsert", func(t *testing.T) {
req := require.New(t)
req.NoError(s.TruncateFlags(ctx))
req.NoError(s.UpsertFlag(ctx, &types.Flag{
Kind: "kind",
ResourceID: 1,
OwnedBy: 2,
Name: "fname",
Active: true,
}))
})
}

View File

@@ -0,0 +1,53 @@
package tests
import (
"context"
"testing"
"github.com/cortezaproject/corteza/server/pkg/label/types"
"github.com/cortezaproject/corteza/server/pkg/logger"
"github.com/cortezaproject/corteza/server/store"
_ "github.com/joho/godotenv/autoload"
"github.com/stretchr/testify/require"
)
func testLabels(t *testing.T, s store.Labels) {
var (
ctx = context.Background()
)
ctx = logger.ContextWithValue(ctx, logger.MakeDebugLogger())
t.Run("create", func(t *testing.T) {
req := require.New(t)
req.NoError(s.TruncateLabels(ctx))
req.NoError(s.CreateLabel(ctx, &types.Label{
Kind: "kind",
ResourceID: 1,
Name: "lname",
Value: types.LabelValue{Val: "lvalue"},
}))
})
t.Run("update", func(t *testing.T) {
req := require.New(t)
req.NoError(s.TruncateLabels(ctx))
req.NoError(s.UpdateLabel(ctx, &types.Label{
Kind: "kind",
ResourceID: 1,
Name: "lname",
Value: types.LabelValue{Val: "lvalue"},
}))
})
t.Run("upsert", func(t *testing.T) {
req := require.New(t)
req.NoError(s.TruncateLabels(ctx))
req.NoError(s.UpsertLabel(ctx, &types.Label{
Kind: "kind",
ResourceID: 1,
Name: "lname",
Value: types.LabelValue{Val: "lvalue"},
}))
})
}

View File

@@ -0,0 +1,106 @@
package tests
import (
"context"
"os"
"testing"
"time"
"github.com/cortezaproject/corteza/server/pkg/cli"
"github.com/cortezaproject/corteza/server/pkg/id"
"github.com/cortezaproject/corteza/server/store"
"github.com/cortezaproject/corteza/server/store/adapters/rdbms/drivers/mssql"
"github.com/cortezaproject/corteza/server/store/adapters/rdbms/drivers/mysql"
"github.com/cortezaproject/corteza/server/store/adapters/rdbms/drivers/postgres"
"github.com/cortezaproject/corteza/server/store/adapters/rdbms/drivers/sqlite"
"github.com/cortezaproject/corteza/server/tests/helpers"
_ "github.com/joho/godotenv/autoload"
"go.uber.org/zap"
)
var (
now = func() *time.Time {
n := time.Now().Round(time.Second)
return &n
}
)
func init() {
helpers.RecursiveDotEnvLoad()
id.Init(cli.Context())
}
func Test_RDBMS_SQLITE(t *testing.T) {
testAllGenerated(t, setup(t, sqlite.Connect))
}
func Test_RDBMS_MYSQL(t *testing.T) {
testAllGenerated(t, setup(t, mysql.Connect))
}
func Test_RDBMS_SQLSERVER_2022(t *testing.T) {
testAllGenerated(t, setup(t, mssql.Connect))
}
func Test_RDBMS_SQLSERVER_2019(t *testing.T) {
testAllGenerated(t, setup(t, mssql.Connect))
}
func Test_RDBMS_SQLSERVER_2017(t *testing.T) {
testAllGenerated(t, setup(t, mssql.Connect))
}
func Test_RDBMS_PGSQL(t *testing.T) {
testAllGenerated(t, setup(t, postgres.Connect))
}
func Test_RDBMS_COCKROACHDB(t *testing.T) {
testAllGenerated(t, setup(t, nil))
}
func Test_MEMORY(t *testing.T) {
testAllGenerated(t, setup(t, nil))
}
func Test_MONGODB(t *testing.T) {
testAllGenerated(t, setup(t, nil))
}
func Test_ELASTICSEARCH(t *testing.T) {
testAllGenerated(t, setup(t, nil))
}
func setup(t *testing.T, connect store.ConnectorFn) (s store.Storer) {
t.Parallel()
if connect == nil {
t.Skipf("connection function not set, skipping tests")
return
}
var (
err error
env = t.Name()[5:] + "_DSN"
dsn, has = os.LookupEnv(env)
ctx = context.Background()
)
if !has || len(dsn) == 0 {
t.Skipf("no %s found, skipping tests", env)
return
}
s, err = connect(ctx, dsn)
if err != nil {
t.Errorf("failed to initialize: %v", err)
return
}
err = store.Upgrade(ctx, zap.NewNop(), s)
if err != nil {
t.Fatalf("failed to upgrade : %v", err)
return
}
return s
}

View File

@@ -0,0 +1,178 @@
package tests
import (
"context"
"testing"
"time"
"github.com/cortezaproject/corteza/server/pkg/filter"
"github.com/cortezaproject/corteza/server/pkg/id"
"github.com/cortezaproject/corteza/server/pkg/rand"
"github.com/cortezaproject/corteza/server/store"
"github.com/cortezaproject/corteza/server/system/types"
_ "github.com/joho/godotenv/autoload"
"github.com/stretchr/testify/require"
)
func testNotifications(t *testing.T, s store.Notifications) {
var (
ctx = context.Background()
makeNew = func(nn ...string) *types.Notification {
// minimum data set for new notification
thisID := id.Next()
return &types.Notification{
ID: thisID,
Kind: types.NotificationKindSimple,
Config: types.NotificationConfig{
Simple: types.SimpleNotificationConfig{
Title: "Test Notification",
Description: "This is a test notification",
},
},
Recipient: thisID,
CreatedAt: time.Now(),
CreatedBy: thisID,
}
}
truncAndCreate = func(t *testing.T) (*require.Assertions, *types.Notification) {
req := require.New(t)
req.NoError(s.TruncateNotifications(ctx))
notification := makeNew()
req.NoError(s.CreateNotification(ctx, notification))
return req, notification
}
truncAndFill = func(t *testing.T, l int) (*require.Assertions, types.NotificationSet) {
req := require.New(t)
req.NoError(s.TruncateNotifications(ctx))
set := make([]*types.Notification, l)
for i := 0; i < l; i++ {
set[i] = makeNew(string(rand.Bytes(10)))
}
req.NoError(s.CreateNotification(ctx, set...))
return req, set
}
)
t.Run("create", func(t *testing.T) {
req := require.New(t)
req.NoError(s.CreateNotification(ctx, makeNew()))
})
t.Run("lookup by ID", func(t *testing.T) {
req, notification := truncAndCreate(t)
fetched, err := s.LookupNotificationByID(ctx, notification.ID)
req.NoError(err)
req.Equal(notification.ID, fetched.ID)
req.NotNil(fetched.CreatedAt)
req.Nil(fetched.UpdatedAt)
req.Nil(fetched.DeletedAt)
})
t.Run("update", func(t *testing.T) {
req, notification := truncAndCreate(t)
req.NoError(s.UpdateNotification(ctx, notification))
})
t.Run("search", func(t *testing.T) {
t.Run("by ID", func(t *testing.T) {
req, prefill := truncAndFill(t, 5)
set, f, err := s.SearchNotifications(ctx, types.NotificationFilter{NotificationID: []uint64{prefill[0].ID}})
req.NoError(err)
req.Equal([]uint64{prefill[0].ID}, f.NotificationID)
req.Len(set, 1)
})
t.Run("by kind", func(t *testing.T) {
req, prefill := truncAndFill(t, 5)
set, _, err := s.SearchNotifications(ctx, types.NotificationFilter{Kind: []types.NotificationKind{prefill[0].Kind}})
req.NoError(err)
req.Len(set, 5) // All have the same kind
})
t.Run("by recipient", func(t *testing.T) {
req, prefill := truncAndFill(t, 5)
set, f, err := s.SearchNotifications(ctx, types.NotificationFilter{Recipient: prefill[0].Recipient})
req.NoError(err)
req.Equal(prefill[0].Recipient, f.Recipient)
req.Len(set, 1)
})
t.Run("unread only", func(t *testing.T) {
req, prefill := truncAndFill(t, 5)
// Check that all notifications are initially unread
filter := types.NotificationFilter{
Read: filter.StateExcluded, // Only unread notifications
}
set, _, err := s.SearchNotifications(ctx, filter)
req.NoError(err)
req.Len(set, 5, "Expected all 5 notifications to be unread")
// Mark one notification as read
now := time.Now()
prefill[0].ReadAt = &now
req.NoError(s.UpdateNotification(ctx, prefill[0]))
// Search for unread notifications again
set, _, err = s.SearchNotifications(ctx, filter)
req.NoError(err)
// We expect 4 unread notifications (5 total - 1 read)
req.Len(set, 4, "Expected 4 unread notifications after marking one as read")
})
t.Run("deleted only", func(t *testing.T) {
req, prefill := truncAndFill(t, 5)
// Check that no notifications are initially deleted
filter := types.NotificationFilter{
Deleted: filter.StateExclusive, // Only deleted notifications
}
set, _, err := s.SearchNotifications(ctx, filter)
req.NoError(err)
req.Len(set, 0, "Expected no deleted notifications")
// Mark one notification as deleted
now := time.Now()
prefill[0].DeletedAt = &now
req.NoError(s.UpdateNotification(ctx, prefill[0]))
// Search for deleted notifications
set, _, err = s.SearchNotifications(ctx, filter)
req.NoError(err)
// We expect 1 deleted notification
req.Len(set, 1, "Expected 1 deleted notification")
})
t.Run("with check", func(t *testing.T) {
req, prefill := truncAndFill(t, 5)
set, _, err := s.SearchNotifications(ctx, types.NotificationFilter{
Check: func(notification *types.Notification) (bool, error) {
// simple check that matches with the first notification from prefill
return notification.ID == prefill[0].ID, nil
},
})
req.NoError(err)
req.Len(set, 1)
req.Equal(prefill[0].ID, set[0].ID)
})
})
t.Run("delete", func(t *testing.T) {
req, notification := truncAndCreate(t)
req.NoError(s.DeleteNotificationByID(ctx, notification.ID))
// Verify it can't be found
_, err := s.LookupNotificationByID(ctx, notification.ID)
req.Error(err)
})
}

View File

@@ -0,0 +1,43 @@
package tests
import (
"context"
"testing"
"github.com/cortezaproject/corteza/server/store"
"github.com/cortezaproject/corteza/server/system/types"
_ "github.com/joho/godotenv/autoload"
"github.com/stretchr/testify/require"
)
func testQueueMessages(t *testing.T, s store.QueueMessages) {
var (
ctx = context.Background()
foobarMessage = &types.QueueMessage{Payload: []byte(`foobar`), Created: now()}
)
t.Run("create", func(t *testing.T) {
req := require.New(t)
req.NoError(s.TruncateQueueMessages(ctx))
req.NoError(s.CreateQueueMessage(ctx, foobarMessage))
})
t.Run("update", func(t *testing.T) {
req := require.New(t)
req.NoError(s.TruncateQueueMessages(ctx))
req.NoError(s.UpdateQueueMessage(ctx, foobarMessage))
})
t.Run("search", func(t *testing.T) {
req := require.New(t)
req.NoError(s.CreateQueueMessage(ctx,
&types.QueueMessage{ID: 1, Queue: "test", Payload: []byte{}, Created: now()},
&types.QueueMessage{ID: 2, Queue: "test", Payload: []byte{}, Created: now()},
&types.QueueMessage{ID: 3, Queue: "test", Payload: []byte{}, Created: now()},
))
set, _, err := s.SearchQueueMessages(ctx, types.QueueMessageFilter{})
req.NoError(err)
req.Len(set, 3)
})
}

View File

@@ -0,0 +1,69 @@
package tests
import (
"context"
"testing"
"time"
"github.com/cortezaproject/corteza/server/store"
"github.com/cortezaproject/corteza/server/system/types"
_ "github.com/joho/godotenv/autoload"
"github.com/stretchr/testify/require"
)
func testQueues(t *testing.T, s store.Queues) {
var (
ctx = context.Background()
new = &types.Queue{
ID: 42,
Consumer: "testConsumer",
Queue: "testQueue",
Meta: types.QueueMeta{},
CreatedAt: time.Now(),
CreatedBy: 1}
)
t.Run("create", func(t *testing.T) {
req := require.New(t)
req.NoError(s.TruncateQueues(ctx))
req.NoError(s.CreateQueue(ctx, new))
})
t.Run("update", func(t *testing.T) {
req := require.New(t)
req.NoError(s.TruncateQueues(ctx))
req.NoError(s.UpdateQueue(ctx, new))
})
t.Run("upsert", func(t *testing.T) {
req := require.New(t)
req.NoError(s.TruncateQueues(ctx))
req.NoError(s.UpsertQueue(ctx, &types.Queue{ID: 42, Queue: "test", CreatedAt: *now()}))
set, _, err := s.SearchQueues(ctx, types.QueueFilter{})
req.NoError(err)
req.Len(set, 1)
req.True(set[0].Queue == "test")
req.NoError(s.UpsertQueue(ctx, &types.Queue{ID: 42, Queue: "foobar", CreatedAt: *now()}))
set, _, err = s.SearchQueues(ctx, types.QueueFilter{})
req.NoError(err)
req.Len(set, 1)
req.True(set[0].Queue == "foobar")
})
t.Run("search", func(t *testing.T) {
req := require.New(t)
req.NoError(s.TruncateQueues(ctx))
req.NoError(s.CreateQueue(ctx,
new,
))
set, _, err := s.SearchQueues(ctx, types.QueueFilter{Query: "EST"})
req.NoError(err)
req.Len(set, 1)
set, _, err = s.SearchQueues(ctx, types.QueueFilter{Query: "foo"})
req.NoError(err)
req.Len(set, 0)
})
}

View File

@@ -0,0 +1,57 @@
package tests
import (
"context"
"github.com/cortezaproject/corteza/server/pkg/rbac"
"github.com/cortezaproject/corteza/server/store"
_ "github.com/joho/godotenv/autoload"
"github.com/stretchr/testify/require"
"testing"
)
func testRbacRules(t *testing.T, s store.RbacRules) {
var (
ctx = context.Background()
)
t.Run("create", func(t *testing.T) {
req := require.New(t)
req.NoError(s.TruncateRbacRules(ctx))
req.NoError(s.CreateRbacRule(ctx, rbac.AllowRule(42, "res1", "op1")))
})
t.Run("update", func(t *testing.T) {
req := require.New(t)
req.NoError(s.TruncateRbacRules(ctx))
req.NoError(s.UpdateRbacRule(ctx, rbac.AllowRule(42, "res1", "op1")))
})
t.Run("upsert", func(t *testing.T) {
req := require.New(t)
req.NoError(s.TruncateRbacRules(ctx))
req.NoError(s.UpsertRbacRule(ctx, rbac.AllowRule(42, "res1", "op1")))
set, _, err := s.SearchRbacRules(ctx, rbac.RuleFilter{})
req.NoError(err)
req.Len(set, 1)
req.True(set[0].Access == rbac.Allow)
req.NoError(s.UpsertRbacRule(ctx, rbac.DenyRule(42, "res1", "op1")))
set, _, err = s.SearchRbacRules(ctx, rbac.RuleFilter{})
req.NoError(err)
req.Len(set, 1)
req.True(set[0].Access == rbac.Deny)
})
t.Run("search", func(t *testing.T) {
req := require.New(t)
req.NoError(s.TruncateRbacRules(ctx))
req.NoError(s.CreateRbacRule(ctx,
rbac.AllowRule(42, "res1", "op1"),
rbac.AllowRule(42, "res2", "op2"),
))
set, _, err := s.SearchRbacRules(ctx, rbac.RuleFilter{})
req.NoError(err)
req.Len(set, 2)
})
}

View File

@@ -0,0 +1,311 @@
package tests
import (
"context"
"github.com/cortezaproject/corteza/server/pkg/filter"
"github.com/cortezaproject/corteza/server/pkg/id"
"github.com/cortezaproject/corteza/server/pkg/rand"
"github.com/cortezaproject/corteza/server/store"
"github.com/cortezaproject/corteza/server/system/types"
_ "github.com/joho/godotenv/autoload"
"github.com/stretchr/testify/require"
"strings"
"testing"
"time"
)
func testReminders(t *testing.T, s store.Reminders) {
var (
ctx = context.Background()
makeNew = func(nn ...string) *types.Reminder {
// minimum data set for new user
name := strings.Join(nn, "")
thisID := id.Next()
return &types.Reminder{
ID: thisID,
Resource: "resource+" + name,
AssignedTo: thisID,
CreatedAt: time.Now(),
AssignedAt: time.Now(),
}
}
truncAndCreate = func(t *testing.T) (*require.Assertions, *types.Reminder) {
req := require.New(t)
req.NoError(s.TruncateReminders(ctx))
reminder := makeNew()
req.NoError(s.CreateReminder(ctx, reminder))
return req, reminder
}
truncAndFill = func(t *testing.T, l int) (*require.Assertions, types.ReminderSet) {
req := require.New(t)
req.NoError(s.TruncateReminders(ctx))
set := make([]*types.Reminder, l)
for i := 0; i < l; i++ {
set[i] = makeNew(string(rand.Bytes(10)))
}
req.NoError(s.CreateReminder(ctx, set...))
return req, set
}
)
t.Run("create", func(t *testing.T) {
req := require.New(t)
req.NoError(s.CreateReminder(ctx, makeNew()))
})
t.Run("lookup by ID", func(t *testing.T) {
req, reminder := truncAndCreate(t)
fetched, err := s.LookupReminderByID(ctx, reminder.ID)
req.NoError(err)
req.Equal(reminder.ID, fetched.ID)
req.NotNil(fetched.CreatedAt)
req.Nil(fetched.UpdatedAt)
req.Nil(fetched.DeletedAt)
})
t.Run("update", func(t *testing.T) {
req, reminder := truncAndCreate(t)
req.NoError(s.UpdateReminder(ctx, reminder))
})
t.Run("search", func(t *testing.T) {
t.Run("by ID", func(t *testing.T) {
req, prefill := truncAndFill(t, 5)
set, f, err := s.SearchReminders(ctx, types.ReminderFilter{ReminderID: []uint64{prefill[0].ID}})
req.NoError(err)
req.Equal([]uint64{prefill[0].ID}, f.ReminderID)
req.Len(set, 1)
})
t.Run("by resource", func(t *testing.T) {
req, prefill := truncAndFill(t, 5)
set, _, err := s.SearchReminders(ctx, types.ReminderFilter{Resource: prefill[0].Resource})
req.NoError(err)
req.Len(set, 1)
})
t.Run("by assigned to", func(t *testing.T) {
req, prefill := truncAndFill(t, 5)
set, f, err := s.SearchReminders(ctx, types.ReminderFilter{AssignedTo: prefill[0].AssignedTo})
req.NoError(err)
req.Equal(prefill[0].AssignedTo, f.AssignedTo)
req.Len(set, 1)
})
t.Run("by dismissed", func(t *testing.T) {
req, prefill := truncAndFill(t, 5)
prefill[0].DismissedAt = &(prefill[0].CreatedAt)
s.UpdateReminder(ctx, prefill[0])
set, _, err := s.SearchReminders(ctx, types.ReminderFilter{ExcludeDismissed: true})
req.NoError(err)
req.Len(set, 4)
})
t.Run("by scheduled", func(t *testing.T) {
req, prefill := truncAndFill(t, 5)
prefill[0].RemindAt = &(prefill[0].CreatedAt)
s.UpdateReminder(ctx, prefill[0])
set, _, err := s.SearchReminders(ctx, types.ReminderFilter{ScheduledOnly: true})
req.NoError(err)
req.Len(set, 1)
})
t.Run("with check", func(t *testing.T) {
req, prefill := truncAndFill(t, 5)
set, _, err := s.SearchReminders(ctx, types.ReminderFilter{
Check: func(user *types.Reminder) (bool, error) {
// simple check that matches with the first user from prefill
return user.ID == prefill[0].ID, nil
},
})
req.NoError(err)
req.Len(set, 1)
req.Equal(prefill[0].ID, set[0].ID)
})
t.Run("paging with check", func(t *testing.T) {
// hide every third reminder from the check fn
hide := func(prefill types.ReminderSet) (map[uint64]bool, int) {
hidden, visible := make(map[uint64]bool), 0
for i, r := range prefill {
if i%3 == 0 {
hidden[r.ID] = true
} else {
visible++
}
}
return hidden, visible
}
t.Run("page holds no more than the limit and no duplicates", func(t *testing.T) {
req, prefill := truncAndFill(t, 20)
hidden, _ := hide(prefill)
set, _, err := s.SearchReminders(ctx, types.ReminderFilter{
Paging: filter.Paging{Limit: 5},
Check: func(r *types.Reminder) (bool, error) { return !hidden[r.ID], nil },
})
req.NoError(err)
req.Len(set, 5)
seen := make(map[uint64]bool)
for _, r := range set {
req.False(seen[r.ID], "reminder %d returned twice", r.ID)
seen[r.ID] = true
}
})
t.Run("walking every page yields each visible item once", func(t *testing.T) {
req, prefill := truncAndFill(t, 20)
hidden, visible := hide(prefill)
var (
cursor *filter.PagingCursor
seen = make(map[uint64]int)
)
for page := 0; page < 30; page++ {
set, f, err := s.SearchReminders(ctx, types.ReminderFilter{
Paging: filter.Paging{Limit: 3, PageCursor: cursor},
Check: func(r *types.Reminder) (bool, error) { return !hidden[r.ID], nil },
})
req.NoError(err)
for _, r := range set {
req.False(hidden[r.ID], "hidden reminder %d was returned", r.ID)
seen[r.ID]++
}
if f.NextPage == nil {
break
}
cursor = f.NextPage
}
req.Len(seen, visible)
for id, times := range seen {
req.Equal(1, times, "reminder %d returned %d times", id, times)
}
})
t.Run("fills a page past a long run of rejected items", func(t *testing.T) {
req, prefill := truncAndFill(t, 200)
// hide everything but the last 5
hidden := make(map[uint64]bool)
for _, r := range prefill[:len(prefill)-5] {
hidden[r.ID] = true
}
set, _, err := s.SearchReminders(ctx, types.ReminderFilter{
Paging: filter.Paging{Limit: 3},
Check: func(r *types.Reminder) (bool, error) { return !hidden[r.ID], nil },
})
req.NoError(err)
req.Len(set, 3)
})
})
t.Run("total", func(t *testing.T) {
t.Run("omitted when not requested", func(t *testing.T) {
req, _ := truncAndFill(t, 5)
set, f, err := s.SearchReminders(ctx, types.ReminderFilter{
Paging: filter.Paging{Limit: 2},
})
req.NoError(err)
req.Len(set, 2)
req.Equal(uint(0), f.Total)
})
t.Run("without limit", func(t *testing.T) {
req, _ := truncAndFill(t, 5)
set, f, err := s.SearchReminders(ctx, types.ReminderFilter{
Paging: filter.Paging{IncTotal: true},
})
req.NoError(err)
req.Len(set, 5)
req.Equal(uint(5), f.Total)
})
t.Run("with limit above count", func(t *testing.T) {
req, _ := truncAndFill(t, 5)
set, f, err := s.SearchReminders(ctx, types.ReminderFilter{
Paging: filter.Paging{Limit: 10, IncTotal: true},
})
req.NoError(err)
req.Len(set, 5)
req.Equal(uint(5), f.Total)
})
t.Run("with limit equal to count", func(t *testing.T) {
req, _ := truncAndFill(t, 5)
set, f, err := s.SearchReminders(ctx, types.ReminderFilter{
Paging: filter.Paging{Limit: 5, IncTotal: true},
})
req.NoError(err)
req.Len(set, 5)
req.Equal(uint(5), f.Total)
})
t.Run("with limit below count", func(t *testing.T) {
req, _ := truncAndFill(t, 5)
set, f, err := s.SearchReminders(ctx, types.ReminderFilter{
Paging: filter.Paging{Limit: 2, IncTotal: true},
})
req.NoError(err)
req.Len(set, 2)
req.Equal(uint(5), f.Total)
})
t.Run("counts only what check keeps", func(t *testing.T) {
req, prefill := truncAndFill(t, 5)
set, f, err := s.SearchReminders(ctx, types.ReminderFilter{
Paging: filter.Paging{Limit: 2, IncTotal: true},
Check: func(r *types.Reminder) (bool, error) {
return r.ID != prefill[0].ID && r.ID != prefill[1].ID, nil
},
})
req.NoError(err)
req.Len(set, 2)
req.Equal(uint(3), f.Total)
})
t.Run("refused with a page cursor", func(t *testing.T) {
req, _ := truncAndFill(t, 5)
_, f, err := s.SearchReminders(ctx, types.ReminderFilter{
Paging: filter.Paging{Limit: 2},
})
req.NoError(err)
req.NotNil(f.NextPage)
_, _, err = s.SearchReminders(ctx, types.ReminderFilter{
Paging: filter.Paging{Limit: 2, IncTotal: true, PageCursor: f.NextPage},
})
req.Error(err)
})
})
})
t.Run("ordered search", func(t *testing.T) {
t.Skip("not implemented")
})
}

View File

@@ -0,0 +1,11 @@
package tests
import (
"testing"
"github.com/cortezaproject/corteza/server/store"
)
func testReports(t *testing.T, s store.Reports) {
t.Skip("@todo")
}

View File

@@ -0,0 +1,11 @@
package tests
import (
"testing"
"github.com/cortezaproject/corteza/server/store"
)
func testResourceActivitys(t *testing.T, s store.ResourceActivitys) {
t.Skip("@todo")
}

View File

@@ -0,0 +1,11 @@
package tests
import (
"testing"
"github.com/cortezaproject/corteza/server/store"
)
func testResourceTranslations(t *testing.T, s store.Reports) {
t.Skip("@todo")
}

View File

@@ -0,0 +1,100 @@
package tests
import (
"context"
"fmt"
"testing"
"github.com/cortezaproject/corteza/server/pkg/id"
"github.com/cortezaproject/corteza/server/store"
"github.com/cortezaproject/corteza/server/system/types"
_ "github.com/joho/godotenv/autoload"
"github.com/stretchr/testify/require"
)
func testRoleMembers(t *testing.T, s store.RoleMembers) {
var (
ctx = context.Background()
makeNew = func(nn ...string) *types.RoleMember {
// minimum data set for new RoleMember
return &types.RoleMember{
RoleID: id.Next(),
Resource: fmt.Sprintf("corteza::system:user/%d", id.Next()),
}
}
truncAndCreate = func(t *testing.T) (*require.Assertions, *types.RoleMember) {
req := require.New(t)
req.NoError(s.TruncateRoleMembers(ctx))
roleMember := makeNew()
req.NoError(s.CreateRoleMember(ctx, roleMember))
return req, roleMember
}
truncAndFill = func(t *testing.T, l int) (*require.Assertions, types.RoleMemberSet) {
req := require.New(t)
req.NoError(s.TruncateRoleMembers(ctx))
set := make([]*types.RoleMember, l)
for i := 0; i < l; i++ {
set[i] = makeNew()
}
req.NoError(s.CreateRoleMember(ctx, set...))
return req, set
}
)
t.Run("create", func(t *testing.T) {
req := require.New(t)
req.NoError(s.CreateRoleMember(ctx, makeNew()))
})
t.Run("create multiple", func(t *testing.T) {
truncAndFill(t, 5)
})
// t.Run("update", func(t *testing.T) {
// req, roleMember := truncAndCreate(t)
// newID := id.Next()
// roleMember = &types.RoleMember{
// OwnerID: roleMember.OwnerID,
// RoleID: newID,
// }
// req.NoError(s.UpdateRoleMember(ctx, roleMember))
// updated, f, err := s.SearchRoleMembers(ctx, types.RoleMemberFilter{OwnerID: roleMember.OwnerID})
// req.NoError(err)
// req.Equal(updated[0].OwnerID, f.OwnerID)
// })
// t.Run("search", func(t *testing.T) {
// t.Run("by RoleID", func(t *testing.T) {
// req, prefill := truncAndFill(t, 5)
// set, f, err := s.SearchRoleMembers(ctx, types.RoleMemberFilter{RoleID: prefill[0].RoleID})
// req.NoError(err)
// req.Equal(prefill[0].RoleID, f.RoleID)
// req.Len(set, 1)
// })
// })
t.Run("delete", func(t *testing.T) {
t.Run("by role member", func(t *testing.T) {
req, roleMember := truncAndCreate(t)
req.NoError(s.DeleteRoleMember(ctx, roleMember))
roleMembers, _, _ := s.SearchRoleMembers(ctx, types.RoleMemberFilter{Resource: roleMember.Resource, RoleID: roleMember.RoleID})
req.Len(roleMembers, 0)
})
t.Run("by RoleID and UserID", func(t *testing.T) {
req, roleMember := truncAndCreate(t)
req.NoError(s.DeleteRoleMemberByResourceRoleID(ctx, roleMember.Resource, roleMember.RoleID))
roleMembers, _, _ := s.SearchRoleMembers(ctx, types.RoleMemberFilter{Resource: roleMember.Resource, RoleID: roleMember.RoleID})
req.Len(roleMembers, 0)
})
})
}

View File

@@ -0,0 +1,205 @@
package tests
import (
"context"
"strings"
"testing"
"time"
"github.com/cortezaproject/corteza/server/pkg/filter"
"github.com/cortezaproject/corteza/server/pkg/id"
"github.com/cortezaproject/corteza/server/pkg/rand"
"github.com/cortezaproject/corteza/server/store"
"github.com/cortezaproject/corteza/server/system/types"
_ "github.com/joho/godotenv/autoload"
"github.com/stretchr/testify/require"
)
func testRoles(t *testing.T, s store.Roles) {
var (
ctx = context.Background()
makeNew = func(nn ...string) *types.Role {
name := strings.Join(nn, "")
return &types.Role{
ID: id.Next(),
CreatedAt: time.Now(),
Name: "RoleCRUD+" + name,
Handle: "rolecrud+" + name,
}
}
truncAndCreate = func(t *testing.T) (*require.Assertions, *types.Role) {
req := require.New(t)
req.NoError(s.TruncateRoles(ctx))
role := makeNew()
req.NoError(s.CreateRole(ctx, role))
return req, role
}
truncAndFill = func(t *testing.T, l int) (*require.Assertions, types.RoleSet) {
req := require.New(t)
req.NoError(s.TruncateRoles(ctx))
set := make([]*types.Role, l)
for i := 0; i < l; i++ {
set[i] = makeNew(string(rand.Bytes(10)))
}
req.NoError(s.CreateRole(ctx, set...))
return req, set
}
)
t.Run("create", func(t *testing.T) {
req := require.New(t)
req.NoError(s.CreateRole(ctx, makeNew()))
})
t.Run("lookup by ID", func(t *testing.T) {
req, role := truncAndCreate(t)
fetched, err := s.LookupRoleByID(ctx, role.ID)
req.NoError(err)
req.Equal(role.Name, fetched.Name)
req.Equal(role.Handle, fetched.Handle)
req.Equal(role.ID, fetched.ID)
req.NotNil(fetched.CreatedAt)
req.Nil(fetched.UpdatedAt)
req.Nil(fetched.DeletedAt)
})
t.Run("update", func(t *testing.T) {
req, role := truncAndCreate(t)
req.NoError(s.UpdateRole(ctx, role))
})
t.Run("create and update deleted with existing handle", func(t *testing.T) {
req, role := truncAndCreate(t)
deletedRole := makeNew("copy")
deletedRole.DeletedAt = now()
deletedRole.Handle = role.Handle
req.NoError(store.CreateRole(ctx, s, deletedRole))
req.NoError(store.UpdateRole(ctx, s, deletedRole))
})
t.Run("lookup by handle", func(t *testing.T) {
req, role := truncAndCreate(t)
fetched, err := s.LookupRoleByHandle(ctx, role.Handle)
req.NoError(err)
req.Equal(role.ID, fetched.ID)
})
t.Run("search", func(t *testing.T) {
t.Run("by ID", func(t *testing.T) {
req, prefill := truncAndFill(t, 5)
set, f, err := s.SearchRoles(ctx, types.RoleFilter{RoleID: id.Strings(prefill[0].ID)})
req.NoError(err)
req.Equal(id.Strings(prefill[0].ID), f.RoleID)
req.Len(set, 1)
})
t.Run("by query", func(t *testing.T) {
req, prefill := truncAndFill(t, 5)
set, _, err := s.SearchRoles(ctx, types.RoleFilter{Query: prefill[0].Handle})
req.NoError(err)
req.Len(set, 1)
})
t.Run("by state", func(t *testing.T) {
t.Run("deleted", func(t *testing.T) {
req, prefill := truncAndFill(t, 5)
prefill[0].DeletedAt = &(prefill[0].CreatedAt)
s.UpdateRole(ctx, prefill[0])
set, _, err := s.SearchRoles(ctx, types.RoleFilter{Deleted: filter.StateExcluded})
req.NoError(err)
req.Len(set, 4)
set, _, err = s.SearchRoles(ctx, types.RoleFilter{Deleted: filter.StateInclusive})
req.NoError(err)
req.Len(set, 5)
set, _, err = s.SearchRoles(ctx, types.RoleFilter{Deleted: filter.StateExclusive})
req.NoError(err)
req.Len(set, 1)
})
t.Run("archived", func(t *testing.T) {
req, prefill := truncAndFill(t, 5)
prefill[0].ArchivedAt = &(prefill[0].CreatedAt)
s.UpdateRole(ctx, prefill[0])
set, _, err := s.SearchRoles(ctx, types.RoleFilter{Archived: filter.StateExcluded})
req.NoError(err)
req.Len(set, 4)
set, _, err = s.SearchRoles(ctx, types.RoleFilter{Archived: filter.StateInclusive})
req.NoError(err)
req.Len(set, 5)
set, _, err = s.SearchRoles(ctx, types.RoleFilter{Archived: filter.StateExclusive})
req.NoError(err)
req.Len(set, 1)
})
})
t.Run("with check", func(t *testing.T) {
req, prefill := truncAndFill(t, 5)
set, _, err := s.SearchRoles(ctx, types.RoleFilter{
Check: func(role *types.Role) (bool, error) {
return role.ID == prefill[0].ID, nil
},
})
req.NoError(err)
req.Len(set, 1)
req.Equal(prefill[0].ID, set[0].ID)
})
})
t.Run("ordered search", func(t *testing.T) {
t.Skip("not implemented")
})
t.Run("metrics", func(t *testing.T) {
var (
req = require.New(t)
oct, _ = time.Parse(time.RFC3339, "2020-10-02T10:01:10Z")
nov, _ = time.Parse(time.RFC3339, "2020-11-02T20:02:10Z")
octu = uint(oct.Truncate(time.Hour * 24).Unix())
novu = uint(nov.Truncate(time.Hour * 24).Unix())
e = &types.RoleMetrics{
Total: 8,
Valid: 2,
Deleted: 3,
Archived: 3,
DailyCreated: []uint{octu, 7, novu, 1},
DailyUpdated: []uint{octu, 2},
DailyArchived: []uint{octu, 2, novu, 1},
DailyDeleted: []uint{novu, 3},
}
)
req.NoError(s.TruncateRoles(ctx))
req.NoError(s.CreateRole(ctx, &types.Role{ID: id.Next(), CreatedAt: oct, UpdatedAt: &oct}))
req.NoError(s.CreateRole(ctx, &types.Role{ID: id.Next(), CreatedAt: oct, UpdatedAt: &oct}))
req.NoError(s.CreateRole(ctx, &types.Role{ID: id.Next(), CreatedAt: oct, ArchivedAt: &oct}))
req.NoError(s.CreateRole(ctx, &types.Role{ID: id.Next(), CreatedAt: oct, ArchivedAt: &oct}))
req.NoError(s.CreateRole(ctx, &types.Role{ID: id.Next(), CreatedAt: oct, ArchivedAt: &nov}))
req.NoError(s.CreateRole(ctx, &types.Role{ID: id.Next(), CreatedAt: oct, DeletedAt: &nov}))
req.NoError(s.CreateRole(ctx, &types.Role{ID: id.Next(), CreatedAt: oct, DeletedAt: &nov}))
req.NoError(s.CreateRole(ctx, &types.Role{ID: id.Next(), CreatedAt: nov, DeletedAt: &nov}))
m, err := store.RoleMetrics(ctx, s)
req.NoError(err)
req.Equal(e, m)
})
}

View File

@@ -0,0 +1,137 @@
package tests
import (
"context"
"strings"
"testing"
"github.com/cortezaproject/corteza/server/pkg/id"
"github.com/cortezaproject/corteza/server/pkg/rand"
"github.com/cortezaproject/corteza/server/store"
"github.com/cortezaproject/corteza/server/system/types"
"github.com/stretchr/testify/require"
)
func testSettingValues(t *testing.T, s store.SettingValues) {
var (
ctx = context.Background()
makeNew = func(nn ...string) *types.SettingValue {
name := strings.Join(nn, "")
return &types.SettingValue{
Name: name,
OwnedBy: id.Next(),
UpdatedAt: *now(),
}
}
truncAndCreate = func(t *testing.T) (*require.Assertions, *types.SettingValue) {
req := require.New(t)
req.NoError(s.TruncateSettingValues(ctx))
settings := makeNew(string(rand.Bytes(10)))
req.NoError(s.CreateSettingValue(ctx, settings))
return req, settings
}
truncAndFill = func(t *testing.T, l int) (*require.Assertions, types.SettingValueSet) {
req := require.New(t)
req.NoError(s.TruncateSettingValues(ctx))
set := make([]*types.SettingValue, l)
for i := 0; i < l; i++ {
set[i] = makeNew(string(rand.Bytes(10)))
}
req.NoError(s.CreateSettingValue(ctx, set...))
return req, set
}
)
t.Run("create", func(t *testing.T) {
req := require.New(t)
req.NoError(s.CreateSettingValue(ctx, makeNew()))
})
t.Run("lookup by name and ownedBy", func(t *testing.T) {
req, setting := truncAndCreate(t)
fetched, err := s.LookupSettingValueByNameOwnedBy(ctx, setting.Name, setting.OwnedBy)
req.NoError(err)
req.Equal(setting.Name, fetched.Name)
req.Equal(setting.OwnedBy, fetched.OwnedBy)
})
t.Run("update", func(t *testing.T) {
req, setting := truncAndCreate(t)
setting.Value = []byte(`"42"`)
req.NoError(s.UpdateSettingValue(ctx, setting))
fetched, err := s.LookupSettingValueByNameOwnedBy(ctx, setting.Name, setting.OwnedBy)
req.NoError(err)
req.Equal(string(`"42"`), string(fetched.Value))
})
t.Run("upsert", func(t *testing.T) {
req := require.New(t)
req.NoError(s.TruncateSettingValues(ctx))
t.Run("new", func(t *testing.T) {
req := require.New(t)
req.NoError(s.UpsertSettingValue(ctx, &types.SettingValue{Name: "foo", Value: []byte(`"foo"`), UpdatedAt: *now()}))
v, err := s.LookupSettingValueByNameOwnedBy(ctx, "foo", 0)
req.NoError(err)
req.NotNil(v)
req.Equal(string(`"foo"`), string(v.Value))
})
t.Run("existing", func(t *testing.T) {
req.NoError(s.CreateSettingValue(ctx, &types.SettingValue{Name: "baz", Value: []byte(`"created"`), UpdatedAt: *now()}))
req.NoError(s.UpsertSettingValue(ctx, &types.SettingValue{Name: "baz", Value: []byte(`"updated"`), UpdatedAt: *now()}))
v, err := s.LookupSettingValueByNameOwnedBy(ctx, "baz", 0)
req.NoError(err)
req.NotNil(v)
req.Equal(string(`"updated"`), string(v.Value))
})
})
t.Run("delete", func(t *testing.T) {
t.Run("by Settings", func(t *testing.T) {
req, setting := truncAndCreate(t)
req.NoError(s.DeleteSettingValue(ctx, setting))
set, _, err := s.SearchSettingValues(ctx, types.SettingsFilter{OwnedBy: setting.OwnedBy})
req.NoError(err)
req.Len(set, 0)
})
})
t.Run("search", func(t *testing.T) {
t.Run("by ownedBy", func(t *testing.T) {
req, prefill := truncAndFill(t, 5)
set, f, err := s.SearchSettingValues(ctx, types.SettingsFilter{OwnedBy: prefill[0].OwnedBy})
req.NoError(err)
req.Equal(uint64(prefill[0].OwnedBy), f.OwnedBy)
req.Len(set, 1)
})
t.Run("with check", func(t *testing.T) {
t.Skip("Should pass(afaik) but doesn't")
req, prefill := truncAndFill(t, 5)
set, _, err := s.SearchSettingValues(ctx, types.SettingsFilter{
Check: func(setting *types.SettingValue) (bool, error) {
return (setting.Name == prefill[0].Name), nil
},
})
req.NoError(err)
req.Len(set, 1)
req.Equal(prefill[0].Name, set[0].Name)
})
})
t.Run("ordered search", func(t *testing.T) {
t.Skip("not implemented")
})
}

View File

@@ -0,0 +1,157 @@
package tests
import (
"context"
"testing"
"time"
"github.com/cortezaproject/corteza/server/pkg/filter"
"github.com/cortezaproject/corteza/server/pkg/id"
"github.com/cortezaproject/corteza/server/pkg/rand"
"github.com/cortezaproject/corteza/server/store"
"github.com/cortezaproject/corteza/server/system/types"
_ "github.com/joho/godotenv/autoload"
"github.com/stretchr/testify/require"
)
func testTemplates(t *testing.T, s store.Templates) {
var (
ctx = context.Background()
req = require.New(t)
makeNew = func(handle string) *types.Template {
// minimum data set for new template
return &types.Template{
ID: id.Next(),
CreatedAt: time.Now(),
Handle: handle,
}
}
truncAndCreate = func(t *testing.T) (*require.Assertions, *types.Template) {
req := require.New(t)
req.NoError(s.TruncateTemplates(ctx))
res := makeNew(string(rand.Bytes(10)))
req.NoError(s.CreateTemplate(ctx, res))
return req, res
}
)
t.Run("create", func(t *testing.T) {
req.NoError(s.TruncateTemplates(ctx))
template := makeNew("TemplateCRUD")
req.NoError(s.CreateTemplate(ctx, template))
})
t.Run("lookup by ID", func(t *testing.T) {
req, template := truncAndCreate(t)
fetched, err := s.LookupTemplateByID(ctx, template.ID)
req.NoError(err)
req.Equal(template.Handle, fetched.Handle)
req.Equal(template.ID, fetched.ID)
req.NotNil(fetched.CreatedAt)
req.Nil(fetched.UpdatedAt)
req.Nil(fetched.DeletedAt)
})
t.Run("lookup by handle", func(t *testing.T) {
req, template := truncAndCreate(t)
fetched, err := s.LookupTemplateByHandle(ctx, template.Handle)
req.NoError(err)
req.Equal(template.Handle, fetched.Handle)
req.Equal(template.ID, fetched.ID)
req.NotNil(fetched.CreatedAt)
req.Nil(fetched.UpdatedAt)
req.Nil(fetched.DeletedAt)
})
t.Run("update", func(t *testing.T) {
req, template := truncAndCreate(t)
template.Handle = "TemplateCRUD+2"
req.NoError(s.UpdateTemplate(ctx, template))
updated, err := s.LookupTemplateByID(ctx, template.ID)
req.NoError(err)
req.Equal(template.Handle, updated.Handle)
})
t.Run("upsert", func(t *testing.T) {
t.Run("existing", func(t *testing.T) {
req, template := truncAndCreate(t)
template.Handle = "TemplateCRUD+2"
req.NoError(s.UpsertTemplate(ctx, template))
updated, err := s.LookupTemplateByID(ctx, template.ID)
req.NoError(err)
req.Equal(template.Handle, updated.Handle)
})
t.Run("new", func(t *testing.T) {
template := makeNew("upsert me")
template.Handle = "ComposeChartCRUD+2"
req.NoError(s.UpsertTemplate(ctx, template))
upserted, err := s.LookupTemplateByID(ctx, template.ID)
req.NoError(err)
req.Equal(template.Handle, upserted.Handle)
})
})
t.Run("delete", func(t *testing.T) {
t.Run("by Template", func(t *testing.T) {
req, template := truncAndCreate(t)
req.NoError(s.DeleteTemplate(ctx, template))
_, err := s.LookupTemplateByID(ctx, template.ID)
req.EqualError(err, store.ErrNotFound.Error())
})
t.Run("by ID", func(t *testing.T) {
req, template := truncAndCreate(t)
req.NoError(s.DeleteTemplateByID(ctx, template.ID))
_, err := s.LookupTemplateByID(ctx, template.ID)
req.EqualError(err, store.ErrNotFound.Error())
})
})
t.Run("search", func(t *testing.T) {
prefill := []*types.Template{
makeNew("one-one"),
makeNew("one-two"),
makeNew("two-one"),
makeNew("two-two"),
makeNew("two-deleted"),
}
count := len(prefill)
prefill[4].DeletedAt = &prefill[4].CreatedAt
valid := count - 1
req.NoError(s.TruncateTemplates(ctx))
req.NoError(s.CreateTemplate(ctx, prefill...))
// search for all valid
set, f, err := s.SearchTemplates(ctx, types.TemplateFilter{})
req.NoError(err)
req.Len(set, valid) // we've deleted one
// search for ALL
set, f, err = s.SearchTemplates(ctx, types.TemplateFilter{Deleted: filter.StateInclusive})
req.NoError(err)
req.Len(set, count) // we've deleted one
// search for deleted only
set, f, err = s.SearchTemplates(ctx, types.TemplateFilter{Deleted: filter.StateExclusive})
req.NoError(err)
req.Len(set, 1) // we've deleted one
set, f, err = s.SearchTemplates(ctx, types.TemplateFilter{Handle: "two-one"})
req.NoError(err)
req.Len(set, 1)
_ = f // dummy
})
}

View File

@@ -0,0 +1,10 @@
package tests
import (
"testing"
"github.com/cortezaproject/corteza/server/store"
_ "github.com/joho/godotenv/autoload"
)
func testUserGroups(t *testing.T, s store.UserGroups) {}

View File

@@ -0,0 +1,474 @@
package tests
import (
"context"
"fmt"
"strings"
"testing"
"time"
"github.com/cortezaproject/corteza/server/pkg/filter"
"github.com/cortezaproject/corteza/server/pkg/id"
"github.com/cortezaproject/corteza/server/pkg/rand"
"github.com/cortezaproject/corteza/server/store"
"github.com/cortezaproject/corteza/server/system/types"
_ "github.com/joho/godotenv/autoload"
"github.com/stretchr/testify/require"
)
func testUsers(t *testing.T, s store.Users) {
var (
dummyID uint64 = 0
ctx = context.Background()
makeNew = func(nn ...string) *types.User {
// minimum data set for new user
name := strings.Join(nn, "")
dummyID = dummyID + 1
return &types.User{
ID: dummyID,
CreatedAt: time.Now(),
Email: "user-crud+" + name + "@crust.test",
Username: "username_" + name,
Handle: "handle_" + name,
}
}
truncAndCreate = func(t *testing.T) (*require.Assertions, *types.User) {
req := require.New(t)
req.NoError(s.TruncateUsers(ctx))
user := makeNew()
req.NoError(s.CreateUser(ctx, user))
return req, user
}
truncAndFill = func(t *testing.T, l int) (*require.Assertions, types.UserSet) {
req := require.New(t)
req.NoError(s.TruncateUsers(ctx))
set := make([]*types.User, l)
for i := 0; i < l; i++ {
set[i] = makeNew(string(rand.Bytes(10)))
}
req.NoError(s.CreateUser(ctx, set...))
return req, set
}
stringifySetRange = func(set types.UserSet) string {
if len(set) == 0 {
return ""
}
var out = set[0].Handle[7:]
if len(set) > 1 {
out += ".." + set[len(set)-1].Handle[7:]
}
return out
}
// in case we need some quick old-school debugging
//dbg := func(uu ...*types.User) {
// for i, u := range uu {
// fmt.Printf(" => #%2d %s\n", i+1, u.Handle)
// }
//}
)
t.Run("create", func(t *testing.T) {
req := require.New(t)
req.NoError(s.TruncateUsers(ctx))
req.NoError(store.CreateUser(ctx, s, makeNew()))
})
t.Run("create with duplicate email", func(t *testing.T) {
req := require.New(t)
req.NoError(s.TruncateUsers(ctx))
req.NoError(s.CreateUser(ctx, makeNew("a")))
req.EqualError(s.CreateUser(ctx, makeNew("a")), store.ErrNotUnique.Error())
})
t.Run("create with duplicate ID", func(t *testing.T) {
req := require.New(t)
req.NoError(s.TruncateUsers(ctx))
user := makeNew("a")
req.NoError(s.CreateUser(ctx, user))
req.EqualError(s.CreateUser(ctx, user), store.ErrNotUnique.Error())
})
t.Run("lookup by ID", func(t *testing.T) {
req, user := truncAndCreate(t)
fetched, err := store.LookupUserByID(ctx, s, user.ID)
req.NoError(err)
req.Equal(user.Email, fetched.Email)
req.Equal(user.Username, fetched.Username)
req.Equal(user.Handle, fetched.Handle)
req.Equal(user.ID, fetched.ID)
req.NotNil(fetched.CreatedAt)
req.Nil(fetched.UpdatedAt)
req.Nil(fetched.DeletedAt)
req.Nil(fetched.SuspendedAt)
})
t.Run("update", func(t *testing.T) {
req, user := truncAndCreate(t)
req.NoError(s.UpdateUser(ctx, user))
})
t.Run("lookup by email", func(t *testing.T) {
req, user := truncAndCreate(t)
fetched, err := store.LookupUserByEmail(ctx, s, user.Email)
req.NoError(err)
req.Equal(user.Email, fetched.Email)
})
t.Run("lookup by handle", func(t *testing.T) {
req, user := truncAndCreate(t)
fetched, err := store.LookupUserByHandle(ctx, s, user.Handle)
req.NoError(err)
req.Equal(user.ID, fetched.ID)
})
t.Run("lookup by nonexisting handle", func(t *testing.T) {
req, _ := truncAndCreate(t)
fetched, err := store.LookupUserByHandle(ctx, s, "no such handle")
req.EqualError(err, "not found")
req.Nil(fetched)
})
t.Run("lookup by username", func(t *testing.T) {
req, user := truncAndCreate(t)
fetched, err := store.LookupUserByUsername(ctx, s, user.Username)
req.NoError(err)
req.Equal(user.ID, fetched.ID)
})
t.Run("create and update deleted with existing email", func(t *testing.T) {
req, user := truncAndCreate(t)
deletedUser := makeNew("copy")
deletedUser.DeletedAt = now()
deletedUser.Email = user.Email
req.NoError(store.CreateUser(ctx, s, deletedUser))
req.NoError(store.UpdateUser(ctx, s, deletedUser))
})
t.Run("search", func(t *testing.T) {
t.Run("by ID", func(t *testing.T) {
req, prefill := truncAndFill(t, 5)
set, f, err := store.SearchUsers(ctx, s, types.UserFilter{UserID: id.Strings(prefill[0].ID)})
req.NoError(err)
req.Equal(id.Strings(prefill[0].ID), f.UserID)
req.Len(set, 1)
//req.Equal(set[0].ID, user.ID)
})
t.Run("by email", func(t *testing.T) {
req, prefill := truncAndFill(t, 5)
set, _, err := store.SearchUsers(ctx, s, types.UserFilter{Email: prefill[0].Email})
req.NoError(err)
req.Len(set, 1)
})
t.Run("by username", func(t *testing.T) {
req, prefill := truncAndFill(t, 5)
set, _, err := store.SearchUsers(ctx, s, types.UserFilter{Username: prefill[0].Username})
req.NoError(err)
req.Len(set, 1)
})
t.Run("by query", func(t *testing.T) {
req, prefill := truncAndFill(t, 5)
set, _, err := store.SearchUsers(ctx, s, types.UserFilter{Query: prefill[0].Handle})
req.NoError(err)
req.Len(set, 1)
})
t.Run("by username", func(t *testing.T) {
req, _ := truncAndFill(t, 5)
set, _, err := store.SearchUsers(ctx, s, types.UserFilter{Username: "no such username"})
req.NoError(err)
req.Len(set, 0)
})
t.Run("with check", func(t *testing.T) {
req, prefill := truncAndFill(t, 5)
set, _, err := store.SearchUsers(ctx, s, types.UserFilter{
Check: func(user *types.User) (bool, error) {
// simple check that matches with the first user from prefill
return user.ID == prefill[0].ID, nil
},
})
req.NoError(err)
req.Len(set, 1)
req.Equal(prefill[0].ID, set[0].ID)
})
})
t.Run("paging and sorting", func(t *testing.T) {
require.NoError(t, s.TruncateUsers(ctx))
require.NoError(t, s.CreateUser(ctx,
makeNew("01"),
makeNew("02"),
makeNew("03"),
makeNew("04"),
makeNew("05"),
makeNew("06"),
makeNew("07"),
makeNew("08"),
makeNew("09"),
makeNew("10"),
))
{
tcc := []struct {
sort string
rval string
}{
{"email", "01..10"},
{"email DESC", "10..01"},
{"id, email", "01..10"},
{"id DESC, email DESC", "10..01"},
{"id DESC, email", "10..01"},
{"id, email DESC", "01..10"},
}
for _, tc := range tcc {
t.Run(tc.sort, func(t *testing.T) {
var (
req = require.New(t)
f = types.UserFilter{}
set types.UserSet
err error
)
f.Sort.Set(tc.sort)
set, f, err = store.SearchUsers(ctx, s, f)
req.NoError(err)
req.Equal(tc.rval, stringifySetRange(set))
req.Nil(f.PrevPage)
req.Nil(f.NextPage)
})
}
}
{
prevCur := 1
nextCur := 2
bothCur := prevCur | nextCur
// tests if cursors are properly set/unset by inspecting req. bits
testCursors := func(req *require.Assertions, b int, f types.UserFilter) {
if b&prevCur == 0 {
req.Nil(f.PrevPage)
} else {
req.NotNil(f.PrevPage)
}
if b&nextCur == 0 {
req.Nil(f.NextPage)
} else {
req.NotNil(f.NextPage)
}
}
tcc := []struct {
// how data is sorted
sort string
// expected data
rval []string
// how cursors should be set when moving forward/backward
curr []int
}{
{
"id",
[]string{"01..03", "04..06", "07..09", "10"},
[]int{nextCur, bothCur, bothCur, prevCur},
},
{
"id DESC",
[]string{"10..08", "07..05", "04..02", "01"},
[]int{nextCur, bothCur, bothCur, prevCur},
},
{
"email",
[]string{"01..03", "04..06", "07..09", "10"},
[]int{nextCur, bothCur, bothCur, prevCur},
},
{
"email DESC",
[]string{"10..08", "07..05", "04..02", "01"},
[]int{nextCur, bothCur, bothCur, prevCur},
},
{
"id DESC, email",
[]string{"10..08", "07..05", "04..02", "01"},
[]int{nextCur, bothCur, bothCur, prevCur},
},
}
for _, tc := range tcc {
t.Run("crawling: "+tc.sort+"x", func(t *testing.T) {
var (
req = require.New(t)
f = types.UserFilter{}
set types.UserSet
err error
)
f.Sort.Set(tc.sort)
f.Limit = 3 // 3, 3, 3, 1
t.Log("going from page 1 to 4")
for p := 0; p < 4; p++ {
t.Logf("0123 next page cursor: %35s", f.PageCursor)
set, f, err = store.SearchUsers(ctx, s, f)
req.NoError(err)
req.True(tc.sort == f.Sort.String() || strings.HasPrefix(f.Sort.String(), tc.sort+","))
req.Equal(tc.rval[p], stringifySetRange(set))
testCursors(req, tc.curr[p], f)
// advance to next page
f.PageCursor = f.NextPage
}
t.Log("and back from 3 to 1")
f.PageCursor = f.PrevPage
for p := 2; p >= 0; p-- {
f.Sort = nil
t.Logf("_210 next page cursor: %35s", f.PageCursor)
set, f, err = store.SearchUsers(ctx, s, f)
t.Log(stringifySetRange(set))
req.NoError(err)
//req.True(tc.sort == f.Sort.String() || strings.HasPrefix(f.Sort.String(), tc.sort+","), "search should not return altered sort on filter")
req.Equal(tc.rval[p], stringifySetRange(set))
testCursors(req, tc.curr[p], f)
// reverse to previous page
f.PageCursor = f.PrevPage
}
t.Log("and again all the way to 4th page")
f.PageCursor = f.NextPage
for p := 1; p < 4; p++ {
set, f, err = store.SearchUsers(ctx, s, f)
req.NoError(err)
req.True(tc.sort == f.Sort.String() || strings.HasPrefix(f.Sort.String(), tc.sort+","))
req.Equal(tc.rval[p], stringifySetRange(set))
testCursors(req, tc.curr[p], f)
// advance to next page
f.PageCursor = f.NextPage
}
})
}
}
t.Run("with incompatible sort", func(t *testing.T) {
req := require.New(t)
req.NoError(s.TruncateUsers(ctx))
set := []*types.User{
makeNew("01"),
makeNew("02"),
makeNew("03"),
makeNew("04"),
makeNew("05"),
}
req.NoError(s.CreateUser(ctx, set...))
f := types.UserFilter{}
f.Sort = filter.SortExprSet{&filter.SortExpr{Column: "email", Descending: true}, &filter.SortExpr{Column: "handle", Descending: true}}
f.Limit = uint(len(set))
set, f, err := store.SearchUsers(ctx, s, f)
req.Len(set, int(f.Limit))
req.NoError(err)
f.Limit = 1
set, f, err = store.SearchUsers(ctx, s, f)
req.NoError(err)
// go to next page with different sorting
f.PageCursor = f.NextPage
f.Sort = filter.SortExprSet{&filter.SortExpr{Column: "username", Descending: false}}
set, f, err = store.SearchUsers(ctx, s, f)
req.EqualError(err, filter.ErrIncompatibleSort.Error())
})
})
t.Run("count", func(t *testing.T) {
var (
req = require.New(t)
f = types.UserFilter{}
c1, c2 uint
err error
user = &types.User{ID: id.Next(), CreatedAt: time.Now(), Email: fmt.Sprintf("user-crud+%s@crust.test", time.Now().String())}
)
c1, err = store.CountUsers(ctx, s, f)
req.NoError(err)
req.NoError(s.CreateUser(ctx, user))
c2, err = store.CountUsers(ctx, s, f)
req.NoError(err)
req.Equal(c1+1, c2)
req.NoError(s.DeleteUserByID(ctx, user.ID))
c2, err = store.CountUsers(ctx, s, f)
req.NoError(err)
req.Equal(c1, c2)
})
t.Run("metrics", func(t *testing.T) {
var (
req = require.New(t)
oct, _ = time.Parse(time.RFC3339, "2020-10-02T10:01:10Z")
nov, _ = time.Parse(time.RFC3339, "2020-11-02T20:02:10Z")
octu = uint(oct.Truncate(time.Hour * 24).Unix())
novu = uint(nov.Truncate(time.Hour * 24).Unix())
e = &types.UserMetrics{
Total: 8,
Valid: 2,
Deleted: 3,
Suspended: 3,
DailyCreated: []uint{octu, 7, novu, 1},
DailyUpdated: []uint{octu, 2},
DailySuspended: []uint{octu, 2, novu, 1},
DailyDeleted: []uint{novu, 3},
}
)
req.NoError(s.TruncateUsers(ctx))
req.NoError(s.CreateUser(ctx, &types.User{ID: id.Next(), CreatedAt: oct, Email: "user-metrics-1@crust.test", UpdatedAt: &oct}))
req.NoError(s.CreateUser(ctx, &types.User{ID: id.Next(), CreatedAt: oct, Email: "user-metrics-2@crust.test", UpdatedAt: &oct}))
req.NoError(s.CreateUser(ctx, &types.User{ID: id.Next(), CreatedAt: oct, Email: "user-metrics-3@crust.test", SuspendedAt: &oct}))
req.NoError(s.CreateUser(ctx, &types.User{ID: id.Next(), CreatedAt: oct, Email: "user-metrics-4@crust.test", SuspendedAt: &oct}))
req.NoError(s.CreateUser(ctx, &types.User{ID: id.Next(), CreatedAt: oct, Email: "user-metrics-5@crust.test", SuspendedAt: &nov}))
req.NoError(s.CreateUser(ctx, &types.User{ID: id.Next(), CreatedAt: oct, Email: "user-metrics-6@crust.test", DeletedAt: &nov}))
req.NoError(s.CreateUser(ctx, &types.User{ID: id.Next(), CreatedAt: oct, Email: "user-metrics-7@crust.test", DeletedAt: &nov}))
req.NoError(s.CreateUser(ctx, &types.User{ID: id.Next(), CreatedAt: nov, Email: "user-metrics-8@crust.test", DeletedAt: &nov}))
m, err := store.UserMetrics(ctx, s)
req.NoError(err)
req.Equal(e, m)
})
}