Add a provision testcase

This commit is contained in:
Tomaž Jerman
2020-11-27 11:19:15 +01:00
parent 9aa968e36a
commit 72ac5fa2ac
8 changed files with 390 additions and 0 deletions
+8
View File
@@ -7,6 +7,7 @@ import (
"github.com/cortezaproject/corteza-server/compose/types"
"github.com/cortezaproject/corteza-server/pkg/envoy"
"github.com/cortezaproject/corteza-server/pkg/envoy/directory"
"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"
@@ -64,6 +65,13 @@ func yd(ctx context.Context, suite, fname string) ([]resource.Interface, error)
return d.Decode(ctx, f, info)
}
func dd(ctx context.Context, suite string) ([]resource.Interface, error) {
fp := path.Join("testdata", suite)
d := yaml.Decoder(nil)
return directory.Decode(ctx, fp, d)
}
func encode(ctx context.Context, s store.Storer, nn []resource.Interface) error {
se := es.NewStoreEncoder(s, nil)
bld := envoy.NewGraphBuilder(se)
+187
View File
@@ -0,0 +1,187 @@
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/pkg/rbac"
"github.com/cortezaproject/corteza-server/store"
"github.com/stretchr/testify/require"
)
func TestProvision(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)
return req, encode(ctx, s, nn)
}
fullModLoad := func(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
}
getOptSlice := func(req *require.Assertions, key string, f *types.ModuleField) []interface{} {
opt, _ := (f.Options[key]).([]interface{})
req.NotNil(opt)
return opt
}
cases := []*tc{
{
name: "simple provision set",
suite: "provision",
pre: func() (err error) {
s, err = initStore(ctx)
return ce(
err,
storeRole(ctx, s, 1, "everyone"),
storeRole(ctx, s, 2, "admins"),
)
},
post: func(req *require.Assertions, err error) {
req.NoError(err)
},
check: func(req *require.Assertions) {
// Checkup AC
rrls, _, err := store.SearchRbacRules(ctx, s, rbac.RuleFilter{})
req.NoError(err)
req.NotNil(rrls)
req.Len(rrls, 14)
// -----------
// Checkup namespaces
ns, err := store.LookupComposeNamespaceBySlug(ctx, s, "ns1")
req.NoError(err)
req.NotNil(ns)
// -----------
// Checkup modules
m1, err := fullModLoad(ctx, s, req, ns.ID, "mod1")
m2, err := fullModLoad(ctx, s, req, ns.ID, "mod2")
m3, err := fullModLoad(ctx, s, req, ns.ID, "mod3")
// mod1
req.Len(m1.Fields, 4)
req.Equal("String", m1.Fields[0].Kind)
req.Equal("Select", m1.Fields[1].Kind)
opt := getOptSlice(req, "options", m1.Fields[1])
req.Equal([]interface{}{"f2 opt 1", "f2 opt 2", "f2 opt 3"}, opt)
req.Equal("Select", m1.Fields[2].Kind)
opt = getOptSlice(req, "options", m1.Fields[2])
req.Equal([]interface{}{"☆☆☆☆☆", "★☆☆☆☆"}, opt)
req.Equal("Record", m1.Fields[3].Kind)
req.Equal(m2.ID, uint64(m1.Fields[3].Options.Int64("module")))
opt = getOptSlice(req, "queryFields", m1.Fields[3])
req.Equal([]interface{}{"f1"}, opt)
// mod2
req.Len(m1.Fields, 4)
req.Equal("Record", m2.Fields[1].Kind)
req.Equal(m2.ID, uint64(m2.Fields[1].Options.Int64("module")))
opt = getOptSlice(req, "queryFields", m2.Fields[1])
req.Equal([]interface{}{"f1"}, opt)
req.Equal("Record", m2.Fields[3].Kind)
req.Equal(m3.ID, uint64(m2.Fields[3].Options.Int64("module")))
opt = getOptSlice(req, "queryFields", m2.Fields[3])
req.Equal([]interface{}{"f1"}, opt)
// -----------
// Checkup charts
ch1, err := store.LookupComposeChartByNamespaceIDHandle(ctx, s, ns.ID, "chr1")
req.NoError(err)
req.NotNil(ch1)
req.Len(ch1.Config.Reports, 1)
r := ch1.Config.Reports[0]
req.Len(r.Dimensions, 1)
req.Len(r.Metrics, 1)
req.Equal(m1.ID, r.ModuleID)
// -----------
// Checkup pages
pg1, err := store.LookupComposePageByNamespaceIDHandle(ctx, s, ns.ID, "pg1")
req.NoError(err)
req.NotNil(pg1)
pg2, err := store.LookupComposePageByNamespaceIDHandle(ctx, s, ns.ID, "rpg2")
req.NoError(err)
req.NotNil(pg2)
// pg1
req.Len(pg1.Blocks, 3)
req.Equal("Content", pg1.Blocks[0].Kind)
req.Equal("pg1 b1 content body", pg1.Blocks[0].Options["body"])
req.Equal("RecordList", pg1.Blocks[1].Kind)
req.Equal(m1.ID, uint64((pg1.Blocks[1].Options["module"]).(float64)))
req.Equal("Chart", pg1.Blocks[2].Kind)
req.Equal(ch1.ID, uint64((pg1.Blocks[2].Options["chart"]).(float64)))
// pg2
req.Equal(m1.ID, pg2.ModuleID)
req.Equal(pg1.ID, pg2.SelfID)
req.Equal("Record", pg2.Blocks[0].Kind)
// -----------
// Checkup settings records
ms, err := fullModLoad(ctx, s, req, ns.ID, "settings")
rr, _, err := store.SearchComposeRecords(ctx, s, ms, types.RecordFilter{})
req.NoError(err)
req.Len(rr, 1)
sr := rr[0]
req.Equal("s1 value", sr.Values.Get("s1", 0).Value)
req.Equal("1", sr.Values.Get("s2", 0).Value)
// -----------
},
},
}
for _, c := range cases {
t.Run(fmt.Sprintf("%s; %s", c.name, c.suite), func(t *testing.T) {
err = c.pre()
if err != nil {
t.Fatal(err.Error())
}
req, err := prepare(ctx, s, t, c.suite)
c.post(req, err)
c.check(req)
})
ni = 0
}
}
@@ -0,0 +1,33 @@
allow:
everyone:
compose:
- op1
compose:namespace:
- op1
admins:
compose:
- op1
- op1.sub
compose:namespace:
- op1
- op1.sub
deny:
everyone:
compose:
- op2
compose:namespace:
- op2
admins:
compose:
- op2
- op2.sub
compose:namespace:
- op2
- op2.sub
+10
View File
@@ -0,0 +1,10 @@
namespaces:
ns1:
name: ns1 name
allow:
everyone:
- op1
deny:
everyone:
- op2
+80
View File
@@ -0,0 +1,80 @@
# Provides a complete set of things to cover regarding modules and module fields.
# mod1: defines more complicated fields, relates to mod2
# mod2: defines a self-ref, relates to mod3
# mod3: just a placeholder
namespace: ns1
modules:
mod1:
name: mod1 name
fields:
f1:
label: f1 label
kind: String
required: true
f2:
label: f2 label
kind: Select
options:
options:
- f2 opt 1
- f2 opt 2
- f2 opt 3
f3:
label: f3 label
kind: Select
options:
options:
- ☆☆☆☆☆
- ★☆☆☆☆
f4:
label: f4 label
kind: Record
options:
labelField: f_label
module: mod2
queryFields:
- f1
mod2:
name: mod2 name
fields:
f_label:
label: f_label record label
f_ref_self:
label: f_ref_self label
kind: Record
options:
labelField: f_label
module: mod2
queryFields:
- f1
f1:
label: f1 label
kind: String
required: true
f2:
label: f2 label
kind: Record
options:
labelField: f_label
module: mod3
queryFields:
- f1
mod3:
name: mod3 name
fields:
f_label:
label: f_label record label
settings:
name: settings
fields:
s1:
label: s1 label
kind: String
s2:
label: s2 label
kind: Bool
+48
View File
@@ -0,0 +1,48 @@
namespace: ns1
pages:
pg1:
title: pg1 title
blocks:
- title: pg1 b1
kind: Content
xywh: [0, 0, 1, 1]
options:
body: pg1 b1 content body
- title: pg1 b2
kind: RecordList
xywh: [0, 1, 1, 1]
options:
module: mod1
fields:
- name: f1
- name: f2
variants:
bodyBg: white
border: primary
headerBg: white
headerText: primary
- title: pg1 b3
kind: Chart
xywh: [0, 2, 1, 1]
options:
chart: chr1
variants:
bodyBg: white
border: primary
headerBg: white
headerText: primary
children:
rpg2:
handle: rpg2
module: mod1
title: Record page for module "mod1"
blocks:
- title: rpg2 b1 title
kind: Record
options:
fields:
- name: f1
- name: f2
+18
View File
@@ -0,0 +1,18 @@
namespace: ns1
charts:
chr1:
name: chr1 name
config:
reports:
- dimensions:
- field: Status
modifier: (no grouping / buckets)
filter: ""
metrics:
- backgroundColor: '#11ff57'
field: count
fixTooltips: true
type: pie
module: mod1
renderer: {}
colorScheme: tableau.Tableau10
@@ -0,0 +1,6 @@
namespace: ns1
records:
settings:
- values:
s1: s1 value
s2: true