Fix compose integration tests

This commit is contained in:
Denis Arh
2020-09-08 14:51:19 +02:00
parent 4e2f9fdfcd
commit be76207e50
33 changed files with 606 additions and 502 deletions
-2
View File
@@ -89,8 +89,6 @@ func (ctrl *Record) List(ctx context.Context, r *request.RecordList) (interface{
return nil, err
}
panic("refactor page filter")
if m, err = ctrl.module.With(ctx).FindByID(r.NamespaceID, r.ModuleID); err != nil {
return nil, err
}
+2 -2
View File
@@ -72,7 +72,7 @@ func (svc chart) Find(filter types.ChartFilter) (set types.ChartSet, f types.Cha
}
err = func() error {
if ns, err := loadNamespace(svc.ctx, svc.store, f.NamespaceID); err != nil {
if ns, err := loadNamespace(svc.ctx, svc.store, filter.NamespaceID); err != nil {
return err
} else {
aProps.setNamespace(ns)
@@ -256,7 +256,7 @@ func (svc chart) handleUpdate(upd *types.Chart) chartUpdateHandler {
func (svc chart) handleDelete(ctx context.Context, ns *types.Namespace, c *types.Chart) (bool, error) {
if !svc.ac.CanDeleteChart(ctx, c) {
return false, ChartErrNotAllowedToUndelete()
return false, ChartErrNotAllowedToDelete()
}
if c.DeletedAt != nil {
+1 -1
View File
@@ -16,7 +16,7 @@ import (
func TestCharts(t *testing.T) {
var (
ctx = context.Background()
s, err = sqlite.NewInMemory(ctx)
s, err = sqlite.ConnectInMemory(ctx)
namespaceID = id.Next()
ns *types.Namespace
+69 -45
View File
@@ -8,6 +8,7 @@ import (
"github.com/cortezaproject/corteza-server/compose/types"
"github.com/cortezaproject/corteza-server/pkg/actionlog"
"github.com/cortezaproject/corteza-server/pkg/eventbus"
"github.com/cortezaproject/corteza-server/pkg/filter"
"github.com/cortezaproject/corteza-server/pkg/handle"
"github.com/cortezaproject/corteza-server/pkg/id"
"github.com/cortezaproject/corteza-server/store"
@@ -82,7 +83,7 @@ func (svc module) Find(filter types.ModuleFilter) (set types.ModuleSet, f types.
}
err = func() error {
if ns, err := loadNamespace(svc.ctx, svc.store, f.NamespaceID); err != nil {
if ns, err := loadNamespace(svc.ctx, svc.store, filter.NamespaceID); err != nil {
return err
} else {
aProps.setNamespace(ns)
@@ -156,13 +157,13 @@ func (svc module) FindByAny(namespaceID uint64, identifier interface{}) (m *type
return m, nil
}
func (svc module) Create(new *types.Module) (m *types.Module, err error) {
func (svc module) Create(new *types.Module) (*types.Module, error) {
var (
ns *types.Namespace
aProps = &moduleActionProps{changed: new}
)
err = store.Tx(svc.ctx, svc.store, func(ctx context.Context, s store.Storable) error {
err := store.Tx(svc.ctx, svc.store, func(ctx context.Context, s store.Storable) (err error) {
if !handle.IsValid(new.Handle) {
return ModuleErrInvalidHandle()
}
@@ -191,25 +192,27 @@ func (svc module) Create(new *types.Module) (m *types.Module, err error) {
new.UpdatedAt = nil
new.DeletedAt = nil
m.Fields.Walk(func(f *types.ModuleField) error {
f.ModuleID = new.ID
f.CreatedAt = *nowPtr()
f.UpdatedAt = nil
f.DeletedAt = nil
return nil
})
if new.Fields != nil {
_ = new.Fields.Walk(func(f *types.ModuleField) error {
f.ModuleID = new.ID
f.CreatedAt = *nowPtr()
f.UpdatedAt = nil
f.DeletedAt = nil
return nil
})
}
aProps.setModule(m)
aProps.setModule(new)
if err = store.CreateComposeModule(ctx, s, new); err != nil {
return err
}
if err = store.CreateComposeModuleField(ctx, s, m.Fields...); err != nil {
if err = store.CreateComposeModuleField(ctx, s, new.Fields...); err != nil {
return err
}
_ = svc.eventbus.WaitFor(ctx, event.ModuleAfterCreate(m, nil, ns))
_ = svc.eventbus.WaitFor(ctx, event.ModuleAfterCreate(new, nil, ns))
return nil
})
@@ -272,10 +275,15 @@ func (svc module) updater(namespaceID, moduleID uint64, action func(...*moduleAc
if fieldsChanged {
var (
hasRecords bool
// @todo
//store.SearchComposeRecords()
set types.RecordSet
)
if set, _, err = store.SearchComposeRecords(ctx, s, m, types.RecordFilter{Paging: filter.Paging{Limit: 1}}); err != nil {
return err
}
hasRecords = len(set) > 0
if err = updateModuleFields(ctx, s, m, m.Fields, hasRecords); err != nil {
}
@@ -340,7 +348,7 @@ func (svc module) uniqueCheck(m *types.Module) (err error) {
}
func (svc module) handleUpdate(upd *types.Module) moduleUpdateHandler {
return func(ctx context.Context, ns *types.Namespace, m *types.Module) (bool, bool, error) {
return func(ctx context.Context, ns *types.Namespace, m *types.Module) (mch bool, fch bool, err error) {
if isStale(upd.UpdatedAt, m.UpdatedAt, m.CreatedAt) {
return false, false, ModuleErrStaleData()
}
@@ -349,7 +357,7 @@ func (svc module) handleUpdate(upd *types.Module) moduleUpdateHandler {
return false, false, ModuleErrInvalidHandle()
}
if err := svc.uniqueCheck(upd); err != nil {
if err = svc.uniqueCheck(upd); err != nil {
return false, false, err
}
@@ -357,31 +365,39 @@ func (svc module) handleUpdate(upd *types.Module) moduleUpdateHandler {
return false, false, ModuleErrNotAllowedToUpdate()
}
m.Name = upd.Name
m.Handle = upd.Handle
m.Meta = upd.Meta
m.Fields = upd.Fields
m.UpdatedAt = nowPtr()
if m.Name != upd.Name {
mch = true
m.Name = upd.Name
}
// @todo
// select 1 record to see how fields can be updated
//var rf = types.RecordFilter{}
//rf.Limit = 1
//if _, rf, err = svc.recordRepo.Find(m, rf); err != nil {
// return err
//}
//
//if err = svc.moduleRepo.UpdateFields(m.ID, m.Fields, rf.Count > 0); err != nil {
// return err
//}
if m.Handle != upd.Handle {
mch = true
m.Handle = upd.Handle
}
return true, false, nil
if m.Meta.String() != upd.Meta.String() {
mch = true
m.Meta = upd.Meta
}
// @todo make field-change detection more optimal
if len(upd.Fields) > 0 {
fch = true
m.Fields = upd.Fields
}
if mch {
m.UpdatedAt = nowPtr()
}
// for now, we assume that
return mch, fch, nil
}
}
func (svc module) handleDelete(ctx context.Context, ns *types.Namespace, m *types.Module) (bool, bool, error) {
if !svc.ac.CanDeleteModule(ctx, m) {
return false, false, ModuleErrNotAllowedToUndelete()
return false, false, ModuleErrNotAllowedToDelete()
}
if m.DeletedAt != nil {
@@ -410,8 +426,8 @@ func (svc module) handleUndelete(ctx context.Context, ns *types.Namespace, m *ty
// updates module fields
// expecting to receive all module fields, as it deletes the rest
// also, sort order of the fields is also important as this fn stores and updates field's place as send
func updateModuleFields(ctx context.Context, s store.Storable, m *types.Module, ff types.ModuleFieldSet, hasRecords bool) error {
for _, f := range ff {
func updateModuleFields(ctx context.Context, s store.Storable, m *types.Module, newFields types.ModuleFieldSet, hasRecords bool) (err error) {
for _, f := range newFields {
// Set module ID to all new fields
if f.ModuleID == 0 {
f.ModuleID = m.ID
@@ -423,29 +439,28 @@ func updateModuleFields(ctx context.Context, s store.Storable, m *types.Module,
}
}
eff, _, err := store.SearchComposeModuleFields(ctx, s, types.ModuleFieldFilter{ModuleID: []uint64{m.ID}})
if err != nil {
return err
if err = loadModuleFields(ctx, s, m); err != nil {
return
}
for _, ef := range eff {
f := ff.FindByID(ef.ID)
for _, ef := range m.Fields {
f := newFields.FindByID(ef.ID)
if f != nil || f.DeletedAt == nil {
continue
}
ef.DeletedAt = nowPtr()
err = store.PartialComposeModuleFieldUpdate(ctx, s, []string{"deleted_at"}, ef)
err = store.UpdateComposeModuleField(ctx, s, ef)
if err != nil {
return err
}
}
for idx, f := range ff {
for idx, f := range newFields {
f.Place = idx
f.DeletedAt = nil
if e := eff.FindByID(f.ID); e != nil {
if e := m.Fields.FindByID(f.ID); e != nil {
f.CreatedAt = e.CreatedAt
// We do not have any other code in place that would handle changes of field name and kind, so we need
@@ -474,6 +489,10 @@ func updateModuleFields(ctx context.Context, s store.Storable, m *types.Module,
}
func loadModuleFields(ctx context.Context, s store.Storable, mm ...*types.Module) (err error) {
if len(mm) == 0 {
return nil
}
var (
ff types.ModuleFieldSet
mff = types.ModuleFieldFilter{ModuleID: types.ModuleSet(mm).IDs()}
@@ -491,6 +510,7 @@ func loadModuleFields(ctx context.Context, s store.Storable, mm ...*types.Module
return
}
// loads record module with fields and namespace
func loadModuleWithNamespace(ctx context.Context, s store.Storable, namespaceID, moduleID uint64) (ns *types.Namespace, m *types.Module, err error) {
if moduleID == 0 {
return nil, nil, ModuleErrInvalidID()
@@ -521,6 +541,10 @@ func loadModule(ctx context.Context, s store.Storable, moduleID uint64) (m *type
err = ModuleErrNotFound()
}
if err == nil {
err = loadModuleFields(ctx, s, m)
}
if err != nil {
return nil, err
}
+1 -1
View File
@@ -301,7 +301,7 @@ func (svc namespace) handleUpdate(upd *types.Namespace) namespaceUpdateHandler {
func (svc namespace) handleDelete(ctx context.Context, ns *types.Namespace) (bool, error) {
if !svc.ac.CanDeleteNamespace(ctx, ns) {
return false, NamespaceErrNotAllowedToUndelete()
return false, NamespaceErrNotAllowedToDelete()
}
if ns.DeletedAt != nil {
+4 -3
View File
@@ -52,6 +52,7 @@ func Page() PageService {
return (&page{
ac: DefaultAccessControl,
eventbus: eventbus.Service(),
store: DefaultNgStore,
}).With(context.Background())
}
@@ -61,7 +62,7 @@ func (svc page) With(ctx context.Context) PageService {
actionlog: DefaultActionlog,
ac: svc.ac,
eventbus: svc.eventbus,
store: DefaultNgStore,
store: svc.store,
}
}
@@ -118,7 +119,7 @@ func (svc page) search(filter types.PageFilter) (set types.PageSet, f types.Page
filter.Check = checkPage(svc.ctx, svc.ac)
err = func() error {
if ns, err := loadNamespace(svc.ctx, svc.store, f.NamespaceID); err != nil {
if ns, err := loadNamespace(svc.ctx, svc.store, filter.NamespaceID); err != nil {
return err
} else {
aProps.setNamespace(ns)
@@ -416,7 +417,7 @@ func (svc page) handleUpdate(upd *types.Page) pageUpdateHandler {
func (svc page) handleDelete(ctx context.Context, ns *types.Namespace, m *types.Page) (bool, error) {
if !svc.ac.CanDeletePage(ctx, m) {
return false, PageErrNotAllowedToUndelete()
return false, PageErrNotAllowedToDelete()
}
if m.DeletedAt != nil {
+23 -101
View File
@@ -57,6 +57,11 @@ type (
UserRefChecker(fn values.ReferenceChecker)
}
recordValueAccessController interface {
CanReadRecordValue(context.Context, *types.ModuleField) bool
CanUpdateRecordValue(context.Context, *types.ModuleField) bool
}
recordAccessController interface {
CanCreateRecord(context.Context, *types.Module) bool
CanReadNamespace(context.Context, *types.Namespace) bool
@@ -64,8 +69,8 @@ type (
CanReadRecord(context.Context, *types.Module) bool
CanUpdateRecord(context.Context, *types.Module) bool
CanDeleteRecord(context.Context, *types.Module) bool
CanReadRecordValue(context.Context, *types.ModuleField) bool
CanUpdateRecordValue(context.Context, *types.ModuleField) bool
recordValueAccessController
}
RecordService interface {
@@ -131,6 +136,7 @@ func Record() RecordService {
ac: DefaultAccessControl,
eventbus: eventbus.Service(),
optEmitEvents: true,
store: DefaultNgStore,
}).With(context.Background())
}
@@ -219,9 +225,7 @@ func (svc record) lookup(namespaceID, moduleID uint64, lookup func(*types.Module
return RecordErrNotAllowedToRead()
}
if err = svc.preloadValues(m, r); err != nil {
return err
}
trimUnreadableRecordFields(svc.ctx, svc.ac, m, r)
return nil
}()
@@ -236,58 +240,6 @@ func (svc record) FindByID(namespaceID, moduleID, recordID uint64) (r *types.Rec
})
}
//func (svc record) loadModuleWithNamespace(namespaceID, moduleID uint64) (m *types.Module, err error) {
// return m, func() error {
// if namespaceID == 0 {
// return RecordErrInvalidNamespaceID()
// }
//
// if moduleID == 0 {
// return RecordErrInvalidModuleID()
// }
//
// if m, err = svc.moduleRepo.FindByID(namespaceID, moduleID); err != nil {
// if repository.ErrModuleNotFound.Eq(err) {
// return RecordErrModuleNotFoundModule()
// }
//
// return err
// }
//
// if !svc.ac.CanReadModule(svc.ctx, m) {
// return RecordErrNotAllowedToReadModule()
// }
//
// if m.Fields, err = svc.moduleRepo.FindFields(m.ID); err != nil {
// return err
// }
//
// return nil
// }()
//}
//
//func (svc record) loadNamespace(namespaceID uint64) (ns *types.Namespace, err error) {
// return ns, func() error {
// if namespaceID == 0 {
// return RecordErrInvalidNamespaceID()
// }
//
// if ns, err = svc.nsRepo.FindByID(namespaceID); err != nil {
// if repository.ErrNamespaceNotFound.Eq(err) {
// return RecordErrNamespaceNotFound()
// }
//
// return err
// }
//
// if !svc.ac.CanReadNamespace(svc.ctx, ns) {
// return RecordErrNotAllowedToReadNamespace()
// }
//
// return err
// }()
//}
// Report generates report for a given module using metrics, dimensions and filter
func (svc record) Report(namespaceID, moduleID uint64, metrics, dimensions, filter string) (out interface{}, err error) {
var (
@@ -327,9 +279,7 @@ func (svc record) Find(filter types.RecordFilter) (set types.RecordSet, f types.
return err
}
if err = svc.preloadValues(m, set...); err != nil {
return err
}
trimUnreadableRecordFields(svc.ctx, svc.ac, m, set...)
return nil
}()
@@ -409,10 +359,6 @@ func (svc record) Export(f types.RecordFilter, enc Encoder) (err error) {
return err
}
if err = svc.preloadValues(m, set...); err != nil {
return err
}
return set.Walk(enc.Record)
}()
@@ -644,11 +590,6 @@ func (svc record) update(upd *types.Record) (rec *types.Record, err error) {
return
}
// Preload old record values so we can send it together with event
if err = svc.preloadValues(m, old); err != nil {
return
}
var (
rve *types.RecordValueErrorSet
)
@@ -858,11 +799,6 @@ func (svc record) delete(namespaceID, moduleID, recordID uint64) (del *types.Rec
}
if svc.optEmitEvents {
// Preload old record values so we can send it together with event
if err = svc.preloadValues(m, del); err != nil {
return nil, err
}
// Calling before-record-delete scripts
if err = svc.eventbus.WaitFor(svc.ctx, event.RecordBeforeDelete(nil, del, m, ns, nil)); err != nil {
return nil, err
@@ -1211,10 +1147,6 @@ func (svc record) Iterator(f types.RecordFilter, fn eventbus.HandlerFn, action s
return err
}
if err = svc.preloadValues(m, set...); err != nil {
return err
}
for _, rec := range set {
recordableAction := RecordActionIteratorIteration
@@ -1363,31 +1295,21 @@ func (svc record) generalValueSetValidation(m *types.Module, vv types.RecordValu
return
}
func (svc record) preloadValues(m *types.Module, rr ...*types.Record) error {
panic("refactor")
//if rvs, err := svc.recordRepo.LoadValues(svc.readableFields(m), types.RecordSet(rr).IDs()); err != nil {
// return err
//} else {
// return types.RecordSet(rr).Walk(func(r *types.Record) error {
// r.Values = svc.formatter.Run(m, rvs.FilterByRecordID(r.ID))
// return nil
// })
//}
}
// checks record-value-read access permissions for all module fields and removes unreadable fields from all records
func trimUnreadableRecordFields(ctx context.Context, ac recordValueAccessController, m *types.Module, rr ...*types.Record) {
var (
readableFields = map[string]bool{}
)
// readableFields creates a slice of module fields that current user has permission to read
func (svc record) readableFields(m *types.Module) []string {
ff := make([]string, 0)
for _, f := range m.Fields {
readableFields[f.Name] = ac.CanReadRecordValue(ctx, f)
}
_ = m.Fields.Walk(func(f *types.ModuleField) error {
if svc.ac.CanReadRecordValue(svc.ctx, f) {
ff = append(ff, f.Name)
}
return nil
})
return ff
for _, r := range rr {
r.Values, _ = r.Values.Filter(func(v *types.RecordValue) (bool, error) {
return readableFields[v.Name], nil
})
}
}
// loadRecordCombo Loads namespace, module and record