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
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:
388
server/tests/envoy/import_export_test.go
Normal file
388
server/tests/envoy/import_export_test.go
Normal file
@@ -0,0 +1,388 @@
|
||||
package envoy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
automationTypes "github.com/cortezaproject/corteza/server/automation/types"
|
||||
"github.com/cortezaproject/corteza/server/compose/types"
|
||||
"github.com/cortezaproject/corteza/server/pkg/envoyx"
|
||||
"github.com/cortezaproject/corteza/server/pkg/filter"
|
||||
"github.com/cortezaproject/corteza/server/store"
|
||||
systemTypes "github.com/cortezaproject/corteza/server/system/types"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestImportExport(t *testing.T) {
|
||||
var (
|
||||
ctx = context.Background()
|
||||
req = require.New(t)
|
||||
nodes envoyx.NodeSet
|
||||
gg *envoyx.DepGraph
|
||||
err error
|
||||
)
|
||||
|
||||
cleanup(t)
|
||||
|
||||
// The test
|
||||
//
|
||||
// * imports some YAML files
|
||||
// * checks the DB state
|
||||
// * exports the DB into a YAML
|
||||
// * clears the DB
|
||||
// * imports the YAML
|
||||
// * checks the DB state the same way as before
|
||||
//
|
||||
// The above outlined flow allows us to trivially check if the data is both
|
||||
// imported and exported correctly.
|
||||
//
|
||||
// The initial step could also manually populate the DB but the YAML import
|
||||
// is more convenient.
|
||||
|
||||
t.Run("initial import", func(t *testing.T) {
|
||||
t.Run("parse configs", func(t *testing.T) {
|
||||
nodes, _, err = defaultEnvoy.Decode(ctx, envoyx.DecodeParams{
|
||||
Type: envoyx.DecodeTypeURI,
|
||||
Params: map[string]any{
|
||||
"uri": "file://testdata/full",
|
||||
},
|
||||
})
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
t.Run("bake", func(t *testing.T) {
|
||||
gg, err = defaultEnvoy.Bake(ctx, envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": defaultStore,
|
||||
"dal": defaultDal,
|
||||
},
|
||||
}, nil, nodes...)
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
t.Run("import into DB", func(t *testing.T) {
|
||||
err = defaultEnvoy.Encode(ctx, envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": defaultStore,
|
||||
"dal": defaultDal,
|
||||
},
|
||||
}, gg)
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
assertFullState(ctx, t, defaultStore, req)
|
||||
})
|
||||
|
||||
// Prepare a temp file where we'll dump the YAML into
|
||||
auxFile, err := os.CreateTemp(os.TempDir(), "*.yaml")
|
||||
req.NoError(err)
|
||||
spew.Dump(auxFile.Name())
|
||||
// defer os.Remove(auxFile.Name())
|
||||
defer auxFile.Close()
|
||||
|
||||
t.Run("export", func(t *testing.T) {
|
||||
t.Run("export from DB", func(t *testing.T) {
|
||||
nodes, _, err = defaultEnvoy.Decode(ctx, envoyx.DecodeParams{
|
||||
Type: envoyx.DecodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": defaultStore,
|
||||
"dal": defaultDal,
|
||||
},
|
||||
Filter: map[string]envoyx.ResourceFilter{
|
||||
types.ChartResourceType: {},
|
||||
types.ModuleResourceType: {},
|
||||
types.NamespaceResourceType: {},
|
||||
types.PageResourceType: {},
|
||||
types.PageLayoutResourceType: {},
|
||||
|
||||
systemTypes.ApplicationResourceType: {},
|
||||
systemTypes.ApigwRouteResourceType: {},
|
||||
systemTypes.AuthClientResourceType: {},
|
||||
systemTypes.QueueResourceType: {},
|
||||
systemTypes.ReportResourceType: {},
|
||||
systemTypes.RoleResourceType: {},
|
||||
systemTypes.TemplateResourceType: {},
|
||||
systemTypes.UserResourceType: {},
|
||||
systemTypes.DalConnectionResourceType: {},
|
||||
systemTypes.DalSensitivityLevelResourceType: {},
|
||||
|
||||
automationTypes.WorkflowResourceType: {},
|
||||
},
|
||||
})
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
t.Run("bake", func(t *testing.T) {
|
||||
gg, err = defaultEnvoy.Bake(ctx, envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": defaultStore,
|
||||
"dal": defaultDal,
|
||||
},
|
||||
}, nil, nodes...)
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
t.Run("write file", func(t *testing.T) {
|
||||
err = defaultEnvoy.Encode(ctx, envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeIo,
|
||||
Params: map[string]any{
|
||||
"writer": auxFile,
|
||||
},
|
||||
}, gg)
|
||||
req.NoError(err)
|
||||
})
|
||||
})
|
||||
|
||||
cleanup(t)
|
||||
|
||||
t.Run("second import", func(t *testing.T) {
|
||||
t.Run("yaml parse", func(t *testing.T) {
|
||||
nodes, _, err = defaultEnvoy.Decode(ctx, envoyx.DecodeParams{
|
||||
Type: envoyx.DecodeTypeURI,
|
||||
Params: map[string]any{
|
||||
"uri": fmt.Sprintf("file://%s", auxFile.Name()),
|
||||
},
|
||||
})
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
t.Run("bake", func(t *testing.T) {
|
||||
gg, err = defaultEnvoy.Bake(ctx, envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": defaultStore,
|
||||
"dal": defaultDal,
|
||||
},
|
||||
}, nil, nodes...)
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
t.Run("run import", func(t *testing.T) {
|
||||
err = defaultEnvoy.Encode(ctx, envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": defaultStore,
|
||||
"dal": defaultDal,
|
||||
},
|
||||
}, gg)
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
assertFullState(ctx, t, defaultStore, req)
|
||||
})
|
||||
}
|
||||
|
||||
func assertFullState(ctx context.Context, t *testing.T, s store.Storer, req *require.Assertions) {
|
||||
t.Run("check state", func(t *testing.T) {
|
||||
t.Run("corteza::compose", func(t *testing.T) {
|
||||
// Namespaces
|
||||
ns, err := store.LookupComposeNamespaceBySlug(ctx, s, "test_ns_1")
|
||||
req.NoError(err)
|
||||
req.NotNil(ns)
|
||||
|
||||
// Modules
|
||||
modules, _, err := store.SearchComposeModules(ctx, s, types.ModuleFilter{
|
||||
NamespaceID: ns.ID,
|
||||
Sorting: filter.Sorting{
|
||||
Sort: filter.SortExprSet{{Column: "handle", Descending: false}},
|
||||
},
|
||||
})
|
||||
req.NoError(err)
|
||||
|
||||
mod1 := modules.FindByHandle("test_ns_1_mod_1")
|
||||
req.NotNil(mod1)
|
||||
|
||||
mod2 := modules.FindByHandle("test_ns_1_mod_2")
|
||||
req.NotNil(mod2)
|
||||
|
||||
// Fields
|
||||
fields, _, err := store.SearchComposeModuleFields(ctx, s, types.ModuleFieldFilter{
|
||||
ModuleID: []uint64{mod1.ID, mod2.ID},
|
||||
})
|
||||
req.NoError(err)
|
||||
|
||||
assignModuleFields(modules, fields)
|
||||
|
||||
req.Len(mod1.Fields, 2)
|
||||
req.Len(mod2.Fields, 2)
|
||||
|
||||
req.Equal(mod1.ID, mod2.Fields.FindByName("test_ns_1_mod_2_f1").Options.UInt64("moduleID"))
|
||||
req.Equal(mod2.ID, mod2.Fields.FindByName("test_ns_1_mod_2_f2").Options.UInt64("moduleID"))
|
||||
|
||||
// Charts
|
||||
charts, _, err := store.SearchComposeCharts(ctx, s, types.ChartFilter{
|
||||
NamespaceID: ns.ID,
|
||||
})
|
||||
req.NoError(err)
|
||||
ch1 := charts.FindByHandle("test_ns_1_chart_1")
|
||||
req.NotNil(ch1)
|
||||
|
||||
req.Equal(mod1.ID, ch1.Config.Reports[0].ModuleID)
|
||||
req.Equal(mod2.ID, ch1.Config.Reports[1].ModuleID)
|
||||
|
||||
// Pages
|
||||
pages, _, err := store.SearchComposePages(ctx, s, types.PageFilter{
|
||||
NamespaceID: ns.ID,
|
||||
})
|
||||
req.NoError(err)
|
||||
|
||||
pg1 := pages.FindByHandle("test_ns_1_page_1")
|
||||
req.NotNil(pg1)
|
||||
|
||||
req.Len(pg1.Blocks, 8)
|
||||
// @todo test page block references
|
||||
// spew.Dump(pg1.Blocks)
|
||||
|
||||
rpg1 := pages.FindByHandle("test_ns_1_record_page_1")
|
||||
req.NotNil(rpg1)
|
||||
req.Equal(mod1.ID, rpg1.ModuleID)
|
||||
|
||||
// Page layouts
|
||||
layouts, _, err := store.SearchComposePageLayouts(ctx, s, types.PageLayoutFilter{
|
||||
NamespaceID: ns.ID,
|
||||
})
|
||||
req.NoError(err)
|
||||
|
||||
ly1 := layouts.FindByHandle("test_ns_1_page_1_layout_1")
|
||||
req.NotNil(ly1)
|
||||
|
||||
ly2 := layouts.FindByHandle("test_ns_1_page_1_layout_2")
|
||||
req.NotNil(ly2)
|
||||
|
||||
// Record page layouts
|
||||
ly3 := layouts.FindByHandle("test_ns_1_record_page_1_layout_1")
|
||||
req.NotNil(ly3)
|
||||
|
||||
ly4 := layouts.FindByHandle("test_ns_1_record_page_1_layout_2")
|
||||
req.NotNil(ly4)
|
||||
})
|
||||
t.Run("corteza::system", func(t *testing.T) {
|
||||
// Users
|
||||
users, _, err := store.SearchUsers(ctx, s, systemTypes.UserFilter{})
|
||||
req.NoError(err)
|
||||
req.Len(users, 1)
|
||||
|
||||
u1 := users[0]
|
||||
req.Equal("test_user_1", u1.Handle)
|
||||
|
||||
// ApigwRoutes
|
||||
apigwroutes, _, err := store.SearchApigwRoutes(ctx, s, systemTypes.ApigwRouteFilter{})
|
||||
req.NoError(err)
|
||||
req.Len(apigwroutes, 1)
|
||||
|
||||
r1 := apigwroutes[0]
|
||||
req.Equal("/test/endpoint/1", r1.Endpoint)
|
||||
req.Equal(u1.ID, r1.CreatedBy)
|
||||
req.Equal(u1.ID, r1.UpdatedBy)
|
||||
|
||||
// ApigwFilters
|
||||
apigwfilter, _, err := store.SearchApigwFilters(ctx, s, systemTypes.ApigwFilterFilter{})
|
||||
req.NoError(err)
|
||||
req.Len(apigwfilter, 1)
|
||||
|
||||
f1 := apigwfilter[0]
|
||||
req.Equal(r1.ID, f1.Route)
|
||||
|
||||
// AuthClients
|
||||
clients, _, err := store.SearchAuthClients(ctx, s, systemTypes.AuthClientFilter{})
|
||||
req.NoError(err)
|
||||
req.Len(clients, 1)
|
||||
|
||||
c1 := clients[0]
|
||||
req.Equal("test_authclient_1", c1.Handle)
|
||||
req.Equal(u1.ID, c1.OwnedBy)
|
||||
req.Equal(u1.ID, c1.CreatedBy)
|
||||
req.Equal(u1.ID, c1.UpdatedBy)
|
||||
|
||||
// Queues
|
||||
queues, _, err := store.SearchQueues(ctx, s, systemTypes.QueueFilter{})
|
||||
req.NoError(err)
|
||||
req.Len(queues, 1)
|
||||
|
||||
q1 := queues[0]
|
||||
req.Equal("test_queue_1", q1.Queue)
|
||||
req.Equal(u1.ID, q1.CreatedBy)
|
||||
req.Equal(u1.ID, q1.UpdatedBy)
|
||||
|
||||
// Reports
|
||||
reports, _, err := store.SearchReports(ctx, s, systemTypes.ReportFilter{})
|
||||
req.NoError(err)
|
||||
req.Len(reports, 1)
|
||||
|
||||
rp1 := reports[0]
|
||||
req.Equal("test_report_1", rp1.Handle)
|
||||
req.Equal(u1.ID, rp1.OwnedBy)
|
||||
req.Equal(u1.ID, rp1.CreatedBy)
|
||||
req.Equal(u1.ID, rp1.UpdatedBy)
|
||||
|
||||
// Roles
|
||||
roles, _, err := store.SearchRoles(ctx, s, systemTypes.RoleFilter{})
|
||||
req.NoError(err)
|
||||
|
||||
rl1 := roles[0]
|
||||
req.Equal("test_role_1", rl1.Handle)
|
||||
|
||||
// Templates
|
||||
templates, _, err := store.SearchTemplates(ctx, s, systemTypes.TemplateFilter{})
|
||||
req.NoError(err)
|
||||
req.Len(templates, 1)
|
||||
|
||||
tpl1 := templates[0]
|
||||
req.Equal("test_template_1", tpl1.Handle)
|
||||
req.Equal(u1.ID, tpl1.OwnerID)
|
||||
|
||||
// DalConnections
|
||||
connections, _, err := store.SearchDalConnections(ctx, s, systemTypes.DalConnectionFilter{})
|
||||
req.NoError(err)
|
||||
req.Len(connections, 1)
|
||||
conn1 := connections[0]
|
||||
req.Equal("test_connection_1", conn1.Handle)
|
||||
|
||||
req.Equal(u1.ID, conn1.CreatedBy)
|
||||
req.Equal(u1.ID, conn1.UpdatedBy)
|
||||
|
||||
// DalSensitivityLevels
|
||||
dalsensitivitylevels, _, err := store.SearchDalSensitivityLevels(ctx, s, systemTypes.DalSensitivityLevelFilter{})
|
||||
req.NoError(err)
|
||||
req.Len(dalsensitivitylevels, 1)
|
||||
sens1 := dalsensitivitylevels[0]
|
||||
|
||||
req.Equal("test_sensitivity_level_1", sens1.Handle)
|
||||
req.Equal(u1.ID, sens1.CreatedBy)
|
||||
req.Equal(u1.ID, sens1.UpdatedBy)
|
||||
})
|
||||
t.Run("corteza::automation", func(t *testing.T) {
|
||||
// Workflows
|
||||
workflows, _, err := store.SearchAutomationWorkflows(ctx, s, automationTypes.WorkflowFilter{})
|
||||
req.NoError(err)
|
||||
req.Len(workflows, 1)
|
||||
|
||||
wf1 := workflows[0]
|
||||
req.Equal("test_workflow_1", wf1.Handle)
|
||||
|
||||
// Triggers
|
||||
triggers, _, err := store.SearchAutomationTriggers(ctx, s, automationTypes.TriggerFilter{})
|
||||
req.NoError(err)
|
||||
req.Len(triggers, 1)
|
||||
|
||||
t1 := triggers[0]
|
||||
req.Equal(wf1.ID, t1.WorkflowID)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func assignModuleFields(modules types.ModuleSet, fields types.ModuleFieldSet) {
|
||||
for _, m := range modules {
|
||||
for _, f := range fields {
|
||||
if m.ID == f.ModuleID {
|
||||
m.Fields = append(m.Fields, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
191
server/tests/envoy/main_test.go
Normal file
191
server/tests/envoy/main_test.go
Normal file
@@ -0,0 +1,191 @@
|
||||
package envoy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
automationEnvoy "github.com/cortezaproject/corteza/server/automation/envoy"
|
||||
composeEnvoy "github.com/cortezaproject/corteza/server/compose/envoy"
|
||||
systemEnvoy "github.com/cortezaproject/corteza/server/system/envoy"
|
||||
"github.com/cortezaproject/corteza/server/tests/helpers"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/pkg/cli"
|
||||
"github.com/cortezaproject/corteza/server/pkg/dal"
|
||||
"github.com/cortezaproject/corteza/server/pkg/envoyx"
|
||||
"github.com/cortezaproject/corteza/server/pkg/id"
|
||||
"github.com/cortezaproject/corteza/server/store"
|
||||
"github.com/cortezaproject/corteza/server/system/service"
|
||||
sysTypes "github.com/cortezaproject/corteza/server/system/types"
|
||||
_ "github.com/joho/godotenv/autoload"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var (
|
||||
defaultEnvoy *envoyx.Service
|
||||
defaultStore store.Storer
|
||||
defaultDal dal.FullService
|
||||
)
|
||||
|
||||
func init() {
|
||||
helpers.RecursiveDotEnvLoad()
|
||||
id.Init(cli.Context())
|
||||
}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
InitTestApp()
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func InitTestApp() {
|
||||
ctx := cli.Context()
|
||||
|
||||
if defaultStore == nil {
|
||||
initStore(ctx)
|
||||
}
|
||||
|
||||
if defaultDal == nil {
|
||||
initDalSvc(ctx)
|
||||
}
|
||||
|
||||
if defaultEnvoy == nil {
|
||||
initSvc(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
func initStore(ctx context.Context) {
|
||||
var err error
|
||||
dsn := "sqlite3+debug://file::memory:?cache=shared&mode=memory"
|
||||
defaultStore, err = store.Connect(ctx, zap.NewNop(), dsn, true)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = store.Upgrade(ctx, zap.NewNop(), defaultStore)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func initDalSvc(ctx context.Context) {
|
||||
var err error
|
||||
defaultDal, err = dal.New(zap.NewNop(), true)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
conn := &sysTypes.DalConnection{
|
||||
ID: id.Next(),
|
||||
Handle: sysTypes.DalPrimaryConnectionHandle,
|
||||
Type: sysTypes.DalPrimaryConnectionResourceType,
|
||||
|
||||
Meta: sysTypes.ConnectionMeta{
|
||||
Name: "Primary Database",
|
||||
},
|
||||
|
||||
Config: sysTypes.ConnectionConfig{
|
||||
DAL: &sysTypes.ConnectionConfigDAL{
|
||||
ModelIdent: "compose_record",
|
||||
},
|
||||
},
|
||||
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
|
||||
cw, err := service.MakeDalConnection(conn, defaultStore.ToDalConn())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = defaultDal.ReplaceConnection(ctx, cw, true)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func cleanup(t *testing.T) {
|
||||
var (
|
||||
ctx = context.Background()
|
||||
)
|
||||
|
||||
err := collect(
|
||||
store.TruncateComposeCharts(ctx, defaultStore),
|
||||
store.TruncateComposeModules(ctx, defaultStore),
|
||||
store.TruncateComposeModuleFields(ctx, defaultStore),
|
||||
store.TruncateComposeNamespaces(ctx, defaultStore),
|
||||
store.TruncateComposePages(ctx, defaultStore),
|
||||
|
||||
store.TruncateApplications(ctx, defaultStore),
|
||||
store.TruncateApigwRoutes(ctx, defaultStore),
|
||||
store.TruncateApigwFilters(ctx, defaultStore),
|
||||
store.TruncateAuthClients(ctx, defaultStore),
|
||||
store.TruncateQueues(ctx, defaultStore),
|
||||
store.TruncateReports(ctx, defaultStore),
|
||||
store.TruncateRoles(ctx, defaultStore),
|
||||
store.TruncateTemplates(ctx, defaultStore),
|
||||
store.TruncateUsers(ctx, defaultStore),
|
||||
store.TruncateDalConnections(ctx, defaultStore),
|
||||
store.TruncateDalSensitivityLevels(ctx, defaultStore),
|
||||
store.TruncateRbacRules(ctx, defaultStore),
|
||||
store.TruncateResourceTranslations(ctx, defaultStore),
|
||||
|
||||
store.TruncateAutomationWorkflows(ctx, defaultStore),
|
||||
store.TruncateAutomationTriggers(ctx, defaultStore),
|
||||
|
||||
truncateRecords(ctx),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to decode scenario data: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func truncateRecords(ctx context.Context) error {
|
||||
models, err := defaultDal.SearchModels(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, model := range models {
|
||||
err = defaultDal.Truncate(ctx, model.ToFilter(), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func collect(ee ...error) error {
|
||||
for _, e := range ee {
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func initSvc(ctx context.Context) {
|
||||
defaultEnvoy = envoyx.New()
|
||||
defaultEnvoy.AddDecoder(envoyx.DecodeTypeURI,
|
||||
composeEnvoy.YamlDecoder{},
|
||||
systemEnvoy.YamlDecoder{},
|
||||
automationEnvoy.YamlDecoder{},
|
||||
)
|
||||
defaultEnvoy.AddDecoder(envoyx.DecodeTypeStore,
|
||||
composeEnvoy.StoreDecoder{},
|
||||
systemEnvoy.StoreDecoder{},
|
||||
automationEnvoy.StoreDecoder{},
|
||||
)
|
||||
|
||||
defaultEnvoy.AddEncoder(envoyx.EncodeTypeIo,
|
||||
composeEnvoy.YamlEncoder{},
|
||||
systemEnvoy.YamlEncoder{},
|
||||
automationEnvoy.YamlEncoder{},
|
||||
)
|
||||
defaultEnvoy.AddEncoder(envoyx.EncodeTypeStore,
|
||||
composeEnvoy.StoreEncoder{},
|
||||
systemEnvoy.StoreEncoder{},
|
||||
automationEnvoy.StoreEncoder{},
|
||||
)
|
||||
defaultEnvoy.AddEncoder(envoyx.EncodeTypeIo,
|
||||
composeEnvoy.CsvEncoder{},
|
||||
)
|
||||
}
|
||||
260
server/tests/envoy/rbac_rules_test.go
Normal file
260
server/tests/envoy/rbac_rules_test.go
Normal file
@@ -0,0 +1,260 @@
|
||||
package envoy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/compose/types"
|
||||
"github.com/cortezaproject/corteza/server/pkg/envoyx"
|
||||
"github.com/cortezaproject/corteza/server/pkg/rbac"
|
||||
"github.com/cortezaproject/corteza/server/store"
|
||||
systemTypes "github.com/cortezaproject/corteza/server/system/types"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestRbacImportExport(t *testing.T) {
|
||||
var (
|
||||
ctx = context.Background()
|
||||
req = require.New(t)
|
||||
nodes envoyx.NodeSet
|
||||
gg *envoyx.DepGraph
|
||||
err error
|
||||
)
|
||||
|
||||
cleanup(t)
|
||||
|
||||
// The test
|
||||
//
|
||||
// * imports some YAML files
|
||||
// * checks the DB state
|
||||
// * exports the DB into a YAML
|
||||
// * clears the DB
|
||||
// * imports the YAML
|
||||
// * checks the DB state the same way as before
|
||||
//
|
||||
// The above outlined flow allows us to trivially check if the data is both
|
||||
// imported and exported correctly.
|
||||
//
|
||||
// The initial step could also manually populate the DB but the YAML import
|
||||
// is more convenient.
|
||||
|
||||
t.Run("initial import", func(t *testing.T) {
|
||||
t.Run("parse configs", func(t *testing.T) {
|
||||
nodes, _, err = defaultEnvoy.Decode(ctx, envoyx.DecodeParams{
|
||||
Type: envoyx.DecodeTypeURI,
|
||||
Params: map[string]any{
|
||||
"uri": "file://testdata/rbac",
|
||||
},
|
||||
})
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
t.Run("bake", func(t *testing.T) {
|
||||
gg, err = defaultEnvoy.Bake(ctx, envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": defaultStore,
|
||||
"dal": defaultDal,
|
||||
},
|
||||
}, nil, nodes...)
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
t.Run("import into DB", func(t *testing.T) {
|
||||
err = defaultEnvoy.Encode(ctx, envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": defaultStore,
|
||||
"dal": defaultDal,
|
||||
},
|
||||
}, gg)
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
assertRBACState(ctx, t, defaultStore, req)
|
||||
})
|
||||
|
||||
// Prepare a temp file where we'll dump the YAML into
|
||||
auxFile, err := os.CreateTemp(os.TempDir(), "*.yaml")
|
||||
req.NoError(err)
|
||||
spew.Dump(auxFile.Name())
|
||||
// defer os.Remove(auxFile.Name())
|
||||
defer auxFile.Close()
|
||||
|
||||
var rules envoyx.NodeSet
|
||||
t.Run("export", func(t *testing.T) {
|
||||
t.Run("export from DB", func(t *testing.T) {
|
||||
nodes, _, err = defaultEnvoy.Decode(ctx, envoyx.DecodeParams{
|
||||
Type: envoyx.DecodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": defaultStore,
|
||||
"dal": defaultDal,
|
||||
},
|
||||
Filter: map[string]envoyx.ResourceFilter{
|
||||
types.ModuleResourceType: {},
|
||||
types.NamespaceResourceType: {},
|
||||
|
||||
systemTypes.RoleResourceType: {},
|
||||
},
|
||||
})
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
var rr rbac.RuleSet
|
||||
t.Run("get all rules", func(t *testing.T) {
|
||||
rr, _, err = store.SearchRbacRules(ctx, defaultStore, rbac.RuleFilter{})
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
t.Run("connect rules to resources", func(t *testing.T) {
|
||||
rules, err = envoyx.RBACRulesForNodes(rr, nodes...)
|
||||
req.NoError(err)
|
||||
|
||||
nodes = append(nodes, rules...)
|
||||
})
|
||||
|
||||
t.Run("bake", func(t *testing.T) {
|
||||
gg, err = defaultEnvoy.Bake(ctx, envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": defaultStore,
|
||||
"dal": defaultDal,
|
||||
},
|
||||
}, nil, nodes...)
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
t.Run("write file", func(t *testing.T) {
|
||||
err = defaultEnvoy.Encode(ctx, envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeIo,
|
||||
Params: map[string]any{
|
||||
"writer": auxFile,
|
||||
},
|
||||
}, gg)
|
||||
req.NoError(err)
|
||||
})
|
||||
})
|
||||
|
||||
cleanup(t)
|
||||
|
||||
t.Run("second import", func(t *testing.T) {
|
||||
t.Run("yaml parse", func(t *testing.T) {
|
||||
nodes, _, err = defaultEnvoy.Decode(ctx, envoyx.DecodeParams{
|
||||
Type: envoyx.DecodeTypeURI,
|
||||
Params: map[string]any{
|
||||
"uri": fmt.Sprintf("file://%s", auxFile.Name()),
|
||||
},
|
||||
})
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
t.Run("bake", func(t *testing.T) {
|
||||
gg, err = defaultEnvoy.Bake(ctx, envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": defaultStore,
|
||||
"dal": defaultDal,
|
||||
},
|
||||
}, nil, nodes...)
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
t.Run("run import", func(t *testing.T) {
|
||||
err = defaultEnvoy.Encode(ctx, envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": defaultStore,
|
||||
"dal": defaultDal,
|
||||
},
|
||||
}, gg)
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
assertRBACState(ctx, t, defaultStore, req)
|
||||
})
|
||||
}
|
||||
|
||||
func assertRBACState(ctx context.Context, t *testing.T, s store.Storer, req *require.Assertions) {
|
||||
t.Run("check state", func(t *testing.T) {
|
||||
namespaces, _, err := store.SearchComposeNamespaces(ctx, defaultStore, types.NamespaceFilter{})
|
||||
req.NoError(err)
|
||||
ns1 := namespaces[0]
|
||||
|
||||
modules, _, err := store.SearchComposeModules(ctx, defaultStore, types.ModuleFilter{})
|
||||
req.NoError(err)
|
||||
mod1 := modules[0]
|
||||
|
||||
roles, _, err := store.SearchRoles(ctx, defaultStore, systemTypes.RoleFilter{})
|
||||
req.NoError(err)
|
||||
role1 := roles.FindByHandle("test_role_1")
|
||||
role2 := roles.FindByHandle("test_role_2")
|
||||
|
||||
rr, _, err := store.SearchRbacRules(ctx, defaultStore, rbac.RuleFilter{})
|
||||
req.NoError(err)
|
||||
|
||||
allows := rr.FilterAccess(rbac.Allow)
|
||||
compareRules(req, *allows.FilterOperation("op2")[0], rbac.Rule{
|
||||
RoleID: role1.ID,
|
||||
Resource: fmt.Sprintf("corteza::compose:namespace/%d", ns1.ID),
|
||||
Operation: "op2",
|
||||
Access: rbac.Allow,
|
||||
})
|
||||
|
||||
compareRules(req, *allows.FilterOperation("op3")[0], rbac.Rule{
|
||||
RoleID: role1.ID,
|
||||
Resource: fmt.Sprintf("corteza::compose:module/%d/*", ns1.ID),
|
||||
Operation: "op3",
|
||||
Access: rbac.Allow,
|
||||
})
|
||||
|
||||
compareRules(req, *allows.FilterOperation("op4")[0], rbac.Rule{
|
||||
RoleID: role1.ID,
|
||||
Resource: fmt.Sprintf("corteza::compose:module/%d/%d", ns1.ID, mod1.ID),
|
||||
Operation: "op4",
|
||||
Access: rbac.Allow,
|
||||
})
|
||||
|
||||
denies := rr.FilterAccess(rbac.Deny)
|
||||
compareRules(req, *denies.FilterOperation("op2")[0], rbac.Rule{
|
||||
RoleID: role2.ID,
|
||||
Resource: fmt.Sprintf("corteza::compose:namespace/%d", ns1.ID),
|
||||
Operation: "op2",
|
||||
Access: rbac.Deny,
|
||||
})
|
||||
|
||||
compareRules(req, *denies.FilterOperation("op3")[0], rbac.Rule{
|
||||
RoleID: role2.ID,
|
||||
Resource: fmt.Sprintf("corteza::compose:module/%d/*", ns1.ID),
|
||||
Operation: "op3",
|
||||
Access: rbac.Deny,
|
||||
})
|
||||
|
||||
compareRules(req, *denies.FilterOperation("op4")[0], rbac.Rule{
|
||||
RoleID: role2.ID,
|
||||
Resource: fmt.Sprintf("corteza::compose:module/%d/%d", ns1.ID, mod1.ID),
|
||||
Operation: "op4",
|
||||
Access: rbac.Deny,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func compareRules(req *require.Assertions, a, b rbac.Rule) {
|
||||
if a.RoleID != b.RoleID {
|
||||
req.FailNow("RoleID missmatch")
|
||||
}
|
||||
|
||||
if a.Resource != b.Resource {
|
||||
req.FailNow("Resource missmatch")
|
||||
}
|
||||
|
||||
if a.Operation != b.Operation {
|
||||
req.FailNow("Operation missmatch")
|
||||
}
|
||||
|
||||
if a.Access != b.Access {
|
||||
req.FailNow("Access missmatch")
|
||||
}
|
||||
}
|
||||
374
server/tests/envoy/records_test.go
Normal file
374
server/tests/envoy/records_test.go
Normal file
@@ -0,0 +1,374 @@
|
||||
package envoy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/compose/dalutils"
|
||||
"github.com/cortezaproject/corteza/server/compose/envoy"
|
||||
"github.com/cortezaproject/corteza/server/compose/types"
|
||||
"github.com/cortezaproject/corteza/server/pkg/dal"
|
||||
"github.com/cortezaproject/corteza/server/pkg/envoyx"
|
||||
"github.com/cortezaproject/corteza/server/store"
|
||||
systemTypes "github.com/cortezaproject/corteza/server/system/types"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestRecordsImportExport(t *testing.T) {
|
||||
var (
|
||||
ctx = context.Background()
|
||||
req = require.New(t)
|
||||
nodes envoyx.NodeSet
|
||||
providers []envoyx.Provider
|
||||
gg *envoyx.DepGraph
|
||||
err error
|
||||
)
|
||||
_ = gg
|
||||
|
||||
cleanup(t)
|
||||
|
||||
// The test
|
||||
//
|
||||
// * imports some YAML files
|
||||
// * checks the DB state
|
||||
// * exports the DB into a YAML
|
||||
// * clears the DB
|
||||
// * imports the YAML
|
||||
// * checks the DB state the same way as before
|
||||
//
|
||||
// The above outlined flow allows us to trivially check if the data is both
|
||||
// imported and exported correctly.
|
||||
//
|
||||
// The initial step could also manually populate the DB but the YAML import
|
||||
// is more convenient.
|
||||
|
||||
t.Run("initial import", func(t *testing.T) {
|
||||
t.Run("parse configs", func(t *testing.T) {
|
||||
nodes, providers, err = defaultEnvoy.Decode(ctx, envoyx.DecodeParams{
|
||||
Type: envoyx.DecodeTypeURI,
|
||||
Params: map[string]any{
|
||||
"uri": "file://testdata/datasource_records",
|
||||
},
|
||||
})
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
t.Run("bake", func(t *testing.T) {
|
||||
gg, err = defaultEnvoy.Bake(ctx, envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": defaultStore,
|
||||
"dal": defaultDal,
|
||||
},
|
||||
}, providers, nodes...)
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
t.Run("import into DB", func(t *testing.T) {
|
||||
err = defaultEnvoy.Encode(ctx, envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": defaultStore,
|
||||
"dal": defaultDal,
|
||||
},
|
||||
}, gg)
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
assertRecordState(ctx, t, defaultStore, defaultDal, req)
|
||||
})
|
||||
|
||||
// Prepare a temp file where we'll dump the YAML into
|
||||
auxFile, err := os.CreateTemp(os.TempDir(), "*.csv")
|
||||
req.NoError(err)
|
||||
spew.Dump(auxFile.Name())
|
||||
// defer os.Remove(auxFile.Name())
|
||||
defer auxFile.Close()
|
||||
|
||||
t.Run("export", func(t *testing.T) {
|
||||
t.Run("export from DB", func(t *testing.T) {
|
||||
nodes, _, err = defaultEnvoy.Decode(ctx, envoyx.DecodeParams{
|
||||
Type: envoyx.DecodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": defaultStore,
|
||||
"dal": defaultDal,
|
||||
},
|
||||
Filter: map[string]envoyx.ResourceFilter{
|
||||
envoy.ComposeRecordDatasourceAuxType: {
|
||||
Refs: map[string]envoyx.Ref{
|
||||
"NamespaceID": {
|
||||
ResourceType: types.NamespaceResourceType,
|
||||
Identifiers: envoyx.MakeIdentifiers("test_ns_1"),
|
||||
Scope: envoyx.Scope{
|
||||
ResourceType: types.NamespaceResourceType,
|
||||
Identifiers: envoyx.MakeIdentifiers("test_ns_1")},
|
||||
},
|
||||
"ModuleID": {
|
||||
ResourceType: types.ModuleResourceType,
|
||||
Identifiers: envoyx.MakeIdentifiers("test_ns_1_mod_1"),
|
||||
Scope: envoyx.Scope{
|
||||
ResourceType: types.NamespaceResourceType,
|
||||
Identifiers: envoyx.MakeIdentifiers("test_ns_1"),
|
||||
},
|
||||
},
|
||||
},
|
||||
Scope: envoyx.Scope{
|
||||
ResourceType: types.NamespaceResourceType,
|
||||
Identifiers: envoyx.MakeIdentifiers("test_ns_1"),
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
t.Run("bake", func(t *testing.T) {
|
||||
gg, err = defaultEnvoy.Bake(ctx, envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": defaultStore,
|
||||
"dal": defaultDal,
|
||||
},
|
||||
}, nil, nodes...)
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
t.Run("write file", func(t *testing.T) {
|
||||
err = defaultEnvoy.Encode(ctx, envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeIo,
|
||||
Params: map[string]any{
|
||||
"writer": auxFile,
|
||||
},
|
||||
}, gg)
|
||||
req.NoError(err)
|
||||
})
|
||||
})
|
||||
|
||||
cleanup(t)
|
||||
|
||||
t.Run("second import", func(t *testing.T) {
|
||||
t.Run("yaml parse", func(t *testing.T) {
|
||||
nodes, _, err = defaultEnvoy.Decode(ctx, envoyx.DecodeParams{
|
||||
Type: envoyx.DecodeTypeURI,
|
||||
Params: map[string]any{
|
||||
"uri": "file://testdata/datasource_records",
|
||||
},
|
||||
})
|
||||
req.NoError(err)
|
||||
|
||||
_, providers, err = defaultEnvoy.Decode(ctx, envoyx.DecodeParams{
|
||||
Type: envoyx.DecodeTypeURI,
|
||||
Params: map[string]any{
|
||||
"uri": fmt.Sprintf("file://%s", auxFile.Name()),
|
||||
},
|
||||
})
|
||||
req.NoError(err)
|
||||
for _, p := range providers {
|
||||
p.SetIdent("records.csv")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("bake", func(t *testing.T) {
|
||||
gg, err = defaultEnvoy.Bake(ctx, envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": defaultStore,
|
||||
"dal": defaultDal,
|
||||
},
|
||||
}, providers, nodes...)
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
t.Run("run import", func(t *testing.T) {
|
||||
err = defaultEnvoy.Encode(ctx, envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": defaultStore,
|
||||
"dal": defaultDal,
|
||||
},
|
||||
}, gg)
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
assertRecordState(ctx, t, defaultStore, defaultDal, req)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRecordsXrefs(t *testing.T) {
|
||||
var (
|
||||
ctx = context.Background()
|
||||
req = require.New(t)
|
||||
nodes envoyx.NodeSet
|
||||
providers []envoyx.Provider
|
||||
gg *envoyx.DepGraph
|
||||
err error
|
||||
)
|
||||
_ = gg
|
||||
|
||||
cleanup(t)
|
||||
|
||||
t.Run("parse configs", func(t *testing.T) {
|
||||
nodes, providers, err = defaultEnvoy.Decode(ctx, envoyx.DecodeParams{
|
||||
Type: envoyx.DecodeTypeURI,
|
||||
Params: map[string]any{
|
||||
"uri": "file://testdata/records/cross_ref",
|
||||
},
|
||||
})
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
t.Run("bake", func(t *testing.T) {
|
||||
gg, err = defaultEnvoy.Bake(ctx, envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": defaultStore,
|
||||
"dal": defaultDal,
|
||||
},
|
||||
}, providers, nodes...)
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
t.Run("import into DB", func(t *testing.T) {
|
||||
err = defaultEnvoy.Encode(ctx, envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": defaultStore,
|
||||
"dal": defaultDal,
|
||||
},
|
||||
}, gg)
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
ns, err := store.LookupComposeNamespaceBySlug(ctx, defaultStore, "test_ns")
|
||||
req.NoError(err)
|
||||
|
||||
modParent, err := store.LookupComposeModuleByNamespaceIDHandle(ctx, defaultStore, ns.ID, "mod_parent")
|
||||
req.NoError(err)
|
||||
|
||||
modChild, err := store.LookupComposeModuleByNamespaceIDHandle(ctx, defaultStore, ns.ID, "mod_child")
|
||||
req.NoError(err)
|
||||
|
||||
parentRecords, _, err := dalutils.ComposeRecordsList(ctx, defaultDal, modParent, types.RecordFilter{})
|
||||
req.NoError(err)
|
||||
|
||||
compareValues(req, parentRecords[0].Values, types.RecordValueSet{{Name: "name", Value: "Jane Doe"}, {Name: "code", Value: "3124"}})
|
||||
compareValues(req, parentRecords[1].Values, types.RecordValueSet{{Name: "name", Value: "Ana Banana"}, {Name: "code", Value: "4153"}})
|
||||
compareValues(req, parentRecords[2].Values, types.RecordValueSet{{Name: "name", Value: "Qwerty"}, {Name: "code", Value: "83172"}})
|
||||
|
||||
childRecords, _, err := dalutils.ComposeRecordsList(ctx, defaultDal, modChild, types.RecordFilter{})
|
||||
req.NoError(err)
|
||||
|
||||
compareValues(req, childRecords[0].Values, types.RecordValueSet{{Name: "user_name", Value: "Daniel Adams", Ref: 0}, {Name: "parent", Value: strconv.FormatUint(parentRecords[0].ID, 10), Ref: parentRecords[0].ID}, {Name: "alt", Value: strconv.FormatUint(childRecords[2].ID, 10), Ref: childRecords[2].ID}})
|
||||
compareValues(req, childRecords[1].Values, types.RecordValueSet{{Name: "user_name", Value: "Jane Alex", Ref: 0}, {Name: "parent", Value: strconv.FormatUint(parentRecords[1].ID, 10), Ref: parentRecords[1].ID}, {Name: "alt", Value: strconv.FormatUint(childRecords[0].ID, 10), Ref: childRecords[0].ID}})
|
||||
compareValues(req, childRecords[2].Values, types.RecordValueSet{{Name: "user_name", Value: "Fish", Ref: 0}, {Name: "parent", Value: strconv.FormatUint(parentRecords[2].ID, 10), Ref: parentRecords[2].ID}, {Name: "alt", Value: strconv.FormatUint(childRecords[1].ID, 10), Ref: childRecords[1].ID}})
|
||||
}
|
||||
|
||||
func TestRecordsUserRefs(t *testing.T) {
|
||||
var (
|
||||
ctx = context.Background()
|
||||
req = require.New(t)
|
||||
nodes envoyx.NodeSet
|
||||
providers []envoyx.Provider
|
||||
gg *envoyx.DepGraph
|
||||
err error
|
||||
)
|
||||
_ = gg
|
||||
|
||||
cleanup(t)
|
||||
|
||||
t.Run("parse configs", func(t *testing.T) {
|
||||
nodes, providers, err = defaultEnvoy.Decode(ctx, envoyx.DecodeParams{
|
||||
Type: envoyx.DecodeTypeURI,
|
||||
Params: map[string]any{
|
||||
"uri": "file://testdata/records/user_ref",
|
||||
},
|
||||
})
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
t.Run("bake", func(t *testing.T) {
|
||||
gg, err = defaultEnvoy.Bake(ctx, envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": defaultStore,
|
||||
"dal": defaultDal,
|
||||
},
|
||||
}, providers, nodes...)
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
t.Run("import into DB", func(t *testing.T) {
|
||||
err = defaultEnvoy.Encode(ctx, envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": defaultStore,
|
||||
"dal": defaultDal,
|
||||
},
|
||||
}, gg)
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
ns, err := store.LookupComposeNamespaceBySlug(ctx, defaultStore, "test_ns")
|
||||
req.NoError(err)
|
||||
|
||||
mod, err := store.LookupComposeModuleByNamespaceIDHandle(ctx, defaultStore, ns.ID, "test_mod")
|
||||
req.NoError(err)
|
||||
|
||||
rr, _, err := dalutils.ComposeRecordsList(ctx, defaultDal, mod, types.RecordFilter{})
|
||||
req.NoError(err)
|
||||
|
||||
uu, _, err := store.SearchUsers(ctx, defaultStore, systemTypes.UserFilter{})
|
||||
req.NoError(err)
|
||||
|
||||
usr0 := uu[0]
|
||||
usr1 := uu[1]
|
||||
usr2 := uu[2]
|
||||
usrx := uu[3]
|
||||
|
||||
compareValues(req, rr[0].Values, types.RecordValueSet{{Name: "name", Value: "Jane Doe"}, {Name: "code", Value: "3124"}, {Name: "rel_user", Value: strconv.FormatUint(usr0.ID, 10), Ref: usr0.ID}})
|
||||
compareValues(req, rr[1].Values, types.RecordValueSet{{Name: "name", Value: "Ana Banana"}, {Name: "code", Value: "4153"}, {Name: "rel_user", Value: strconv.FormatUint(usr1.ID, 10), Ref: usr1.ID}})
|
||||
compareValues(req, rr[2].Values, types.RecordValueSet{{Name: "name", Value: "Qwerty"}, {Name: "code", Value: "83172"}, {Name: "rel_user", Value: strconv.FormatUint(usr2.ID, 10), Ref: usr2.ID}})
|
||||
|
||||
req.Equal(usrx.ID, rr[0].CreatedBy)
|
||||
req.Equal(usrx.ID, rr[1].CreatedBy)
|
||||
req.Equal(usrx.ID, rr[2].CreatedBy)
|
||||
}
|
||||
|
||||
func assertRecordState(ctx context.Context, t *testing.T, s store.Storer, dl dal.FullService, req *require.Assertions) {
|
||||
t.Run("check state", func(t *testing.T) {
|
||||
ns, err := store.LookupComposeNamespaceBySlug(ctx, defaultStore, "test_ns_1")
|
||||
req.NoError(err)
|
||||
|
||||
mod, err := store.LookupComposeModuleByNamespaceIDHandle(ctx, defaultStore, ns.ID, "test_ns_1_mod_1")
|
||||
req.NoError(err)
|
||||
|
||||
rr, _, err := dalutils.ComposeRecordsList(ctx, dl, mod, types.RecordFilter{})
|
||||
req.NoError(err)
|
||||
|
||||
req.Len(rr, 8)
|
||||
|
||||
compareValues(req, rr[0].Values, types.RecordValueSet{{Name: "test_ns_1_mod_1_f1", Value: "row_1_src_c1"}, {Name: "test_ns_1_mod_1_f2", Value: "row_1_src_c2"}})
|
||||
compareValues(req, rr[1].Values, types.RecordValueSet{{Name: "test_ns_1_mod_1_f1", Value: "row_2_src_c1"}, {Name: "test_ns_1_mod_1_f2", Value: "row_2_src_c2"}})
|
||||
compareValues(req, rr[2].Values, types.RecordValueSet{{Name: "test_ns_1_mod_1_f1", Value: "row_3_src_c1"}, {Name: "test_ns_1_mod_1_f2", Value: "row_3_src_c2"}})
|
||||
compareValues(req, rr[3].Values, types.RecordValueSet{{Name: "test_ns_1_mod_1_f1", Value: "row_4_src_c1"}, {Name: "test_ns_1_mod_1_f2", Value: "row_4_src_c2"}})
|
||||
compareValues(req, rr[4].Values, types.RecordValueSet{{Name: "test_ns_1_mod_1_f1", Value: "row_5_src_c1"}, {Name: "test_ns_1_mod_1_f2", Value: "row_5_src_c2"}})
|
||||
compareValues(req, rr[5].Values, types.RecordValueSet{{Name: "test_ns_1_mod_1_f1", Value: "row_6_src_c1"}, {Name: "test_ns_1_mod_1_f2", Value: "row_6_src_c2"}})
|
||||
compareValues(req, rr[6].Values, types.RecordValueSet{{Name: "test_ns_1_mod_1_f1", Value: "row_7_src_c1"}, {Name: "test_ns_1_mod_1_f2", Value: "row_7_src_c2"}})
|
||||
compareValues(req, rr[7].Values, types.RecordValueSet{{Name: "test_ns_1_mod_1_f1", Value: "row_8_src_c1"}, {Name: "test_ns_1_mod_1_f2", Value: "row_8_src_c2"}})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func compareValues(req *require.Assertions, a, b types.RecordValueSet) {
|
||||
for _, va := range a {
|
||||
vb := b.Get(va.Name, va.Place)
|
||||
req.NotNil(vb)
|
||||
|
||||
req.Equal(va.Value, vb.Value)
|
||||
}
|
||||
|
||||
}
|
||||
80
server/tests/envoy/res_tr_dup_test.go
Normal file
80
server/tests/envoy/res_tr_dup_test.go
Normal file
@@ -0,0 +1,80 @@
|
||||
package envoy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/compose/types"
|
||||
"github.com/cortezaproject/corteza/server/pkg/envoyx"
|
||||
"github.com/cortezaproject/corteza/server/store"
|
||||
systemTypes "github.com/cortezaproject/corteza/server/system/types"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
// Importing configs where the same (lang, resource, key) translation appears
|
||||
// multiple times (across files or on repeated imports) must not trip the
|
||||
// unique constraint on resource translations
|
||||
func TestResTrImportDuplicates(t *testing.T) {
|
||||
var (
|
||||
ctx = context.Background()
|
||||
req = require.New(t)
|
||||
)
|
||||
|
||||
cleanup(t)
|
||||
|
||||
runImport := func(uri string) error {
|
||||
nodes, _, err := defaultEnvoy.Decode(ctx, envoyx.DecodeParams{
|
||||
Type: envoyx.DecodeTypeURI,
|
||||
Params: map[string]any{
|
||||
"uri": uri,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
gg, err := defaultEnvoy.Bake(ctx, envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": defaultStore,
|
||||
"dal": defaultDal,
|
||||
},
|
||||
}, nil, nodes...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return defaultEnvoy.Encode(ctx, envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": defaultStore,
|
||||
"dal": defaultDal,
|
||||
},
|
||||
}, gg)
|
||||
}
|
||||
|
||||
t.Run("import with duplicated translations", func(t *testing.T) {
|
||||
req.NoError(runImport("file://testdata/locale_dup"))
|
||||
|
||||
namespaces, _, err := store.SearchComposeNamespaces(ctx, defaultStore, types.NamespaceFilter{})
|
||||
req.NoError(err)
|
||||
req.Len(namespaces, 1)
|
||||
nsRes := fmt.Sprintf("corteza::compose:namespace/%d", namespaces[0].ID)
|
||||
|
||||
ll, _, err := store.SearchResourceTranslations(ctx, defaultStore, systemTypes.ResourceTranslationFilter{})
|
||||
req.NoError(err)
|
||||
|
||||
// Only one row per (lang, resource, key) may exist; the later
|
||||
// duplicate wins and may not be silently dropped
|
||||
en := ll.FilterLanguage(language.English)
|
||||
req.Len(en.FilterResource(nsRes).FilterKey("res_tr_1"), 1)
|
||||
req.Equal("res_tr_1_text_duplicate", en.FilterResource(nsRes).FilterKey("res_tr_1")[0].Message)
|
||||
req.Len(en.FilterResource(nsRes).FilterKey("res_tr_2"), 1)
|
||||
})
|
||||
|
||||
t.Run("re-import over existing translations", func(t *testing.T) {
|
||||
req.NoError(runImport("file://testdata/locale_dup"))
|
||||
})
|
||||
}
|
||||
243
server/tests/envoy/res_tr_test.go
Normal file
243
server/tests/envoy/res_tr_test.go
Normal file
@@ -0,0 +1,243 @@
|
||||
package envoy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/compose/types"
|
||||
"github.com/cortezaproject/corteza/server/pkg/envoyx"
|
||||
"github.com/cortezaproject/corteza/server/store"
|
||||
systemTypes "github.com/cortezaproject/corteza/server/system/types"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
func TestResTrImportExport(t *testing.T) {
|
||||
var (
|
||||
ctx = context.Background()
|
||||
req = require.New(t)
|
||||
nodes envoyx.NodeSet
|
||||
gg *envoyx.DepGraph
|
||||
err error
|
||||
)
|
||||
|
||||
cleanup(t)
|
||||
|
||||
// The test
|
||||
//
|
||||
// * imports some YAML files
|
||||
// * checks the DB state
|
||||
// * exports the DB into a YAML
|
||||
// * clears the DB
|
||||
// * imports the YAML
|
||||
// * checks the DB state the same way as before
|
||||
//
|
||||
// The above outlined flow allows us to trivially check if the data is both
|
||||
// imported and exported correctly.
|
||||
//
|
||||
// The initial step could also manually populate the DB but the YAML import
|
||||
// is more convenient.
|
||||
|
||||
t.Run("initial import", func(t *testing.T) {
|
||||
t.Run("parse configs", func(t *testing.T) {
|
||||
nodes, _, err = defaultEnvoy.Decode(ctx, envoyx.DecodeParams{
|
||||
Type: envoyx.DecodeTypeURI,
|
||||
Params: map[string]any{
|
||||
"uri": "file://testdata/locale",
|
||||
},
|
||||
})
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
t.Run("bake", func(t *testing.T) {
|
||||
gg, err = defaultEnvoy.Bake(ctx, envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": defaultStore,
|
||||
"dal": defaultDal,
|
||||
},
|
||||
}, nil, nodes...)
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
t.Run("import into DB", func(t *testing.T) {
|
||||
err = defaultEnvoy.Encode(ctx, envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": defaultStore,
|
||||
"dal": defaultDal,
|
||||
},
|
||||
}, gg)
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
req.NoError(err)
|
||||
assertLocaleState(ctx, t, defaultStore, req)
|
||||
})
|
||||
|
||||
// Prepare a temp file where we'll dump the YAML into
|
||||
auxFile, err := os.CreateTemp(os.TempDir(), "*.yaml")
|
||||
req.NoError(err)
|
||||
spew.Dump(auxFile.Name())
|
||||
// defer os.Remove(auxFile.Name())
|
||||
defer auxFile.Close()
|
||||
|
||||
var translations envoyx.NodeSet
|
||||
t.Run("export", func(t *testing.T) {
|
||||
t.Run("export from DB", func(t *testing.T) {
|
||||
nodes, _, err = defaultEnvoy.Decode(ctx, envoyx.DecodeParams{
|
||||
Type: envoyx.DecodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": defaultStore,
|
||||
"dal": defaultDal,
|
||||
},
|
||||
Filter: map[string]envoyx.ResourceFilter{
|
||||
types.ModuleResourceType: {},
|
||||
types.NamespaceResourceType: {},
|
||||
|
||||
systemTypes.RoleResourceType: {},
|
||||
},
|
||||
})
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
var tt systemTypes.ResourceTranslationSet
|
||||
t.Run("get all rules", func(t *testing.T) {
|
||||
tt, _, err = store.SearchResourceTranslations(ctx, defaultStore, systemTypes.ResourceTranslationFilter{})
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
t.Run("connect rules to resources", func(t *testing.T) {
|
||||
translations, err = envoyx.ResourceTranslationsForNodes(tt, nodes...)
|
||||
req.NoError(err)
|
||||
nodes = append(nodes, translations...)
|
||||
})
|
||||
|
||||
t.Run("bake", func(t *testing.T) {
|
||||
gg, err = defaultEnvoy.Bake(ctx, envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": defaultStore,
|
||||
"dal": defaultDal,
|
||||
},
|
||||
}, nil, nodes...)
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
t.Run("write file", func(t *testing.T) {
|
||||
err = defaultEnvoy.Encode(ctx, envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeIo,
|
||||
Params: map[string]any{
|
||||
"writer": auxFile,
|
||||
},
|
||||
}, gg)
|
||||
req.NoError(err)
|
||||
})
|
||||
})
|
||||
|
||||
cleanup(t)
|
||||
|
||||
t.Run("second import", func(t *testing.T) {
|
||||
t.Run("yaml parse", func(t *testing.T) {
|
||||
nodes, _, err = defaultEnvoy.Decode(ctx, envoyx.DecodeParams{
|
||||
Type: envoyx.DecodeTypeURI,
|
||||
Params: map[string]any{
|
||||
"uri": fmt.Sprintf("file://%s", auxFile.Name()),
|
||||
},
|
||||
})
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
t.Run("bake", func(t *testing.T) {
|
||||
gg, err = defaultEnvoy.Bake(ctx, envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": defaultStore,
|
||||
"dal": defaultDal,
|
||||
},
|
||||
}, nil, nodes...)
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
t.Run("run import", func(t *testing.T) {
|
||||
err = defaultEnvoy.Encode(ctx, envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": defaultStore,
|
||||
"dal": defaultDal,
|
||||
},
|
||||
}, gg)
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
assertLocaleState(ctx, t, defaultStore, req)
|
||||
})
|
||||
}
|
||||
|
||||
func assertLocaleState(ctx context.Context, t *testing.T, s store.Storer, req *require.Assertions) {
|
||||
t.Run("check state", func(t *testing.T) {
|
||||
namespaces, _, err := store.SearchComposeNamespaces(ctx, defaultStore, types.NamespaceFilter{})
|
||||
req.NoError(err)
|
||||
ns1 := namespaces[0]
|
||||
|
||||
modules, _, err := store.SearchComposeModules(ctx, defaultStore, types.ModuleFilter{})
|
||||
req.NoError(err)
|
||||
mod1 := modules[0]
|
||||
|
||||
ll, _, err := store.SearchResourceTranslations(ctx, defaultStore, systemTypes.ResourceTranslationFilter{})
|
||||
req.NoError(err)
|
||||
|
||||
en := ll.FilterLanguage(language.English)
|
||||
compareResourceTranslations(req, *en.FilterKey("res_tr_1")[0], systemTypes.ResourceTranslation{
|
||||
Resource: fmt.Sprintf("corteza::compose:namespace/%d", ns1.ID),
|
||||
K: "res_tr_1",
|
||||
Message: "res_tr_1_text",
|
||||
})
|
||||
|
||||
compareResourceTranslations(req, *en.FilterKey("res_tr_2")[0], systemTypes.ResourceTranslation{
|
||||
Resource: fmt.Sprintf("corteza::compose:namespace/%d", ns1.ID),
|
||||
K: "res_tr_2",
|
||||
Message: "res_tr_2_text",
|
||||
})
|
||||
|
||||
compareResourceTranslations(req, *en.FilterKey("res_tr_3")[0], systemTypes.ResourceTranslation{
|
||||
Resource: fmt.Sprintf("corteza::compose:module/%d/%d", ns1.ID, mod1.ID),
|
||||
K: "res_tr_3",
|
||||
Message: "res_tr_3_text",
|
||||
})
|
||||
|
||||
de := ll.FilterLanguage(language.English)
|
||||
compareResourceTranslations(req, *de.FilterKey("res_tr_1")[0], systemTypes.ResourceTranslation{
|
||||
Resource: fmt.Sprintf("corteza::compose:namespace/%d", ns1.ID),
|
||||
K: "res_tr_1",
|
||||
Message: "res_tr_1_text",
|
||||
})
|
||||
|
||||
compareResourceTranslations(req, *de.FilterKey("res_tr_2")[0], systemTypes.ResourceTranslation{
|
||||
Resource: fmt.Sprintf("corteza::compose:namespace/%d", ns1.ID),
|
||||
K: "res_tr_2",
|
||||
Message: "res_tr_2_text",
|
||||
})
|
||||
|
||||
compareResourceTranslations(req, *de.FilterKey("res_tr_3")[0], systemTypes.ResourceTranslation{
|
||||
Resource: fmt.Sprintf("corteza::compose:module/%d/%d", ns1.ID, mod1.ID),
|
||||
K: "res_tr_3",
|
||||
Message: "res_tr_3_text",
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func compareResourceTranslations(req *require.Assertions, a, b systemTypes.ResourceTranslation) {
|
||||
if a.Resource != b.Resource {
|
||||
req.FailNow("Resource missmatch")
|
||||
}
|
||||
if a.K != b.K {
|
||||
req.FailNow("K missmatch")
|
||||
}
|
||||
if a.Message != b.Message {
|
||||
req.FailNow("Message missmatch")
|
||||
}
|
||||
}
|
||||
192
server/tests/envoy/settings_test.go
Normal file
192
server/tests/envoy/settings_test.go
Normal file
@@ -0,0 +1,192 @@
|
||||
package envoy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/pkg/envoyx"
|
||||
"github.com/cortezaproject/corteza/server/pkg/rbac"
|
||||
"github.com/cortezaproject/corteza/server/store"
|
||||
"github.com/cortezaproject/corteza/server/system/types"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestSettingImportExport(t *testing.T) {
|
||||
var (
|
||||
ctx = context.Background()
|
||||
req = require.New(t)
|
||||
nodes envoyx.NodeSet
|
||||
gg *envoyx.DepGraph
|
||||
err error
|
||||
)
|
||||
|
||||
cleanup(t)
|
||||
|
||||
// The test
|
||||
//
|
||||
// * imports some YAML files
|
||||
// * checks the DB state
|
||||
// * exports the DB into a YAML
|
||||
// * clears the DB
|
||||
// * imports the YAML
|
||||
// * checks the DB state the same way as before
|
||||
//
|
||||
// The above outlined flow allows us to trivially check if the data is both
|
||||
// imported and exported correctly.
|
||||
//
|
||||
// The initial step could also manually populate the DB but the YAML import
|
||||
// is more convenient.
|
||||
|
||||
t.Run("initial import", func(t *testing.T) {
|
||||
t.Run("parse configs", func(t *testing.T) {
|
||||
nodes, _, err = defaultEnvoy.Decode(ctx, envoyx.DecodeParams{
|
||||
Type: envoyx.DecodeTypeURI,
|
||||
Params: map[string]any{
|
||||
"uri": "file://testdata/settings",
|
||||
},
|
||||
})
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
t.Run("bake", func(t *testing.T) {
|
||||
gg, err = defaultEnvoy.Bake(ctx, envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": defaultStore,
|
||||
"dal": defaultDal,
|
||||
},
|
||||
}, nil, nodes...)
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
t.Run("import into DB", func(t *testing.T) {
|
||||
err = defaultEnvoy.Encode(ctx, envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": defaultStore,
|
||||
"dal": defaultDal,
|
||||
},
|
||||
}, gg)
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
assertSettingState(ctx, t, defaultStore, req)
|
||||
})
|
||||
|
||||
// Prepare a temp file where we'll dump the YAML into
|
||||
auxFile, err := os.CreateTemp(os.TempDir(), "*.yaml")
|
||||
req.NoError(err)
|
||||
spew.Dump(auxFile.Name())
|
||||
// defer os.Remove(auxFile.Name())
|
||||
defer auxFile.Close()
|
||||
|
||||
var rules envoyx.NodeSet
|
||||
t.Run("export", func(t *testing.T) {
|
||||
t.Run("export from DB", func(t *testing.T) {
|
||||
nodes, _, err = defaultEnvoy.Decode(ctx, envoyx.DecodeParams{
|
||||
Type: envoyx.DecodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": defaultStore,
|
||||
"dal": defaultDal,
|
||||
},
|
||||
Filter: map[string]envoyx.ResourceFilter{
|
||||
types.SettingValueResourceType: {},
|
||||
},
|
||||
})
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
var rr rbac.RuleSet
|
||||
t.Run("get all rules", func(t *testing.T) {
|
||||
rr, _, err = store.SearchRbacRules(ctx, defaultStore, rbac.RuleFilter{})
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
t.Run("connect rules to resources", func(t *testing.T) {
|
||||
rules, err = envoyx.RBACRulesForNodes(rr, nodes...)
|
||||
req.NoError(err)
|
||||
|
||||
nodes = append(nodes, rules...)
|
||||
})
|
||||
|
||||
t.Run("bake", func(t *testing.T) {
|
||||
gg, err = defaultEnvoy.Bake(ctx, envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": defaultStore,
|
||||
"dal": defaultDal,
|
||||
},
|
||||
}, nil, nodes...)
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
t.Run("write file", func(t *testing.T) {
|
||||
err = defaultEnvoy.Encode(ctx, envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeIo,
|
||||
Params: map[string]any{
|
||||
"writer": auxFile,
|
||||
},
|
||||
}, gg)
|
||||
req.NoError(err)
|
||||
})
|
||||
})
|
||||
|
||||
cleanup(t)
|
||||
|
||||
t.Run("second import", func(t *testing.T) {
|
||||
t.Run("yaml parse", func(t *testing.T) {
|
||||
nodes, _, err = defaultEnvoy.Decode(ctx, envoyx.DecodeParams{
|
||||
Type: envoyx.DecodeTypeURI,
|
||||
Params: map[string]any{
|
||||
"uri": fmt.Sprintf("file://%s", auxFile.Name()),
|
||||
},
|
||||
})
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
t.Run("bake", func(t *testing.T) {
|
||||
gg, err = defaultEnvoy.Bake(ctx, envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": defaultStore,
|
||||
"dal": defaultDal,
|
||||
},
|
||||
}, nil, nodes...)
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
t.Run("run import", func(t *testing.T) {
|
||||
err = defaultEnvoy.Encode(ctx, envoyx.EncodeParams{
|
||||
Type: envoyx.EncodeTypeStore,
|
||||
Params: map[string]any{
|
||||
"storer": defaultStore,
|
||||
"dal": defaultDal,
|
||||
},
|
||||
}, gg)
|
||||
req.NoError(err)
|
||||
})
|
||||
|
||||
assertSettingState(ctx, t, defaultStore, req)
|
||||
})
|
||||
}
|
||||
|
||||
func assertSettingState(ctx context.Context, t *testing.T, s store.Storer, req *require.Assertions) {
|
||||
t.Run("check state", func(t *testing.T) {
|
||||
ss, _, err := store.SearchSettingValues(ctx, s, types.SettingsFilter{})
|
||||
req.NoError(err)
|
||||
|
||||
var st *types.SettingValue
|
||||
st = ss.FindByName("auth.external.enabled")
|
||||
req.NotNil(st)
|
||||
|
||||
st = ss.FindByName("auth.mail.from-address")
|
||||
req.NotNil(st)
|
||||
|
||||
st = ss.FindByName("auth.internal.enabled")
|
||||
req.NotNil(st)
|
||||
|
||||
})
|
||||
}
|
||||
22
server/tests/envoy/testdata/datasource_records/def.yaml
vendored
Normal file
22
server/tests/envoy/testdata/datasource_records/def.yaml
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
namespace:
|
||||
test_ns_1:
|
||||
name: Test Namespace 1
|
||||
modules:
|
||||
test_ns_1_mod_1:
|
||||
name: Test Namespace 1 Module 1
|
||||
fields:
|
||||
test_ns_1_mod_1_f1:
|
||||
title: Test Namespace 1 Module 1 Field 1
|
||||
test_ns_1_mod_1_f2:
|
||||
title: Test Namespace 1 Module 1 Field 2
|
||||
kind: String
|
||||
source:
|
||||
- from: records.csv
|
||||
key: ID
|
||||
map:
|
||||
- column: ID
|
||||
skip: true
|
||||
- column: test_ns_1_mod_1_f1
|
||||
field: test_ns_1_mod_1_f1
|
||||
- column: test_ns_1_mod_1_f2
|
||||
field: test_ns_1_mod_1_f2
|
||||
9
server/tests/envoy/testdata/datasource_records/records.csv
vendored
Normal file
9
server/tests/envoy/testdata/datasource_records/records.csv
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
ID,test_ns_1_mod_1_f1,test_ns_1_mod_1_f2
|
||||
row_1,row_1_src_c1,row_1_src_c2
|
||||
row_2,row_2_src_c1,row_2_src_c2
|
||||
row_3,row_3_src_c1,row_3_src_c2
|
||||
row_4,row_4_src_c1,row_4_src_c2
|
||||
row_5,row_5_src_c1,row_5_src_c2
|
||||
row_6,row_6_src_c1,row_6_src_c2
|
||||
row_7,row_7_src_c1,row_7_src_c2
|
||||
row_8,row_8_src_c1,row_8_src_c2
|
||||
|
197
server/tests/envoy/testdata/full/full.yaml
vendored
Normal file
197
server/tests/envoy/testdata/full/full.yaml
vendored
Normal file
@@ -0,0 +1,197 @@
|
||||
namespace:
|
||||
test_ns_1:
|
||||
name: Test Namespace 1
|
||||
enabled: true
|
||||
|
||||
modules:
|
||||
test_ns_1_mod_1:
|
||||
name: Test Namespace 1 Module 1
|
||||
fields:
|
||||
test_ns_1_mod_1_f1:
|
||||
title: Test Namespace 1 Module 1 Field 1
|
||||
test_ns_1_mod_1_f2:
|
||||
title: Test Namespace 1 Module 1 Field 2
|
||||
kind: Number
|
||||
|
||||
test_ns_1_mod_2:
|
||||
name: Test Namespace 1 Module 2
|
||||
fields:
|
||||
test_ns_1_mod_2_f1:
|
||||
title: Test Namespace 1 Module 2 Field 1
|
||||
kind: Record
|
||||
options:
|
||||
module: test_ns_1_mod_1
|
||||
test_ns_1_mod_2_f2:
|
||||
title: Test Namespace 1 Module 2 Field 2
|
||||
kind: Record
|
||||
options:
|
||||
module: test_ns_1_mod_2
|
||||
|
||||
charts:
|
||||
test_ns_1_chart_1:
|
||||
name: Test Namespace 1 Chart 1
|
||||
config:
|
||||
reports:
|
||||
- filter: true
|
||||
module: test_ns_1_mod_1
|
||||
- filter: true
|
||||
module: test_ns_1_mod_2
|
||||
|
||||
pages:
|
||||
test_ns_1_page_1:
|
||||
title: Test Namespace 1 Page 1
|
||||
visible: true
|
||||
page_layouts:
|
||||
test_ns_1_page_1_layout_1:
|
||||
meta:
|
||||
title: Test Namespace 1 Page 1 Layout 1
|
||||
test_ns_1_page_1_layout_2:
|
||||
meta:
|
||||
title: Test Namespace 1 Page 1 Layout 2
|
||||
blocks:
|
||||
- title: Test Namespace 1 Page 1 Block 1
|
||||
kind: RecordList
|
||||
options:
|
||||
module: test_ns_1_mod_1
|
||||
- title: Test Namespace 1 Page 1 Block 2
|
||||
kind: Automation
|
||||
# @todo
|
||||
# options:
|
||||
|
||||
- title: Test Namespace 1 Page 1 Block 3
|
||||
kind: RecordOrganizer
|
||||
options:
|
||||
module: test_ns_1_mod_1
|
||||
|
||||
- title: Test Namespace 1 Page 1 Block 4
|
||||
kind: Chart
|
||||
options:
|
||||
chart: test_ns_1_chart_1
|
||||
|
||||
- title: Test Namespace 1 Page 1 Block 5
|
||||
kind: Calendar
|
||||
options:
|
||||
feeds:
|
||||
- options:
|
||||
module: test_ns_1_mod_1
|
||||
|
||||
- title: Test Namespace 1 Page 1 Block 6
|
||||
kind: Metric
|
||||
options:
|
||||
metrics:
|
||||
- module: test_ns_1_mod_1
|
||||
|
||||
- title: Test Namespace 1 Page 1 Block 7
|
||||
kind: Comment
|
||||
options:
|
||||
module: test_ns_1_mod_1
|
||||
|
||||
- title: Test Namespace 1 Page 1 Block 8
|
||||
kind: Progress
|
||||
options:
|
||||
module: test_ns_1_mod_1
|
||||
pages:
|
||||
test_ns_1_record_page_1:
|
||||
title: Test Namespace 1 Record Page 1
|
||||
module: test_ns_1_mod_1
|
||||
page_layouts:
|
||||
test_ns_1_record_page_1_layout_1:
|
||||
meta:
|
||||
title: Test Namespace 1 Record Page 1 Layout 1
|
||||
test_ns_1_record_page_1_layout_2:
|
||||
meta:
|
||||
title: Test Namespace 1 Record Page 1 Layout 2
|
||||
|
||||
application:
|
||||
test_app_1:
|
||||
enabled: true
|
||||
owner: test_user_1
|
||||
|
||||
endpoints:
|
||||
/test/endpoint/1:
|
||||
method: GET
|
||||
enabled: true
|
||||
createdBy: test_user_1
|
||||
updatedBy: test_user_1
|
||||
filters:
|
||||
- ref: r1
|
||||
kind: prefilter
|
||||
enabled: true
|
||||
createdBy: test_user_1
|
||||
updatedBy: test_user_1
|
||||
|
||||
authclient:
|
||||
test_authclient_1:
|
||||
secret: 123123
|
||||
security:
|
||||
impersonateUser: test_user_1
|
||||
permittedRoles:
|
||||
- test_role_1
|
||||
prohibitedRoles:
|
||||
- test_role_2
|
||||
forcedRoles:
|
||||
- test_role_3
|
||||
ownedBy: test_user_1
|
||||
createdBy: test_user_1
|
||||
updatedBy: test_user_1
|
||||
|
||||
queue:
|
||||
test_queue_1:
|
||||
consumer: workflow
|
||||
createdBy: test_user_1
|
||||
updatedBy: test_user_1
|
||||
|
||||
report:
|
||||
test_report_1:
|
||||
meta:
|
||||
name: Test Report 1
|
||||
Description: Test Report 1 Description
|
||||
ownedBy: test_user_1
|
||||
createdBy: test_user_1
|
||||
updatedBy: test_user_1
|
||||
|
||||
role:
|
||||
test_role_1:
|
||||
name: Test Role 1
|
||||
test_role_2:
|
||||
name: Test Role 2
|
||||
test_role_3:
|
||||
name: Test Role 3
|
||||
|
||||
template:
|
||||
test_template_1:
|
||||
meta:
|
||||
short: Test Template 1
|
||||
description: Test Template 1 Description
|
||||
ownerID: test_user_1
|
||||
|
||||
user:
|
||||
test_user_1:
|
||||
name: Test User 1
|
||||
email: test_user_1@example.com
|
||||
emailConfirmed: true
|
||||
|
||||
connection:
|
||||
test_connection_1:
|
||||
meta:
|
||||
name: Test Connection 1
|
||||
createdBy: test_user_1
|
||||
updatedBy: test_user_1
|
||||
|
||||
sensitivity_level:
|
||||
test_sensitivity_level_1:
|
||||
meta:
|
||||
name: Test Sensitivity Level 1
|
||||
description: Test sensitivity Level 1 Description
|
||||
createdBy: test_user_1
|
||||
updatedBy: test_user_1
|
||||
|
||||
workflow:
|
||||
test_workflow_1:
|
||||
enabled: true
|
||||
meta:
|
||||
name: Test Workflow 1
|
||||
triggers:
|
||||
- enabled: true
|
||||
stepID: 12
|
||||
resourceType: corteza::compose:namespace
|
||||
20
server/tests/envoy/testdata/locale/locale.yaml
vendored
Normal file
20
server/tests/envoy/testdata/locale/locale.yaml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
namespace:
|
||||
test_ns_1:
|
||||
name: Test Namespace 1
|
||||
modules:
|
||||
test_mod_1:
|
||||
name: Test Module 1
|
||||
|
||||
locale:
|
||||
en:
|
||||
corteza::compose:namespace/test_ns_1:
|
||||
res_tr_1: res_tr_1_text
|
||||
res_tr_2: res_tr_2_text
|
||||
corteza::compose:module/test_ns_1/test_mod_1:
|
||||
res_tr_3: res_tr_3_text
|
||||
de:
|
||||
corteza::compose:namespace/test_ns_1:
|
||||
res_tr_1: res_tr_1_text
|
||||
res_tr_2: res_tr_2_text
|
||||
corteza::compose:module/test_ns_1/test_mod_1:
|
||||
res_tr_3: res_tr_3_text
|
||||
14
server/tests/envoy/testdata/locale_dup/locale.yaml
vendored
Normal file
14
server/tests/envoy/testdata/locale_dup/locale.yaml
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
namespace:
|
||||
test_ns_1:
|
||||
name: Test Namespace 1
|
||||
modules:
|
||||
test_mod_1:
|
||||
name: Test Module 1
|
||||
|
||||
locale:
|
||||
en:
|
||||
corteza::compose:namespace/test_ns_1:
|
||||
res_tr_1: res_tr_1_text
|
||||
res_tr_2: res_tr_2_text
|
||||
corteza::compose:module/test_ns_1/test_mod_1:
|
||||
res_tr_3: res_tr_3_text
|
||||
5
server/tests/envoy/testdata/locale_dup/locale_extra.yaml
vendored
Normal file
5
server/tests/envoy/testdata/locale_dup/locale_extra.yaml
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
locale:
|
||||
en:
|
||||
corteza::compose:namespace/test_ns_1:
|
||||
res_tr_1: res_tr_1_text_duplicate
|
||||
res_tr_2: res_tr_2_text
|
||||
29
server/tests/envoy/testdata/rbac/rbac.yaml
vendored
Normal file
29
server/tests/envoy/testdata/rbac/rbac.yaml
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
namespace:
|
||||
test_ns_1:
|
||||
name: Test Namespace 1
|
||||
modules:
|
||||
test_mod_1:
|
||||
name: Test Module 1
|
||||
roles:
|
||||
test_role_1:
|
||||
name: Test Role 1
|
||||
test_role_2:
|
||||
name: Test Role 2
|
||||
|
||||
allow:
|
||||
test_role_1:
|
||||
corteza::compose:namespace/test_ns_1:
|
||||
- op2
|
||||
corteza::compose:module/test_ns_1/*:
|
||||
- op3
|
||||
corteza::compose:module/test_ns_1/test_mod_1:
|
||||
- op4
|
||||
|
||||
deny:
|
||||
test_role_2:
|
||||
corteza::compose:namespace/test_ns_1:
|
||||
- op2
|
||||
corteza::compose:module/test_ns_1/*:
|
||||
- op3
|
||||
corteza::compose:module/test_ns_1/test_mod_1:
|
||||
- op4
|
||||
4
server/tests/envoy/testdata/records/cross_ref/child_records.csv
vendored
Normal file
4
server/tests/envoy/testdata/records/cross_ref/child_records.csv
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
ID,user_name,parent,alt
|
||||
c11,Daniel Adams,p1,c13
|
||||
c12,Jane Alex,p2,c11
|
||||
c13,Fish,p3,c12
|
||||
|
49
server/tests/envoy/testdata/records/cross_ref/def.yaml
vendored
Normal file
49
server/tests/envoy/testdata/records/cross_ref/def.yaml
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
namespace:
|
||||
test_ns:
|
||||
name: Test Namespace
|
||||
modules:
|
||||
mod_parent:
|
||||
name: Test Namespace Module Parent
|
||||
fields:
|
||||
name:
|
||||
title: Name
|
||||
code:
|
||||
title: Code
|
||||
kind: Number
|
||||
source:
|
||||
- from: parent_records.csv
|
||||
key: ID
|
||||
map:
|
||||
- column: ID
|
||||
skip: true
|
||||
- column: name
|
||||
field: name
|
||||
- column: code
|
||||
field: code
|
||||
mod_child:
|
||||
name: Test Namespace Module Child
|
||||
fields:
|
||||
user_name:
|
||||
title: User Name
|
||||
parent:
|
||||
title: Parent
|
||||
kind: Record
|
||||
options:
|
||||
module: mod_parent
|
||||
alt:
|
||||
title: alt
|
||||
kind: Record
|
||||
options:
|
||||
module: mod_child
|
||||
source:
|
||||
- from: child_records.csv
|
||||
key: ID
|
||||
map:
|
||||
- column: ID
|
||||
skip: true
|
||||
- column: user_name
|
||||
field: user_name
|
||||
- column: parent
|
||||
field: parent
|
||||
- column: alt
|
||||
field: alt
|
||||
4
server/tests/envoy/testdata/records/cross_ref/parent_records.csv
vendored
Normal file
4
server/tests/envoy/testdata/records/cross_ref/parent_records.csv
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
ID,name,code
|
||||
p1,Jane Doe,3124
|
||||
p2,Ana Banana,4153
|
||||
p3,Qwerty,83172
|
||||
|
39
server/tests/envoy/testdata/records/user_ref/def.yaml
vendored
Normal file
39
server/tests/envoy/testdata/records/user_ref/def.yaml
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
namespace:
|
||||
test_ns:
|
||||
name: Test Namespace
|
||||
modules:
|
||||
test_mod:
|
||||
name: Test Namespace Module
|
||||
fields:
|
||||
name:
|
||||
title: Name
|
||||
code:
|
||||
title: Code
|
||||
kind: Number
|
||||
rel_user:
|
||||
title: Rel User
|
||||
kind: User
|
||||
source:
|
||||
- from: records.csv
|
||||
key: ID
|
||||
map:
|
||||
- column: ID
|
||||
skip: true
|
||||
- column: name
|
||||
field: name
|
||||
- column: code
|
||||
field: code
|
||||
- column: rel_user
|
||||
field: rel_user
|
||||
- column: created_by
|
||||
field: created_by
|
||||
|
||||
user:
|
||||
usr_0:
|
||||
email: usr_0@test.tld
|
||||
usr_1:
|
||||
email: usr_1@test.tld
|
||||
usr_2:
|
||||
email: usr_2@test.tld
|
||||
usr_x:
|
||||
email: usr_x@test.tld
|
||||
4
server/tests/envoy/testdata/records/user_ref/records.csv
vendored
Normal file
4
server/tests/envoy/testdata/records/user_ref/records.csv
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
ID,name,code,rel_user,created_by
|
||||
p1,Jane Doe,3124,usr_0,usr_x
|
||||
p2,Ana Banana,4153,usr_1,usr_x
|
||||
p3,Qwerty,83172,usr_2,usr_x
|
||||
|
4
server/tests/envoy/testdata/settings/setting.yaml
vendored
Normal file
4
server/tests/envoy/testdata/settings/setting.yaml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
settings:
|
||||
auth.external.enabled: true
|
||||
auth.mail.from-address: info@example.tld
|
||||
auth.internal.enabled: true
|
||||
Reference in New Issue
Block a user