Fix compose module field unmarshling; fix directory decoding
This commit is contained in:
@@ -53,6 +53,11 @@ func Decode(ctx context.Context, p string, decoders ...decoder) ([]resource.Inte
|
||||
for _, d := range decoders {
|
||||
if !d.CanDecodeFile(f) {
|
||||
// decoder can not handle this file
|
||||
// Make sure to reset it, as the above check consumes the reader
|
||||
if _, err = f.Seek(0, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package yaml
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/compose/types"
|
||||
"github.com/cortezaproject/corteza-server/pkg/envoy"
|
||||
"github.com/cortezaproject/corteza-server/pkg/envoy/resource"
|
||||
@@ -32,18 +33,11 @@ type (
|
||||
composeModuleSet []*composeModule
|
||||
|
||||
composeModuleField struct {
|
||||
res *types.ModuleField `yaml:",inline"`
|
||||
res *types.ModuleField
|
||||
rbac rbacRuleSet
|
||||
}
|
||||
composeModuleFieldSet []*composeModuleField
|
||||
|
||||
// aux struct to help us with decoding of module field
|
||||
composeModuleFieldAux struct {
|
||||
*types.ModuleField
|
||||
|
||||
Expressions *composeModuleFieldExprAux
|
||||
}
|
||||
|
||||
// aux struct for decoding module field expressions
|
||||
composeModuleFieldExprAux types.ModuleFieldExpr
|
||||
)
|
||||
@@ -273,23 +267,10 @@ func (set composeModuleFieldSet) set() (out types.ModuleFieldSet) {
|
||||
|
||||
func (wrap *composeModuleField) UnmarshalYAML(n *yaml.Node) (err error) {
|
||||
if wrap.res == nil {
|
||||
wrap.rbac = make(rbacRuleSet, 0, 10)
|
||||
wrap.res = &types.ModuleField{}
|
||||
}
|
||||
|
||||
// cast existing field expressions struct to aux struct
|
||||
exprAux := composeModuleFieldExprAux(wrap.res.Expressions)
|
||||
|
||||
// construct field aux struct from resource and aux expr struct
|
||||
// this way yaml pkg can help us with field unmarshalling but
|
||||
// we catch expressions and do our own magic
|
||||
aux := &composeModuleFieldAux{ModuleField: wrap.res, Expressions: &exprAux}
|
||||
if err = n.Decode(aux); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// cast unmarshalled expressions back to original type
|
||||
wrap.res.Expressions = types.ModuleFieldExpr(exprAux)
|
||||
|
||||
if wrap.rbac, err = decodeRbac(n); err != nil {
|
||||
return
|
||||
}
|
||||
@@ -299,6 +280,39 @@ func (wrap *composeModuleField) UnmarshalYAML(n *yaml.Node) (err error) {
|
||||
case "name":
|
||||
return fmt.Errorf("name should be encoded as field definition key")
|
||||
|
||||
case "place":
|
||||
return decodeScalar(v, "module place", &wrap.res.Place)
|
||||
|
||||
case "kind":
|
||||
return decodeScalar(v, "module kind", &wrap.res.Kind)
|
||||
|
||||
case "label":
|
||||
return decodeScalar(v, "module label", &wrap.res.Label)
|
||||
|
||||
case "private":
|
||||
return decodeScalar(v, "module private", &wrap.res.Private)
|
||||
|
||||
case "required":
|
||||
return decodeScalar(v, "module required", &wrap.res.Required)
|
||||
|
||||
case "visible":
|
||||
return decodeScalar(v, "module visible", &wrap.res.Visible)
|
||||
|
||||
case "multi":
|
||||
return decodeScalar(v, "module multi", &wrap.res.Multi)
|
||||
|
||||
case "options":
|
||||
if err = v.Decode(&wrap.res.Options); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case "expressions":
|
||||
ea := composeModuleFieldExprAux{}
|
||||
if err = v.Decode(&ea); err != nil {
|
||||
return err
|
||||
}
|
||||
wrap.res.Expressions = types.ModuleFieldExpr(ea)
|
||||
|
||||
case "default":
|
||||
var rvs = types.RecordValueSet{}
|
||||
switch v.Kind {
|
||||
|
||||
@@ -149,3 +149,14 @@ func ce(ee ...error) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func fullModLoad(ctx context.Context, s store.Storer, req *require.Assertions, nsID uint64, handle string) (*types.Module, error) {
|
||||
mod, err := store.LookupComposeModuleByNamespaceIDHandle(ctx, s, nsID, handle)
|
||||
req.NoError(err)
|
||||
req.NotNil(mod)
|
||||
|
||||
mod.Fields, _, err = store.SearchComposeModuleFields(ctx, s, types.ModuleFieldFilter{ModuleID: []uint64{mod.ID}})
|
||||
req.NoError(err)
|
||||
req.NotNil(mod.Fields)
|
||||
return mod, err
|
||||
}
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
package envoy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/pkg/envoy/resource"
|
||||
su "github.com/cortezaproject/corteza-server/pkg/envoy/store"
|
||||
"github.com/cortezaproject/corteza-server/store"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestModuleExpr(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 string) (*require.Assertions, error) {
|
||||
req := require.New(t)
|
||||
|
||||
nn, err := dd(ctx, suite)
|
||||
req.NoError(err)
|
||||
|
||||
crs := resource.ComposeRecordShaper()
|
||||
nn, err = resource.Shape(nn, crs)
|
||||
req.NoError(err)
|
||||
|
||||
return req, encode(ctx, s, nn)
|
||||
}
|
||||
// Prepare
|
||||
s, err = initStore(ctx)
|
||||
err = ce(
|
||||
err,
|
||||
|
||||
s.TruncateRbacRules(ctx),
|
||||
s.TruncateRoles(ctx),
|
||||
s.TruncateActionlogs(ctx),
|
||||
s.TruncateApplications(ctx),
|
||||
s.TruncateAttachments(ctx),
|
||||
s.TruncateComposeAttachments(ctx),
|
||||
s.TruncateComposeCharts(ctx),
|
||||
s.TruncateComposeNamespaces(ctx),
|
||||
s.TruncateComposeModules(ctx),
|
||||
s.TruncateComposeModuleFields(ctx),
|
||||
s.TruncateComposePages(ctx),
|
||||
|
||||
storeRole(ctx, s, 1, "everyone"),
|
||||
storeRole(ctx, s, 2, "admins"),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
|
||||
req, err := prepare(ctx, s, t, "mod_expr")
|
||||
req.NoError(err)
|
||||
|
||||
t.Run("module field expressions", func(t *testing.T) {
|
||||
ns, err := store.LookupComposeNamespaceBySlug(ctx, s, "crm")
|
||||
req.NoError(err)
|
||||
req.NotNil(ns)
|
||||
|
||||
mod, err := fullModLoad(ctx, s, req, ns.ID, "Account")
|
||||
req.NotNil(mod)
|
||||
req.NoError(err)
|
||||
req.Len(mod.Fields, 2)
|
||||
|
||||
// Check the full thing
|
||||
mfF := mod.Fields[0]
|
||||
req.Equal("a > b", mfF.Expressions.ValueExpr)
|
||||
req.Subset(mfF.Expressions.Sanitizers, []string{"trim(value)"})
|
||||
v := mfF.Expressions.Validators[0]
|
||||
req.Equal("a == \"\"", v.Test)
|
||||
req.Equal("Value should not be empty", v.Error)
|
||||
|
||||
// Check the other validator form
|
||||
mfV := mod.Fields[1]
|
||||
v = mfV.Expressions.Validators[0]
|
||||
req.Equal("value == \"\"", v.Test)
|
||||
req.Equal("Value should be filled", v.Error)
|
||||
})
|
||||
}
|
||||
@@ -44,6 +44,8 @@ func TestProvision_batch(t *testing.T) {
|
||||
err = ce(
|
||||
err,
|
||||
|
||||
s.TruncateRoles(ctx),
|
||||
s.TruncateRbacRules(ctx),
|
||||
s.TruncateActionlogs(ctx),
|
||||
s.TruncateApplications(ctx),
|
||||
s.TruncateAttachments(ctx),
|
||||
@@ -188,14 +190,3 @@ func checkBatchProvision(ctx context.Context, t *testing.T, req *require.Asserti
|
||||
req.Equal(fmt.Sprintf("%s value", slug), v.Value)
|
||||
})
|
||||
}
|
||||
|
||||
func fullModLoad(ctx context.Context, s store.Storer, req *require.Assertions, nsID uint64, handle string) (*types.Module, error) {
|
||||
mod, err := store.LookupComposeModuleByNamespaceIDHandle(ctx, s, nsID, handle)
|
||||
req.NoError(err)
|
||||
req.NotNil(mod)
|
||||
|
||||
mod.Fields, _, err = store.SearchComposeModuleFields(ctx, s, types.ModuleFieldFilter{ModuleID: []uint64{mod.ID}})
|
||||
req.NoError(err)
|
||||
req.NotNil(mod.Fields)
|
||||
return mod, err
|
||||
}
|
||||
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
namespaces:
|
||||
crm:
|
||||
name: CRM
|
||||
|
||||
modules:
|
||||
Account:
|
||||
name: Expressions
|
||||
fields:
|
||||
full:
|
||||
expressions:
|
||||
valueExpr: "a > b"
|
||||
sanitizers: [ "trim(value)" ]
|
||||
validators:
|
||||
- test: 'a == ""'
|
||||
error: Value should not be empty
|
||||
disableDefaultValidators: true
|
||||
validatorKV:
|
||||
expressions:
|
||||
validators:
|
||||
'value == ""': Value should be filled
|
||||
Reference in New Issue
Block a user