From 09d679fba758f4ed88a8f87a09134f5a47b5e169 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toma=C5=BE=20Jerman?= Date: Thu, 19 Nov 2020 14:39:21 +0100 Subject: [PATCH] Add base tests & post test tweaks --- pkg/envoy/builder.go | 2 +- pkg/envoy/encoder.go | 41 +- pkg/envoy/resource/compose_page.go | 46 +- pkg/envoy/store/application.go | 2 +- pkg/envoy/store/compose_chart.go | 18 +- pkg/envoy/store/compose_module.go | 19 +- pkg/envoy/store/compose_namespace.go | 2 +- pkg/envoy/store/compose_page.go | 137 +++++- pkg/envoy/store/compose_record.go | 2 +- pkg/envoy/store/encoder.go | 8 +- pkg/envoy/store/rbac_rule.go | 31 +- pkg/envoy/store/role.go | 2 +- pkg/envoy/store/settings.go | 7 +- pkg/envoy/store/user.go | 2 +- pkg/envoy/store/util.go | 4 +- pkg/envoy/tests/main_test.go | 126 +++++ pkg/envoy/tests/mod_rel_test.go | 154 ++++++ pkg/envoy/tests/simple_test.go | 453 ++++++++++++++++++ .../testdata/mod_rel/modules_peer_ref.yaml | 13 + .../testdata/mod_rel/modules_self_ref.yaml | 11 + .../testdata/mod_rel/modules_store_ref.yaml | 11 + .../tests/testdata/simple/applications.yaml | 2 + pkg/envoy/tests/testdata/simple/charts.yaml | 26 + .../tests/testdata/simple/charts_no_mod.yaml | 26 + .../tests/testdata/simple/charts_no_ns.yaml | 26 + pkg/envoy/tests/testdata/simple/modules.yaml | 9 + .../tests/testdata/simple/modules_no_ns.yaml | 9 + .../tests/testdata/simple/namespaces.yaml | 3 + pkg/envoy/tests/testdata/simple/pages.yaml | 6 + .../tests/testdata/simple/pages_no_ns.yaml | 7 + pkg/envoy/tests/testdata/simple/pages_r.yaml | 7 + .../tests/testdata/simple/pages_r_no_mod.yaml | 8 + .../tests/testdata/simple/rbac_rules.yaml | 11 + .../testdata/simple/rbac_rules_no_role.yaml | 11 + pkg/envoy/tests/testdata/simple/roles.yaml | 3 + pkg/envoy/tests/testdata/simple/settings.yaml | 4 + pkg/envoy/tests/testdata/simple/users.yaml | 4 + pkg/envoy/yaml/compose_page.go | 30 +- pkg/envoy/yaml/document.go | 3 - 39 files changed, 1192 insertions(+), 94 deletions(-) create mode 100644 pkg/envoy/tests/main_test.go create mode 100644 pkg/envoy/tests/mod_rel_test.go create mode 100644 pkg/envoy/tests/simple_test.go create mode 100644 pkg/envoy/tests/testdata/mod_rel/modules_peer_ref.yaml create mode 100644 pkg/envoy/tests/testdata/mod_rel/modules_self_ref.yaml create mode 100644 pkg/envoy/tests/testdata/mod_rel/modules_store_ref.yaml create mode 100644 pkg/envoy/tests/testdata/simple/applications.yaml create mode 100644 pkg/envoy/tests/testdata/simple/charts.yaml create mode 100644 pkg/envoy/tests/testdata/simple/charts_no_mod.yaml create mode 100644 pkg/envoy/tests/testdata/simple/charts_no_ns.yaml create mode 100644 pkg/envoy/tests/testdata/simple/modules.yaml create mode 100644 pkg/envoy/tests/testdata/simple/modules_no_ns.yaml create mode 100644 pkg/envoy/tests/testdata/simple/namespaces.yaml create mode 100644 pkg/envoy/tests/testdata/simple/pages.yaml create mode 100644 pkg/envoy/tests/testdata/simple/pages_no_ns.yaml create mode 100644 pkg/envoy/tests/testdata/simple/pages_r.yaml create mode 100644 pkg/envoy/tests/testdata/simple/pages_r_no_mod.yaml create mode 100644 pkg/envoy/tests/testdata/simple/rbac_rules.yaml create mode 100644 pkg/envoy/tests/testdata/simple/rbac_rules_no_role.yaml create mode 100644 pkg/envoy/tests/testdata/simple/roles.yaml create mode 100644 pkg/envoy/tests/testdata/simple/settings.yaml create mode 100644 pkg/envoy/tests/testdata/simple/users.yaml diff --git a/pkg/envoy/builder.go b/pkg/envoy/builder.go index 4ae1bca91..e78c704bb 100644 --- a/pkg/envoy/builder.go +++ b/pkg/envoy/builder.go @@ -22,7 +22,7 @@ type ( // // Encoding errors are passed via Ec. Encoder interface { - Encode(ctx context.Context, c Rc) error + Encode(ctx context.Context, p Provider) error } PrepareEncoder interface { diff --git a/pkg/envoy/encoder.go b/pkg/envoy/encoder.go index 57c0d978f..c1ffdc364 100644 --- a/pkg/envoy/encoder.go +++ b/pkg/envoy/encoder.go @@ -2,7 +2,6 @@ package envoy import ( "context" - "sync" ) type ( @@ -12,40 +11,8 @@ type ( ) // @todo errors! -func Encode(ctx context.Context, p Provider, ee ...Encoder) error { - var err error - rcc := make([]Rc, len(ee)) - - var wg sync.WaitGroup - wg.Add(len(ee)) - - for i, e := range ee { - rcc[i] = make(Rc) - - go func() { - defer wg.Done() - - eErr := e.Encode(ctx, rcc[i]) - if err != nil { - err = eErr - } - }() - } - - for { - rs, err := p.Next(ctx) - if err != nil { - return err - } - - for _, rc := range rcc { - rc <- rs - } - if rs == nil { - break - } - } - - wg.Wait() - return nil +func Encode(ctx context.Context, p Provider, e Encoder) error { + // @todo add support for multiple encoders at the same time. + // The issue occurs with routines and error handling... + return e.Encode(ctx, p) } diff --git a/pkg/envoy/resource/compose_page.go b/pkg/envoy/resource/compose_page.go index 0cdfd9404..fba73c4d5 100644 --- a/pkg/envoy/resource/compose_page.go +++ b/pkg/envoy/resource/compose_page.go @@ -10,13 +10,21 @@ type ( *base Res *types.Page - NsRef *Ref - ModRef *Ref + NsRef *Ref + ModRef *Ref + ParentRef *Ref + + ModRefs RefSet + ChartRefs RefSet } ) -func NewComposePage(pg *types.Page, nsRef, modRef string) *ComposePage { - r := &ComposePage{base: &base{}} +func NewComposePage(pg *types.Page, nsRef, modRef, parentRef string) *ComposePage { + r := &ComposePage{ + base: &base{}, + ModRefs: make(RefSet, 0, 10), + ChartRefs: make(RefSet, 0, 10), + } r.SetResourceType(COMPOSE_PAGE_RESOURCE_TYPE) r.Res = pg @@ -27,6 +35,36 @@ func NewComposePage(pg *types.Page, nsRef, modRef string) *ComposePage { r.ModRef = r.AddRef(COMPOSE_MODULE_RESOURCE_TYPE, modRef) } + if parentRef != "" { + r.ParentRef = r.AddRef(COMPOSE_PAGE_RESOURCE_TYPE, parentRef) + } + + for _, b := range pg.Blocks { + switch b.Kind { + case "RecordList": + id, _ := b.Options["module"].(string) + if id != "" { + r.ModRefs = append(r.ModRefs, r.AddRef(COMPOSE_MODULE_RESOURCE_TYPE, id)) + } + + case "Chart": + id, _ := b.Options["chart"].(string) + if id != "" { + r.ChartRefs = append(r.ChartRefs, r.AddRef(COMPOSE_CHART_RESOURCE_TYPE, id)) + } + + case "Metric": + mm, _ := b.Options["metrics"].([]interface{}) + for _, m := range mm { + mops, _ := m.(map[string]interface{}) + id, _ := mops["module"].(string) + if id != "" { + r.ModRefs = append(r.ModRefs, r.AddRef(COMPOSE_MODULE_RESOURCE_TYPE, id)) + } + } + } + } + return r } diff --git a/pkg/envoy/store/application.go b/pkg/envoy/store/application.go index 94b052012..f5e61b8e5 100644 --- a/pkg/envoy/store/application.go +++ b/pkg/envoy/store/application.go @@ -57,7 +57,7 @@ func (n *applicationState) Encode(ctx context.Context, s store.Storer, state *en res.ID = n.app.ID } if res.ID <= 0 { - res.ID = nextID() + res.ID = NextID() } // This is not possible, but let's do it anyway diff --git a/pkg/envoy/store/compose_chart.go b/pkg/envoy/store/compose_chart.go index fa4a60b35..9ccbaab6d 100644 --- a/pkg/envoy/store/compose_chart.go +++ b/pkg/envoy/store/compose_chart.go @@ -2,6 +2,7 @@ package store import ( "context" + "fmt" "time" "github.com/cortezaproject/corteza-server/compose/types" @@ -45,11 +46,6 @@ func (n *composeChartState) Prepare(ctx context.Context, s store.Storer, state * return composeNamespaceErrUnresolved(n.res.NsRef.Identifiers) } - // Can't do anything else, since the NS doesn't yet exist - if n.relNS.ID <= 0 { - return nil - } - // Get related modules n.relMods = make(types.ModuleSet, len(n.res.ModRef)) for i, mRef := range n.res.ModRef { @@ -83,7 +79,7 @@ func (n *composeChartState) Encode(ctx context.Context, s store.Storer, state *e res.ID = n.chr.ID } if res.ID <= 0 { - res.ID = nextID() + res.ID = NextID() } // This is not possible, but let's do it anyway @@ -170,6 +166,10 @@ func findComposeChartRS(ctx context.Context, s store.Storer, nsID uint64, rr res return ch, nil } + if nsID <= 0 { + return nil, nil + } + // Go in the store return findComposeChartS(ctx, s, nsID, makeGenericFilter(ii)) } @@ -211,7 +211,7 @@ func findComposeChartR(rr resource.InterfaceSet, ii resource.Identifiers) (ch *t return nil } - if chRes.Identifiers().HasAny(ii) { + if cr.Identifiers().HasAny(ii) { chRes = cr } return nil @@ -224,3 +224,7 @@ func findComposeChartR(rr resource.InterfaceSet, ii resource.Identifiers) (ch *t return nil } + +func composeChartErrUnresolved(ii resource.Identifiers) error { + return fmt.Errorf("compose chart unresolved %v", ii.StringSlice()) +} diff --git a/pkg/envoy/store/compose_module.go b/pkg/envoy/store/compose_module.go index d90719636..b9cfe80d7 100644 --- a/pkg/envoy/store/compose_module.go +++ b/pkg/envoy/store/compose_module.go @@ -107,7 +107,7 @@ func (n *composeModuleState) Encode(ctx context.Context, s store.Storer, state * res.ID = n.mod.ID } if res.ID <= 0 { - res.ID = nextID() + res.ID = NextID() } if state.Conflicting { @@ -126,8 +126,17 @@ func (n *composeModuleState) Encode(ctx context.Context, s store.Storer, state * } // Fields + off := make(types.ModuleFieldSet, 0) + if n.mod != nil && n.mod.Fields != nil { + off = n.mod.Fields + } for i, f := range res.Fields { - f.ID = res.ID + of := off.FindByName(f.Name) + if of != nil { + f.ID = of.ID + } else { + f.ID = NextID() + } f.ModuleID = res.ID f.Place = i f.DeletedAt = nil @@ -262,6 +271,10 @@ func findComposeModuleRS(ctx context.Context, s store.Storer, nsID uint64, rr re return mod, nil } + if nsID <= 0 { + return nil, nil + } + // Go in the store return findComposeModuleS(ctx, s, nsID, makeGenericFilter(ii)) } @@ -303,7 +316,7 @@ func findComposeModuleR(rr resource.InterfaceSet, ii resource.Identifiers) (ns * return nil } - if modRes.Identifiers().HasAny(ii) { + if mr.Identifiers().HasAny(ii) { modRes = mr } return nil diff --git a/pkg/envoy/store/compose_namespace.go b/pkg/envoy/store/compose_namespace.go index ccf95b7cd..dca9cfce1 100644 --- a/pkg/envoy/store/compose_namespace.go +++ b/pkg/envoy/store/compose_namespace.go @@ -55,7 +55,7 @@ func (n *composeNamespaceState) Encode(ctx context.Context, s store.Storer, stat res.ID = n.ns.ID } if res.ID <= 0 { - res.ID = nextID() + res.ID = NextID() } // This is not possible, but let's do it anyway diff --git a/pkg/envoy/store/compose_page.go b/pkg/envoy/store/compose_page.go index fa05dd2cb..16caa145d 100644 --- a/pkg/envoy/store/compose_page.go +++ b/pkg/envoy/store/compose_page.go @@ -2,6 +2,7 @@ package store import ( "context" + "fmt" "time" "github.com/cortezaproject/corteza-server/compose/types" @@ -17,8 +18,12 @@ type ( res *resource.ComposePage pg *types.Page - relNS *types.Namespace - relMod *types.Module + relNS *types.Namespace + relMod *types.Module + relParent *types.Page + + relMods map[string]*types.Module + relCharts map[string]*types.Chart } ) @@ -27,6 +32,9 @@ func NewComposePageState(res *resource.ComposePage, cfg *EncoderConfig) resource cfg: cfg, res: res, + + relMods: make(map[string]*types.Module), + relCharts: make(map[string]*types.Chart), } } @@ -45,11 +53,6 @@ func (n *composePageState) Prepare(ctx context.Context, s store.Storer, state *e return composeNamespaceErrUnresolved(n.res.NsRef.Identifiers) } - // Can't do anything else, since the NS doesn't yet exist - if n.relNS.ID <= 0 { - return nil - } - // Get related module // If this isn't a record page, there is no related module if n.res.ModRef != nil { @@ -62,6 +65,45 @@ func (n *composePageState) Prepare(ctx context.Context, s store.Storer, state *e } } + // Get parent page + if n.res.ParentRef != nil { + n.relParent, err = findComposePageRS(ctx, s, n.relNS.ID, state.ParentResources, n.res.ParentRef.Identifiers) + if err != nil { + return err + } + if n.relParent == nil { + return composePageErrUnresolved(n.res.ParentRef.Identifiers) + } + } + + // Get other related modules + for _, mr := range n.res.ModRefs { + mod, err := findComposeModuleRS(ctx, s, n.relNS.ID, state.ParentResources, mr.Identifiers) + if err != nil { + return err + } + if mod == nil { + return composeModuleErrUnresolved(mr.Identifiers) + } + for id := range mr.Identifiers { + n.relMods[id] = mod + } + } + + // Get related charts + for _, cr := range n.res.ChartRefs { + chr, err := findComposeChartRS(ctx, s, n.relNS.ID, state.ParentResources, cr.Identifiers) + if err != nil { + return err + } + if chr == nil { + return composeChartErrUnresolved(cr.Identifiers) + } + for id := range cr.Identifiers { + n.relCharts[id] = chr + } + } + // Try to get the original page n.pg, err = findComposePageS(ctx, s, n.relNS.ID, makeGenericFilter(n.res.Identifiers())) if err != nil { @@ -83,7 +125,7 @@ func (n *composePageState) Encode(ctx context.Context, s store.Storer, state *en res.ID = n.pg.ID } if res.ID <= 0 { - res.ID = nextID() + res.ID = NextID() } // This is not possible, but let's do it anyway @@ -111,6 +153,73 @@ func (n *composePageState) Encode(ctx context.Context, s store.Storer, state *en } } + // Parent? + if n.res.ParentRef != nil { + res.SelfID = n.relParent.ID + if res.SelfID <= 0 { + mod := findComposePageR(state.ParentResources, n.res.ParentRef.Identifiers) + res.SelfID = mod.ID + } + } + + // Blocks + getModID := func(id string) uint64 { + mod := n.relMods[id] + if mod == nil || mod.ID <= 0 { + mod = findComposeModuleR(state.ParentResources, resource.MakeIdentifiers(id)) + if mod == nil || mod.ID <= 0 { + return 0 + } + } + return mod.ID + } + + for _, b := range res.Blocks { + switch b.Kind { + case "RecordList": + id, _ := b.Options["module"].(string) + if id == "" { + continue + } + mID := getModID(id) + if mID <= 0 { + return composeModuleErrUnresolved(resource.MakeIdentifiers(id)) + } + b.Options["module"] = mID + + case "Chart": + id, _ := b.Options["chart"].(string) + if id == "" { + continue + } + chr := n.relCharts[id] + if chr == nil || chr.ID <= 0 { + ii := resource.MakeIdentifiers(id) + chr = findComposeChartR(state.ParentResources, ii) + if chr == nil || chr.ID <= 0 { + return composeChartErrUnresolved(ii) + } + } + b.Options["chart"] = chr.ID + + case "Metric": + mm, _ := b.Options["metrics"].([]interface{}) + for _, m := range mm { + mops, _ := m.(map[string]interface{}) + id, _ := mops["module"].(string) + if id == "" { + continue + } + mID := getModID(id) + if mID <= 0 { + return composeModuleErrUnresolved(resource.MakeIdentifiers(id)) + } + mops["module"] = mID + + } + } + } + // Create a fresh page if !exists { return store.CreateComposePage(ctx, s, res) @@ -167,11 +276,15 @@ func mergeComposePage(a, b *types.Page) *types.Page { // // Provided resources are prioritized. func findComposePageRS(ctx context.Context, s store.Storer, nsID uint64, rr resource.InterfaceSet, ii resource.Identifiers) (pg *types.Page, err error) { - pg = findComposePageR(ctx, rr, ii) + pg = findComposePageR(rr, ii) if pg != nil { return pg, nil } + if nsID <= 0 { + return nil, nil + } + // Go in the store return findComposePageS(ctx, s, nsID, makeGenericFilter(ii)) } @@ -204,7 +317,7 @@ func findComposePageS(ctx context.Context, s store.Storer, nsID uint64, gf gener } // findComposePageR looks for the page in the resources -func findComposePageR(ctx context.Context, rr resource.InterfaceSet, ii resource.Identifiers) (pg *types.Page) { +func findComposePageR(rr resource.InterfaceSet, ii resource.Identifiers) (pg *types.Page) { var pgRes *resource.ComposePage rr.Walk(func(r resource.Interface) error { @@ -225,3 +338,7 @@ func findComposePageR(ctx context.Context, rr resource.InterfaceSet, ii resource } return nil } + +func composePageErrUnresolved(ii resource.Identifiers) error { + return fmt.Errorf("compose page unresolved %v", ii.StringSlice()) +} diff --git a/pkg/envoy/store/compose_record.go b/pkg/envoy/store/compose_record.go index bfa4049d5..90705adcb 100644 --- a/pkg/envoy/store/compose_record.go +++ b/pkg/envoy/store/compose_record.go @@ -138,7 +138,7 @@ func (n *composeRecordState) Encode(ctx context.Context, s store.Storer, state * if rec.ID <= 0 && exists { rec.ID = rm[r.ID].ID } else { - rec.ID = nextID() + rec.ID = NextID() } im[r.ID] = rec.ID diff --git a/pkg/envoy/store/encoder.go b/pkg/envoy/store/encoder.go index eccfaace6..3bcc8b3b7 100644 --- a/pkg/envoy/store/encoder.go +++ b/pkg/envoy/store/encoder.go @@ -124,11 +124,14 @@ func (se *storeEncoder) Prepare(ctx context.Context, ee ...*envoy.ResourceState) } // Encode encodes available resource states using the given store encoder -func (se *storeEncoder) Encode(ctx context.Context, rc envoy.Rc) error { +func (se *storeEncoder) Encode(ctx context.Context, p envoy.Provider) error { var e *envoy.ResourceState return store.Tx(ctx, se.s, func(ctx context.Context, s store.Storer) (err error) { for { - e = <-rc + e, err = p.Next(ctx) + if err != nil { + return err + } if e == nil { return nil } @@ -142,7 +145,6 @@ func (se *storeEncoder) Encode(ctx context.Context, rc envoy.Rc) error { if err != nil { return se.WrapError("encode", e.Res, err) - } } }) diff --git a/pkg/envoy/store/rbac_rule.go b/pkg/envoy/store/rbac_rule.go index 14d028854..9a4f1d8b9 100644 --- a/pkg/envoy/store/rbac_rule.go +++ b/pkg/envoy/store/rbac_rule.go @@ -87,19 +87,25 @@ func (n *rbacRuleState) Encode(ctx context.Context, s store.Storer, state *envoy rule.Resource = rule.Resource.AppendWildcard() } - // There isn't anything to merge really, so Skip & MergeLeft skip it; - // Replace & MergeRight replace it. - // - // Replacing is handled after - switch n.cfg.OnExisting { - case Skip, - MergeLeft: - return nil + ee, _ := rbacRules.Filter(func(r *rbac.Rule) (bool, error) { + return (r.RoleID == rule.RoleID && r.Resource == rule.Resource && r.Operation == rule.Operation), nil + }) + + if len(ee) <= 0 { + rbacRules = rbacRules.Merge(rule) + } else { + // There isn't anything to merge really, so Skip & MergeLeft skip it; + // Replace & MergeRight replace it. + switch n.cfg.OnExisting { + case Skip, + MergeLeft: + return nil + } + + rbacRules = rbacRules.Merge(rule) } - nrr := rbacRules.Merge(rule) - d, u := nrr.Dirty() - + d, u := rbacRules.Dirty() err = store.DeleteRbacRule(ctx, s, d...) if err != nil { return @@ -110,8 +116,7 @@ func (n *rbacRuleState) Encode(ctx context.Context, s store.Storer, state *envoy return } - nrr.Clear() - rbacRules = nrr + rbacRules.Clear() return nil } diff --git a/pkg/envoy/store/role.go b/pkg/envoy/store/role.go index f5e60cf02..4f529de84 100644 --- a/pkg/envoy/store/role.go +++ b/pkg/envoy/store/role.go @@ -54,7 +54,7 @@ func (n *roleState) Encode(ctx context.Context, s store.Storer, state *envoy.Res rl.ID = n.rl.ID } if rl.ID <= 0 { - rl.ID = nextID() + rl.ID = NextID() } // This is not possible, but let's do it anyway diff --git a/pkg/envoy/store/settings.go b/pkg/envoy/store/settings.go index 3b14e5f1e..2f13ff173 100644 --- a/pkg/envoy/store/settings.go +++ b/pkg/envoy/store/settings.go @@ -74,8 +74,11 @@ func (n *settingsState) Encode(ctx context.Context, s store.Storer, state *envoy ss = append(ss, ns) } } - - return store.UpsertSetting(ctx, s, ss...) + err = store.TruncateSettings(ctx, s) + if err != nil { + return err + } + return store.CreateSetting(ctx, s, ss...) } // mergeSettings merges b into a, prioritising a diff --git a/pkg/envoy/store/user.go b/pkg/envoy/store/user.go index 4960d3980..9cea10ee9 100644 --- a/pkg/envoy/store/user.go +++ b/pkg/envoy/store/user.go @@ -55,7 +55,7 @@ func (n *userState) Encode(ctx context.Context, s store.Storer, state *envoy.Res res.ID = n.u.ID } if res.ID <= 0 { - res.ID = nextID() + res.ID = NextID() } // This is not possible, but let's do it anyway diff --git a/pkg/envoy/store/util.go b/pkg/envoy/store/util.go index 051b7aff3..b4c935add 100644 --- a/pkg/envoy/store/util.go +++ b/pkg/envoy/store/util.go @@ -22,8 +22,8 @@ var ( // we'll use the pkg/handle to check for handles. refy = regexp.MustCompile(`^[1-9](\d*)$`) - // wrapper around nextID that will aid service testing - nextID = func() uint64 { + // wrapper around NextID that will aid service testing + NextID = func() uint64 { return id.Next() } ) diff --git a/pkg/envoy/tests/main_test.go b/pkg/envoy/tests/main_test.go new file mode 100644 index 000000000..0d01144ee --- /dev/null +++ b/pkg/envoy/tests/main_test.go @@ -0,0 +1,126 @@ +package tests + +import ( + "context" + "os" + "path" + + "github.com/cortezaproject/corteza-server/compose/types" + "github.com/cortezaproject/corteza-server/pkg/envoy" + "github.com/cortezaproject/corteza-server/pkg/envoy/resource" + es "github.com/cortezaproject/corteza-server/pkg/envoy/store" + "github.com/cortezaproject/corteza-server/pkg/envoy/yaml" + "github.com/cortezaproject/corteza-server/store" + "github.com/cortezaproject/corteza-server/store/sqlite3" + stypes "github.com/cortezaproject/corteza-server/system/types" + "github.com/stretchr/testify/require" + "go.uber.org/zap" +) + +type ( + tc struct { + name string + suite string + file string + + // Before the data gets processed + pre func() error + // After the data gets processed + post func(req *require.Assertions, err error) + // Data assertions + check func(req *require.Assertions) + } +) + +func initStore(ctx context.Context) (store.Storer, error) { + s, err := sqlite3.ConnectInMemoryWithDebug(ctx) + if err != nil { + return nil, err + } + + err = store.Upgrade(ctx, zap.NewNop(), s) + if err != nil { + return nil, err + } + + return s, nil +} + +func yd(ctx context.Context, suite, fname string) ([]resource.Interface, error) { + fp := path.Join("testdata", suite, fname) + + f, err := os.Open(fp) + if err != nil { + return nil, err + } + defer f.Close() + + info, err := os.Stat(fp) + if err != nil { + return nil, err + } + + d := yaml.Decoder(nil) + return d.Decode(ctx, f, info) +} + +func encode(ctx context.Context, s store.Storer, nn []resource.Interface) error { + se := es.NewStoreEncoder(s, nil) + bld := envoy.NewGraphBuilder(se) + g, err := bld.Build(ctx, nn...) + if err != nil { + return err + } + + return envoy.Encode(ctx, g, se) +} + +func storeNamespace(ctx context.Context, s store.Storer, nsID uint64, ss ...string) error { + ns := &types.Namespace{ + ID: nsID, + } + if len(ss) > 0 { + ns.Slug = ss[0] + } + if len(ss) > 1 { + ns.Name = ss[1] + } + return store.CreateComposeNamespace(ctx, s, ns) +} + +func storeModule(ctx context.Context, s store.Storer, nsID, modID uint64, ss ...string) error { + mod := &types.Module{ + ID: modID, + NamespaceID: nsID, + } + if len(ss) > 0 { + mod.Handle = ss[0] + } + if len(ss) > 1 { + mod.Name = ss[1] + } + return store.CreateComposeModule(ctx, s, mod) +} + +func storeRole(ctx context.Context, s store.Storer, rID uint64, ss ...string) error { + r := &stypes.Role{ + ID: rID, + } + if len(ss) > 0 { + r.Handle = ss[0] + } + if len(ss) > 1 { + r.Name = ss[1] + } + return store.CreateRole(ctx, s, r) +} + +// Helper to collect resulting errors, returning the first one +func ce(ee ...error) error { + for _, e := range ee { + if e != nil { + return e + } + } + return nil +} diff --git a/pkg/envoy/tests/mod_rel_test.go b/pkg/envoy/tests/mod_rel_test.go new file mode 100644 index 000000000..95971b8a6 --- /dev/null +++ b/pkg/envoy/tests/mod_rel_test.go @@ -0,0 +1,154 @@ +package tests + +import ( + "context" + "fmt" + "testing" + + "github.com/cortezaproject/corteza-server/compose/types" + su "github.com/cortezaproject/corteza-server/pkg/envoy/store" + "github.com/cortezaproject/corteza-server/store" + "github.com/stretchr/testify/require" +) + +func TestModuleRels(t *testing.T) { + var ( + ctx = context.Background() + s, err = initStore(ctx) + ) + if err != nil { + t.Fatalf("failed to init sqlite in-memory db: %v", err) + } + + ni := uint64(0) + su.NextID = func() uint64 { + ni++ + return ni + } + + prepare := func(ctx context.Context, s store.Storer, t *testing.T, suite, file string) (*require.Assertions, error) { + req := require.New(t) + + nn, err := yd(ctx, suite, file) + req.NoError(err) + + return req, encode(ctx, s, nn) + } + + cases := []*tc{ + { + name: "simple mods; self ref", + suite: "mod_rel", + file: "modules_self_ref", + pre: func() (err error) { + return ce( + s.TruncateComposeNamespaces(ctx), + s.TruncateComposeModules(ctx), + + storeNamespace(ctx, s, 10, "ns1"), + ) + }, + post: func(req *require.Assertions, err error) { + req.NoError(err) + }, + check: func(req *require.Assertions) { + mod, err := store.LookupComposeModuleByNamespaceIDHandle(ctx, s, 10, "mod1") + req.NoError(err) + req.NotNil(mod) + + mod.Fields, _, err = store.SearchComposeModuleFields(ctx, s, types.ModuleFieldFilter{ModuleID: []uint64{mod.ID}}) + req.NoError(err) + + ff := mod.Fields + req.Len(ff, 1) + req.Equal("Record", ff[0].Kind) + req.Equal(mod.ID, uint64(ff[0].Options.Int64("module"))) + }, + }, + + { + name: "simple mods; ref to peer", + suite: "mod_rel", + file: "modules_peer_ref", + pre: func() (err error) { + return ce( + s.TruncateComposeNamespaces(ctx), + s.TruncateComposeModules(ctx), + s.TruncateComposeModuleFields(ctx), + + storeNamespace(ctx, s, 100, "ns1"), + ) + }, + post: func(req *require.Assertions, err error) { + req.NoError(err) + }, + check: func(req *require.Assertions) { + pmod, err := store.LookupComposeModuleByNamespaceIDHandle(ctx, s, 100, "mod2") + req.NoError(err) + req.NotNil(pmod) + + mod, err := store.LookupComposeModuleByNamespaceIDHandle(ctx, s, 100, "mod1") + req.NoError(err) + req.NotNil(mod) + + mod.Fields, _, err = store.SearchComposeModuleFields(ctx, s, types.ModuleFieldFilter{ModuleID: []uint64{mod.ID}}) + req.NoError(err) + + ff := mod.Fields + req.Len(ff, 1) + req.Equal("Record", ff[0].Kind) + req.Equal(pmod.ID, uint64(ff[0].Options.Int64("module"))) + }, + }, + + { + name: "simple mods; ref to store", + suite: "mod_rel", + file: "modules_store_ref", + pre: func() (err error) { + return ce( + s.TruncateComposeNamespaces(ctx), + s.TruncateComposeModules(ctx), + s.TruncateComposeModuleFields(ctx), + + storeNamespace(ctx, s, 100, "ns1"), + storeModule(ctx, s, 100, 200, "mod2"), + ) + }, + post: func(req *require.Assertions, err error) { + req.NoError(err) + }, + check: func(req *require.Assertions) { + smod, err := store.LookupComposeModuleByNamespaceIDHandle(ctx, s, 100, "mod2") + req.NoError(err) + req.NotNil(smod) + + mod, err := store.LookupComposeModuleByNamespaceIDHandle(ctx, s, 100, "mod1") + req.NoError(err) + req.NotNil(mod) + + mod.Fields, _, err = store.SearchComposeModuleFields(ctx, s, types.ModuleFieldFilter{ModuleID: []uint64{mod.ID}}) + req.NoError(err) + + ff := mod.Fields + req.Len(ff, 1) + req.Equal("Record", ff[0].Kind) + req.Equal(smod.ID, uint64(ff[0].Options.Int64("module"))) + }, + }, + } + + for _, c := range cases { + t.Run(fmt.Sprintf("%s; %s/%s", c.name, c.suite, c.file), func(t *testing.T) { + err = c.pre() + if err != nil { + t.Fatal(err.Error()) + } + req, err := prepare(ctx, s, t, c.suite, c.file+".yaml") + c.post(req, err) + c.check(req) + }) + + ni = 0 + } +} diff --git a/pkg/envoy/tests/simple_test.go b/pkg/envoy/tests/simple_test.go new file mode 100644 index 000000000..8b84a0bac --- /dev/null +++ b/pkg/envoy/tests/simple_test.go @@ -0,0 +1,453 @@ +package tests + +import ( + "context" + "fmt" + "strings" + "testing" + + "github.com/cortezaproject/corteza-server/compose/types" + su "github.com/cortezaproject/corteza-server/pkg/envoy/store" + "github.com/cortezaproject/corteza-server/pkg/rbac" + "github.com/cortezaproject/corteza-server/store" + st "github.com/cortezaproject/corteza-server/system/types" + "github.com/stretchr/testify/require" +) + +func TestSimpleCases(t *testing.T) { + var ( + ctx = context.Background() + s, err = initStore(ctx) + ) + if err != nil { + t.Fatalf("failed to init sqlite in-memory db: %v", err) + } + + ni := uint64(0) + su.NextID = func() uint64 { + ni++ + return ni + } + + prepare := func(ctx context.Context, s store.Storer, t *testing.T, suite, file string) (*require.Assertions, error) { + req := require.New(t) + + nn, err := yd(ctx, suite, file) + req.NoError(err) + + return req, encode(ctx, s, nn) + } + + cases := []*tc{ + { + name: "simple namespaces", + suite: "simple", + file: "namespaces", + pre: func() (err error) { + return s.TruncateComposeNamespaces(ctx) + }, + post: func(req *require.Assertions, err error) { + req.NoError(err) + }, + check: func(req *require.Assertions) { + ns, err := store.LookupComposeNamespaceBySlug(ctx, s, "ns1") + req.NoError(err) + req.NotNil(ns) + req.Equal("ns1", ns.Slug) + req.Equal("ns1 name", ns.Name) + }, + }, + + { + name: "simple mods; no namespace", + suite: "simple", + file: "modules_no_ns", + pre: func() (err error) { + return ce( + s.TruncateComposeNamespaces(ctx), + s.TruncateComposeModules(ctx), + s.TruncateComposeModuleFields(ctx), + ) + }, + post: func(req *require.Assertions, err error) { + req.Error(err) + req.True(strings.Contains(err.Error(), "prepare compose module")) + req.True(strings.Contains(err.Error(), "compose namespace unresolved")) + }, + check: func(req *require.Assertions) {}, + }, + + { + name: "simple mods", + suite: "simple", + file: "modules", + pre: func() (err error) { + return ce( + s.TruncateComposeNamespaces(ctx), + s.TruncateComposeModules(ctx), + s.TruncateComposeModuleFields(ctx), + + storeNamespace(ctx, s, 100, "ns1"), + ) + }, + post: func(req *require.Assertions, err error) { + req.NoError(err) + }, + check: func(req *require.Assertions) { + mod, err := store.LookupComposeModuleByNamespaceIDHandle(ctx, s, 100, "mod1") + req.NoError(err) + req.NotNil(mod) + + mod.Fields, _, err = store.SearchComposeModuleFields(ctx, s, types.ModuleFieldFilter{ModuleID: []uint64{mod.ID}}) + req.NoError(err) + + req.Equal("mod1", mod.Handle) + req.Equal("mod1 name", mod.Name) + req.Equal(uint64(100), mod.NamespaceID) + + ff := mod.Fields + req.Len(ff, 1) + req.Equal("f1", ff[0].Name) + req.Equal("f1 label", ff[0].Label) + req.Equal("String", ff[0].Kind) + }, + }, + + { + name: "simple charts; no ns", + suite: "simple", + file: "charts_no_ns", + pre: func() (err error) { + return ce( + s.TruncateComposeNamespaces(ctx), + s.TruncateComposeModules(ctx), + s.TruncateComposeCharts(ctx), + ) + }, + post: func(req *require.Assertions, err error) { + req.Error(err) + + req.True(strings.Contains(err.Error(), "prepare compose chart")) + req.True(strings.Contains(err.Error(), "compose namespace unresolved")) + }, + check: func(req *require.Assertions) {}, + }, + + { + name: "simple charts; no mod", + suite: "simple", + file: "charts_no_mod", + pre: func() (err error) { + return ce( + s.TruncateComposeNamespaces(ctx), + s.TruncateComposeModules(ctx), + s.TruncateComposeCharts(ctx), + + storeNamespace(ctx, s, 100, "ns1"), + ) + }, + post: func(req *require.Assertions, err error) { + req.Error(err) + + req.True(strings.Contains(err.Error(), "prepare compose chart")) + req.True(strings.Contains(err.Error(), "compose module unresolved")) + }, + check: func(req *require.Assertions) {}, + }, + + { + name: "simple charts", + suite: "simple", + file: "charts", + pre: func() (err error) { + return ce( + s.TruncateComposeNamespaces(ctx), + s.TruncateComposeModules(ctx), + s.TruncateComposeCharts(ctx), + + storeNamespace(ctx, s, 100, "ns1"), + storeModule(ctx, s, 100, 200, "mod1"), + ) + }, + post: func(req *require.Assertions, err error) { + req.NoError(err) + }, + check: func(req *require.Assertions) { + chr, err := store.LookupComposeChartByNamespaceIDHandle(ctx, s, 100, "c1") + req.NoError(err) + req.NotNil(chr) + + req.Equal("c1", chr.Handle) + req.Equal("c1 name", chr.Name) + + req.Len(chr.Config.Reports, 1) + + req.Equal(uint64(200), chr.Config.Reports[0].ModuleID) + }, + }, + + { + name: "simple pages; no ns", + suite: "simple", + file: "pages_no_ns", + pre: func() (err error) { + return ce( + s.TruncateComposeNamespaces(ctx), + s.TruncateComposeModules(ctx), + s.TruncateComposeCharts(ctx), + s.TruncateComposePages(ctx), + ) + }, + + post: func(req *require.Assertions, err error) { + req.Error(err) + + req.True(strings.Contains(err.Error(), "prepare compose page")) + req.True(strings.Contains(err.Error(), "compose namespace unresolved")) + }, + check: func(req *require.Assertions) {}, + }, + + { + name: "record pages; no mod", + suite: "simple", + file: "pages_r_no_mod", + pre: func() (err error) { + return ce( + s.TruncateComposeNamespaces(ctx), + s.TruncateComposeModules(ctx), + s.TruncateComposeCharts(ctx), + s.TruncateComposePages(ctx), + + storeNamespace(ctx, s, 100, "ns1"), + ) + }, + + post: func(req *require.Assertions, err error) { + req.Error(err) + + req.True(strings.Contains(err.Error(), "prepare compose page")) + req.True(strings.Contains(err.Error(), "compose module unresolved")) + }, + check: func(req *require.Assertions) {}, + }, + + { + name: "simple pages", + suite: "simple", + file: "pages", + pre: func() (err error) { + return ce( + s.TruncateComposeNamespaces(ctx), + s.TruncateComposeModules(ctx), + s.TruncateComposeCharts(ctx), + + storeNamespace(ctx, s, 100, "ns1"), + ) + }, + post: func(req *require.Assertions, err error) { + req.NoError(err) + }, + + check: func(req *require.Assertions) { + pg, err := store.LookupComposePageByNamespaceIDHandle(ctx, s, 100, "pg1") + req.NoError(err) + req.NotNil(pg) + + req.Equal("pg1", pg.Handle) + req.Equal("pg1 name", pg.Title) + req.Equal(uint64(0), pg.ModuleID) + req.Equal(uint64(100), pg.NamespaceID) + + req.Len(pg.Blocks, 1) + req.Equal("block1", pg.Blocks[0].Title) + }, + }, + + { + name: "record page", + suite: "simple", + file: "pages_r", + pre: func() (err error) { + return ce( + s.TruncateComposeNamespaces(ctx), + s.TruncateComposeModules(ctx), + s.TruncateComposeCharts(ctx), + s.TruncateComposePages(ctx), + + storeNamespace(ctx, s, 100, "ns1"), + storeModule(ctx, s, 100, 200, "mod1"), + ) + }, + post: func(req *require.Assertions, err error) { + req.NoError(err) + }, + + check: func(req *require.Assertions) { + pg, err := store.LookupComposePageByNamespaceIDHandle(ctx, s, 100, "pg1") + req.NoError(err) + req.NotNil(pg) + + req.Equal("pg1", pg.Handle) + req.Equal("pg1 name", pg.Title) + req.Equal(uint64(100), pg.NamespaceID) + req.Equal(uint64(200), pg.ModuleID) + + req.Len(pg.Blocks, 1) + req.Equal("block1", pg.Blocks[0].Title) + }, + }, + + { + name: "applications", + suite: "simple", + file: "applications", + pre: func() (err error) { + return ce( + s.TruncateApplications(ctx), + ) + }, + post: func(req *require.Assertions, err error) { + req.NoError(err) + }, + + check: func(req *require.Assertions) { + apps, _, err := store.SearchApplications(ctx, s, st.ApplicationFilter{ + Name: "app1", + }) + req.NoError(err) + req.NotNil(apps) + req.Len(apps, 1) + app := apps[0] + + req.Equal("app1", app.Name) + }, + }, + + { + name: "users", + suite: "simple", + file: "users", + pre: func() (err error) { + return ce( + s.TruncateUsers(ctx), + ) + }, + post: func(req *require.Assertions, err error) { + req.NoError(err) + }, + check: func(req *require.Assertions) { + u, err := store.LookupUserByHandle(ctx, s, "u1") + req.NoError(err) + req.NotNil(u) + + req.Equal("u1", u.Handle) + req.Equal("u1 name", u.Name) + req.Equal("u1@example.tld", u.Email) + }, + }, + + { + name: "roles", + suite: "simple", + file: "roles", + pre: func() (err error) { + return ce( + s.TruncateRoles(ctx), + ) + }, + post: func(req *require.Assertions, err error) { + req.NoError(err) + }, + check: func(req *require.Assertions) { + r, err := store.LookupRoleByHandle(ctx, s, "r1") + req.NoError(err) + req.NotNil(r) + + req.Equal("r1", r.Handle) + req.Equal("r1 name", r.Name) + }, + }, + + { + name: "settings", + suite: "simple", + file: "settings", + pre: func() (err error) { + return ce( + s.TruncateSettings(ctx), + ) + }, + post: func(req *require.Assertions, err error) { + req.NoError(err) + }, + check: func(req *require.Assertions) { + ss, _, err := store.SearchSettings(ctx, s, st.SettingsFilter{}) + req.NoError(err) + req.NotNil(ss) + req.Len(ss, 3) + }, + }, + + { + name: "rbac rules; no role", + suite: "simple", + file: "rbac_rules_no_role", + pre: func() (err error) { + return ce( + s.TruncateRoles(ctx), + s.TruncateRbacRules(ctx), + s.TruncateComposeNamespaces(ctx), + s.TruncateComposeModules(ctx), + s.TruncateComposeModuleFields(ctx), + ) + }, + post: func(req *require.Assertions, err error) { + req.Error(err) + req.True(strings.Contains(err.Error(), "prepare rbac rule")) + req.True(strings.Contains(err.Error(), "role unresolved")) + }, + check: func(req *require.Assertions) { + }, + }, + + { + name: "rbac rules", + suite: "simple", + file: "rbac_rules", + pre: func() (err error) { + return ce( + s.TruncateRoles(ctx), + s.TruncateRbacRules(ctx), + s.TruncateComposeNamespaces(ctx), + s.TruncateComposeModules(ctx), + s.TruncateComposeModuleFields(ctx), + + storeRole(ctx, s, 100, "r1"), + ) + }, + post: func(req *require.Assertions, err error) { + req.NoError(err) + }, + check: func(req *require.Assertions) { + rr, _, err := store.SearchRbacRules(ctx, s, rbac.RuleFilter{}) + req.NoError(err) + req.NotNil(rr) + req.Len(rr, 3) + }, + }, + } + + for _, c := range cases { + t.Run(fmt.Sprintf("%s; %s/%s", c.name, c.suite, c.file), func(t *testing.T) { + err = c.pre() + if err != nil { + t.Fatal(err.Error()) + } + req, err := prepare(ctx, s, t, c.suite, c.file+".yaml") + c.post(req, err) + c.check(req) + }) + ni = 0 + } +} diff --git a/pkg/envoy/tests/testdata/mod_rel/modules_peer_ref.yaml b/pkg/envoy/tests/testdata/mod_rel/modules_peer_ref.yaml new file mode 100644 index 000000000..32c1cdc46 --- /dev/null +++ b/pkg/envoy/tests/testdata/mod_rel/modules_peer_ref.yaml @@ -0,0 +1,13 @@ +namespace: ns1 +modules: + mod1: + name: mod1 name + fields: + f1: + label: f1 label + kind: Record + required: true + options: + module: mod2 + mod2: + name: mod2 name diff --git a/pkg/envoy/tests/testdata/mod_rel/modules_self_ref.yaml b/pkg/envoy/tests/testdata/mod_rel/modules_self_ref.yaml new file mode 100644 index 000000000..3eedef9af --- /dev/null +++ b/pkg/envoy/tests/testdata/mod_rel/modules_self_ref.yaml @@ -0,0 +1,11 @@ +namespace: ns1 +modules: + mod1: + name: mod1 name + fields: + f1: + label: f1 label + kind: Record + required: true + options: + module: mod1 diff --git a/pkg/envoy/tests/testdata/mod_rel/modules_store_ref.yaml b/pkg/envoy/tests/testdata/mod_rel/modules_store_ref.yaml new file mode 100644 index 000000000..0feed7d23 --- /dev/null +++ b/pkg/envoy/tests/testdata/mod_rel/modules_store_ref.yaml @@ -0,0 +1,11 @@ +namespace: ns1 +modules: + mod1: + name: mod1 name + fields: + f1: + label: f1 label + kind: Record + required: true + options: + module: mod2 diff --git a/pkg/envoy/tests/testdata/simple/applications.yaml b/pkg/envoy/tests/testdata/simple/applications.yaml new file mode 100644 index 000000000..6b42b44c3 --- /dev/null +++ b/pkg/envoy/tests/testdata/simple/applications.yaml @@ -0,0 +1,2 @@ +applications: + - app1 diff --git a/pkg/envoy/tests/testdata/simple/charts.yaml b/pkg/envoy/tests/testdata/simple/charts.yaml new file mode 100644 index 000000000..af81745a6 --- /dev/null +++ b/pkg/envoy/tests/testdata/simple/charts.yaml @@ -0,0 +1,26 @@ +namespace: ns1 +charts: + c1: + name: c1 name + config: + reports: + - dimensions: + - conditions: {} + field: Rating + meta: {} + modifier: (no grouping / buckets) + skipMissing: true + filter: "" + metrics: + - aggregate: AVG + field: count + fill: true + fixTooltips: false + label: Number of Accounts + lineTension: 0.4 + type: line + module: mod1 + renderer: {} + yAxis: + label: Accounts + colorScheme: tableau.Tableau10 diff --git a/pkg/envoy/tests/testdata/simple/charts_no_mod.yaml b/pkg/envoy/tests/testdata/simple/charts_no_mod.yaml new file mode 100644 index 000000000..e8b2f0353 --- /dev/null +++ b/pkg/envoy/tests/testdata/simple/charts_no_mod.yaml @@ -0,0 +1,26 @@ +namespace: ns1 +charts: + c1: + name: c1 name + config: + reports: + - dimensions: + - conditions: {} + field: Rating + meta: {} + modifier: (no grouping / buckets) + skipMissing: true + filter: "" + metrics: + - aggregate: AVG + field: count + fill: true + fixTooltips: false + label: Number of Accounts + lineTension: 0.4 + type: line + module: notThere + renderer: {} + yAxis: + label: Accounts + colorScheme: tableau.Tableau10 diff --git a/pkg/envoy/tests/testdata/simple/charts_no_ns.yaml b/pkg/envoy/tests/testdata/simple/charts_no_ns.yaml new file mode 100644 index 000000000..1087bae58 --- /dev/null +++ b/pkg/envoy/tests/testdata/simple/charts_no_ns.yaml @@ -0,0 +1,26 @@ +namespace: notThere +charts: + c1: + name: c1 name + config: + reports: + - dimensions: + - conditions: {} + field: Rating + meta: {} + modifier: (no grouping / buckets) + skipMissing: true + filter: "" + metrics: + - aggregate: AVG + field: count + fill: true + fixTooltips: false + label: Number of Accounts + lineTension: 0.4 + type: line + module: mod1 + renderer: {} + yAxis: + label: Accounts + colorScheme: tableau.Tableau10 diff --git a/pkg/envoy/tests/testdata/simple/modules.yaml b/pkg/envoy/tests/testdata/simple/modules.yaml new file mode 100644 index 000000000..2054c7bfd --- /dev/null +++ b/pkg/envoy/tests/testdata/simple/modules.yaml @@ -0,0 +1,9 @@ +namespace: ns1 +modules: + mod1: + name: mod1 name + fields: + f1: + label: f1 label + kind: String + required: true diff --git a/pkg/envoy/tests/testdata/simple/modules_no_ns.yaml b/pkg/envoy/tests/testdata/simple/modules_no_ns.yaml new file mode 100644 index 000000000..1c0ed09e6 --- /dev/null +++ b/pkg/envoy/tests/testdata/simple/modules_no_ns.yaml @@ -0,0 +1,9 @@ +namespace: notThere +modules: + mod1: + name: mod1 name + fields: + AccountName: + label: REP + kind: String + required: true diff --git a/pkg/envoy/tests/testdata/simple/namespaces.yaml b/pkg/envoy/tests/testdata/simple/namespaces.yaml new file mode 100644 index 000000000..137005b54 --- /dev/null +++ b/pkg/envoy/tests/testdata/simple/namespaces.yaml @@ -0,0 +1,3 @@ +namespaces: + ns1: + name: ns1 name diff --git a/pkg/envoy/tests/testdata/simple/pages.yaml b/pkg/envoy/tests/testdata/simple/pages.yaml new file mode 100644 index 000000000..0c639e1f4 --- /dev/null +++ b/pkg/envoy/tests/testdata/simple/pages.yaml @@ -0,0 +1,6 @@ +namespace: ns1 +pages: + pg1: + title: pg1 name + blocks: + - title: block1 diff --git a/pkg/envoy/tests/testdata/simple/pages_no_ns.yaml b/pkg/envoy/tests/testdata/simple/pages_no_ns.yaml new file mode 100644 index 000000000..56fac7548 --- /dev/null +++ b/pkg/envoy/tests/testdata/simple/pages_no_ns.yaml @@ -0,0 +1,7 @@ +namespace: notThere + +pages: + pg1: + title: pg1 name + blocks: + - title: block1 diff --git a/pkg/envoy/tests/testdata/simple/pages_r.yaml b/pkg/envoy/tests/testdata/simple/pages_r.yaml new file mode 100644 index 000000000..b244a343f --- /dev/null +++ b/pkg/envoy/tests/testdata/simple/pages_r.yaml @@ -0,0 +1,7 @@ +namespace: ns1 +pages: + pg1: + title: pg1 name + module: mod1 + blocks: + - title: block1 diff --git a/pkg/envoy/tests/testdata/simple/pages_r_no_mod.yaml b/pkg/envoy/tests/testdata/simple/pages_r_no_mod.yaml new file mode 100644 index 000000000..127c441bb --- /dev/null +++ b/pkg/envoy/tests/testdata/simple/pages_r_no_mod.yaml @@ -0,0 +1,8 @@ +namespace: ns1 + +pages: + pg1: + title: pg1 name + module: notThere + blocks: + - title: block1 diff --git a/pkg/envoy/tests/testdata/simple/rbac_rules.yaml b/pkg/envoy/tests/testdata/simple/rbac_rules.yaml new file mode 100644 index 000000000..9c4fd4620 --- /dev/null +++ b/pkg/envoy/tests/testdata/simple/rbac_rules.yaml @@ -0,0 +1,11 @@ +allow: + r1: + compose: + - access + +deny: + r1: + compose:namespace: + - access + messaging: + - access diff --git a/pkg/envoy/tests/testdata/simple/rbac_rules_no_role.yaml b/pkg/envoy/tests/testdata/simple/rbac_rules_no_role.yaml new file mode 100644 index 000000000..9c4fd4620 --- /dev/null +++ b/pkg/envoy/tests/testdata/simple/rbac_rules_no_role.yaml @@ -0,0 +1,11 @@ +allow: + r1: + compose: + - access + +deny: + r1: + compose:namespace: + - access + messaging: + - access diff --git a/pkg/envoy/tests/testdata/simple/roles.yaml b/pkg/envoy/tests/testdata/simple/roles.yaml new file mode 100644 index 000000000..c0702bbc7 --- /dev/null +++ b/pkg/envoy/tests/testdata/simple/roles.yaml @@ -0,0 +1,3 @@ +roles: + r1: + name: r1 name diff --git a/pkg/envoy/tests/testdata/simple/settings.yaml b/pkg/envoy/tests/testdata/simple/settings.yaml new file mode 100644 index 000000000..d65a99221 --- /dev/null +++ b/pkg/envoy/tests/testdata/simple/settings.yaml @@ -0,0 +1,4 @@ +settings: + privacy.mask.email: true + privacy.mask.name: true + auth.mail.email-confirmation.subject.en: Test \ No newline at end of file diff --git a/pkg/envoy/tests/testdata/simple/users.yaml b/pkg/envoy/tests/testdata/simple/users.yaml new file mode 100644 index 000000000..f11ab9738 --- /dev/null +++ b/pkg/envoy/tests/testdata/simple/users.yaml @@ -0,0 +1,4 @@ +users: + u1: + name: u1 name + email: u1@example.tld diff --git a/pkg/envoy/yaml/compose_page.go b/pkg/envoy/yaml/compose_page.go index 59411919c..f21cda00e 100644 --- a/pkg/envoy/yaml/compose_page.go +++ b/pkg/envoy/yaml/compose_page.go @@ -11,11 +11,14 @@ import ( type ( composePage struct { - res *types.Page - children composePageSet + res *types.Page + children composePageSet + refNamespace string refModule string - rbac rbacRuleSet + refParent string + + rbac rbacRuleSet } composePageSet []*composePage @@ -59,6 +62,9 @@ func (wset composePageSet) setNamespaceRef(ref string) error { } res.refNamespace = ref + if res.children != nil { + res.children.setNamespaceRef(ref) + } } return nil @@ -131,11 +137,27 @@ func (wrap *composePage) UnmarshalYAML(n *yaml.Node) (err error) { } func (wrap composePage) MarshalEnvoy() ([]resource.Interface, error) { - rs := resource.NewComposePage(wrap.res, wrap.refNamespace, wrap.refModule) + rs := resource.NewComposePage(wrap.res, wrap.refNamespace, wrap.refModule, wrap.refParent) + return envoy.CollectNodes( rs, + wrap.children.bindParent(rs), wrap.rbac.bindResource(rs), + // @todo Not sure yet // wrap.children, ) } + +func (rr composePageSet) bindParent(res resource.Interface) composePageSet { + rtr := make(composePageSet, 0, len(rr)) + for _, r := range rr { + idd := res.Identifiers().StringSlice() + if len(idd) > 0 { + r.refParent = idd[0] + } + rtr = append(rtr, r) + } + + return rtr +} diff --git a/pkg/envoy/yaml/document.go b/pkg/envoy/yaml/document.go index 88b12a09d..a0213e232 100644 --- a/pkg/envoy/yaml/document.go +++ b/pkg/envoy/yaml/document.go @@ -72,9 +72,6 @@ func (doc *Document) Decode(ctx context.Context, l loader) ([]resource.Interface if doc.rbac != nil { mm = append(mm, doc.rbac) } - if doc.users != nil { - mm = append(mm, doc.users) - } for _, m := range mm { if tmp, err := m.MarshalEnvoy(); err != nil {