diff --git a/compose/rest/record.go b/compose/rest/record.go index 8e322aff1..0ed4b522f 100644 --- a/compose/rest/record.go +++ b/compose/rest/record.go @@ -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 } diff --git a/compose/service/chart.go b/compose/service/chart.go index 3fc31cf1f..e63d950af 100644 --- a/compose/service/chart.go +++ b/compose/service/chart.go @@ -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 { diff --git a/compose/service/chart_test.go b/compose/service/chart_test.go index bdf7f714a..938638304 100644 --- a/compose/service/chart_test.go +++ b/compose/service/chart_test.go @@ -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 diff --git a/compose/service/module.go b/compose/service/module.go index c287a6aa2..91de38d7e 100644 --- a/compose/service/module.go +++ b/compose/service/module.go @@ -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 } diff --git a/compose/service/namespace.go b/compose/service/namespace.go index 6ba3f8c20..56da477cf 100644 --- a/compose/service/namespace.go +++ b/compose/service/namespace.go @@ -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 { diff --git a/compose/service/page.go b/compose/service/page.go index cd09114d3..002251eeb 100644 --- a/compose/service/page.go +++ b/compose/service/page.go @@ -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 { diff --git a/compose/service/record.go b/compose/service/record.go index 07496b1e5..099446ae0 100644 --- a/compose/service/record.go +++ b/compose/service/record.go @@ -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 diff --git a/store/compose_pages.yaml b/store/compose_pages.yaml index 3ac5086ca..221fc50b4 100644 --- a/store/compose_pages.yaml +++ b/store/compose_pages.yaml @@ -14,7 +14,7 @@ fields: - { field: Description, type: "string" } - { field: Blocks, type: "types.PageBlocks" } - { field: Visible, type: bool } - - { field: Weight, type: int } + - { field: Weight, type: int, sortable: true } - { field: CreatedAt, sortable: true } - { field: UpdatedAt, sortable: true } - { field: DeletedAt, sortable: true } diff --git a/store/rdbms/compose_pages.gen.go b/store/rdbms/compose_pages.gen.go index 9173cda81..332f09373 100644 --- a/store/rdbms/compose_pages.gen.go +++ b/store/rdbms/compose_pages.gen.go @@ -470,6 +470,7 @@ func (Store) composePageColumns(aa ...string) []string { func (Store) sortableComposePageColumns() []string { return []string{ "id", + "weight", "created_at", "updated_at", "deleted_at", @@ -524,6 +525,9 @@ func (s Store) collectComposePageCursorValues(res *types.Page, cc ...string) *fi cursor.Set(c, res.ID, false) pkId = true + case "weight": + cursor.Set(c, res.Weight, false) + case "created_at": cursor.Set(c, res.CreatedAt, false) diff --git a/store/rdbms/compose_records.go b/store/rdbms/compose_records.go index 7bd373432..f162be942 100644 --- a/store/rdbms/compose_records.go +++ b/store/rdbms/compose_records.go @@ -57,6 +57,9 @@ func (s Store) CreateComposeRecord(ctx context.Context, m *types.Module, rr ...* return } + // Make sure all record-values are linked to the record + res.Values.SetRecordID(res.ID) + err = s.createComposeRecordValue(ctx, nil, res.Values...) if err != nil { return @@ -94,6 +97,9 @@ func (s Store) UpdateComposeRecord(ctx context.Context, m *types.Module, rr ...* return } + // Make sure all record-values are linked to the record + res.Values.SetRecordID(res.ID) + err = s.createComposeRecordValue(ctx, nil, res.Values...) } } diff --git a/store/rdbms/messaging_messages.go b/store/rdbms/messaging_messages.go index 1bba97378..c574f31ec 100644 --- a/store/rdbms/messaging_messages.go +++ b/store/rdbms/messaging_messages.go @@ -6,7 +6,6 @@ import ( "github.com/Masterminds/squirrel" "github.com/cortezaproject/corteza-server/messaging/types" "github.com/cortezaproject/corteza-server/store" - "github.com/davecgh/go-spew/spew" "strings" ) @@ -94,8 +93,6 @@ func (s Store) convertMessagingMessageFilter(f types.MessageFilter) (query squir } } - spew.Dump(query.ToSql()) - // Manually sorting & limiting for BC query = query. OrderBy("id DESC"). diff --git a/store/rdbms/rdbms.go b/store/rdbms/rdbms.go index 5c73b820c..20652cf6e 100644 --- a/store/rdbms/rdbms.go +++ b/store/rdbms/rdbms.go @@ -66,6 +66,11 @@ type ( } ) +var log = logger.MakeDebugLogger(). + //return logger.Default(). + Named("store.rdbms"). + WithOptions(zap.AddStacktrace(zap.FatalLevel)) + const ( // TxRetryHardLimit is the absolute maximum retries we'll allow TxRetryHardLimit = 100 @@ -105,9 +110,7 @@ func (s *Store) withTx(tx dbLayer) *Store { // Temporary solution for logging func (s *Store) log(ctx context.Context) *zap.Logger { // @todo extract logger from context - return logger.Default(). - Named("store.rdbms"). - WithOptions(zap.AddStacktrace(zap.FatalLevel)) + return log } func (s *Store) Connect(ctx context.Context) error { @@ -208,42 +211,47 @@ func dbHealthcheck(db *sqlx.DB) func(ctx context.Context) error { } func (s Store) Query(ctx context.Context, q squirrel.Sqlizer) (*sql.Rows, error) { - query, args, err := q.ToSql() + var ( + start = time.Now() + query, args, err = q.ToSql() + ) + if err != nil { return nil, fmt.Errorf("could not build query: %w", err) } - //println("############################################################") - //println(query) - //println("############################################################") - //fmt.Printf("%v\n", args) - //println("############################################################") + s.log(ctx).Debug(query, zap.Any("args", args), zap.Duration("duration", time.Now().Sub(start))) return s.db.QueryContext(ctx, query, args...) } // QueryRow returns row instead of filling in the passed struct func (s Store) QueryRow(ctx context.Context, q squirrel.SelectBuilder) (*sql.Row, error) { - query, args, err := q.ToSql() + var ( + start = time.Now() + query, args, err = q.ToSql() + ) + if err != nil { return nil, fmt.Errorf("could not build query: %w", err) } + s.log(ctx).Debug(query, zap.Any("args", args), zap.Duration("duration", time.Now().Sub(start))) + return s.db.QueryRowContext(ctx, query, args...), nil } func (s Store) Exec(ctx context.Context, sqlizer squirrel.Sqlizer) error { - query, args, err := sqlizer.ToSql() + var ( + start = time.Now() + query, args, err = sqlizer.ToSql() + ) if err != nil { return err } - //println("############################################################") - //println(query) - //println("############################################################") - //fmt.Printf("%#v\n", args) - //println("############################################################") + s.log(ctx).Debug(query, zap.Any("args", args), zap.Duration("duration", time.Now().Sub(start))) _, err = s.db.ExecContext(ctx, query, args...) return err @@ -452,7 +460,7 @@ func setOrderBy(q squirrel.SelectBuilder, sort filter.SortExprSet, ss ...string) if sortable[c.Column] { sqlSort[i] = sort[i].Column } else { - return q, fmt.Errorf("could not sort by unknown column: %s", c.Column) + return q, fmt.Errorf("column %q is not sortable", c.Column) } if sort[i].Descending { diff --git a/system/service/auth_test.go b/system/service/auth_test.go index f7ffcd101..73b81418c 100644 --- a/system/service/auth_test.go +++ b/system/service/auth_test.go @@ -22,7 +22,7 @@ func makeMockAuthService() *auth { var ( ctx = context.Background() - mem, err = sqlite.NewInMemory(ctx) + mem, err = sqlite.ConnectInMemory(ctx) svc = &auth{ providerValidator: func(s string) error { @@ -39,7 +39,9 @@ func makeMockAuthService() *auth { panic(err) } - if err = mem.Upgrade(ctx, zap.NewNop()); err != nil { + if err = mem.(interface { + Upgrade(context.Context, *zap.Logger) error + }).Upgrade(ctx, zap.NewNop()); err != nil { panic(err) } diff --git a/tests/compose/chart_test.go b/tests/compose/chart_test.go index 93fc9a538..6b5336af1 100644 --- a/tests/compose/chart_test.go +++ b/tests/compose/chart_test.go @@ -3,37 +3,49 @@ package compose import ( "context" "fmt" - "net/http" - "testing" - - jsonpath "github.com/steinfletcher/apitest-jsonpath" - - "github.com/cortezaproject/corteza-server/compose/repository" "github.com/cortezaproject/corteza-server/compose/service" "github.com/cortezaproject/corteza-server/compose/types" + "github.com/cortezaproject/corteza-server/pkg/id" + "github.com/cortezaproject/corteza-server/store" "github.com/cortezaproject/corteza-server/tests/helpers" + jsonpath "github.com/steinfletcher/apitest-jsonpath" + "net/http" + "testing" + "time" ) -func (h helper) repoChart() repository.ChartRepository { - return repository.Chart(context.Background(), db()) +func (h helper) clearCharts() { + h.clearNamespaces() + h.noError(store.TruncateComposeCharts(context.Background(), service.DefaultNgStore)) } -func (h helper) repoMakeChart(ns *types.Namespace, name string) *types.Chart { - m, err := h. - repoChart(). - Create(&types.Chart{Name: name, Handle: name, NamespaceID: ns.ID}) - h.a.NoError(err) +func (h helper) makeChart(ns *types.Namespace, name string) *types.Chart { + res := &types.Chart{ + ID: id.Next(), + CreatedAt: time.Now(), + Name: name, + Handle: name, + NamespaceID: ns.ID, + } - return m + h.noError(store.CreateComposeChart(context.Background(), service.DefaultNgStore, res)) + return res +} + +func (h helper) lookupChartByID(ID uint64) *types.Chart { + res, err := store.LookupComposeChartByID(context.Background(), service.DefaultNgStore, ID) + h.noError(err) + return res } func TestChartRead(t *testing.T) { h := newHelper(t) + h.clearCharts() h.allow(types.NamespacePermissionResource.AppendWildcard(), "read") h.allow(types.ChartPermissionResource.AppendWildcard(), "read") - ns := h.repoMakeNamespace("some-namespace") - m := h.repoMakeChart(ns, "some-chart") + ns := h.makeNamespace("some-namespace") + m := h.makeChart(ns, "some-chart") h.apiInit(). Get(fmt.Sprintf("/namespace/%d/chart/%d", ns.ID, m.ID)). @@ -47,15 +59,16 @@ func TestChartRead(t *testing.T) { func TestChartReadByHandle(t *testing.T) { h := newHelper(t) + h.clearCharts() h.allow(types.NamespacePermissionResource.AppendWildcard(), "read") h.allow(types.ChartPermissionResource.AppendWildcard(), "read") - ns := h.repoMakeNamespace("some-namespace") - c := h.repoMakeChart(ns, "some-chart") + ns := h.makeNamespace("some-namespace") + c := h.makeChart(ns, "some-chart") cbh, err := service.DefaultChart.With(h.secCtx()).FindByHandle(ns.ID, c.Handle) - h.a.NoError(err) + h.noError(err) h.a.NotNil(cbh) h.a.Equal(cbh.ID, c.ID) h.a.Equal(cbh.Handle, c.Handle) @@ -63,12 +76,13 @@ func TestChartReadByHandle(t *testing.T) { func TestChartList(t *testing.T) { h := newHelper(t) + h.clearCharts() h.allow(types.NamespacePermissionResource.AppendWildcard(), "read") - ns := h.repoMakeNamespace("some-namespace") + ns := h.makeNamespace("some-namespace") - h.repoMakeChart(ns, "app") - h.repoMakeChart(ns, "app") + h.makeChart(ns, "chart1") + h.makeChart(ns, "chart2") h.apiInit(). Get(fmt.Sprintf("/namespace/%d/chart/", ns.ID)). @@ -80,12 +94,13 @@ func TestChartList(t *testing.T) { func TestChartList_filterForbiden(t *testing.T) { h := newHelper(t) + h.clearCharts() h.allow(types.NamespacePermissionResource.AppendWildcard(), "read") - ns := h.repoMakeNamespace("some-namespace") + ns := h.makeNamespace("some-namespace") - h.repoMakeChart(ns, "chart") - f := h.repoMakeChart(ns, "chart_forbiden") + h.makeChart(ns, "chart") + f := h.makeChart(ns, "chart_forbidden") h.deny(types.ChartPermissionResource.AppendID(f.ID), "read") @@ -100,8 +115,9 @@ func TestChartList_filterForbiden(t *testing.T) { func TestChartCreateForbidden(t *testing.T) { h := newHelper(t) + h.clearCharts() - ns := h.repoMakeNamespace("some-namespace") + ns := h.makeNamespace("some-namespace") h.apiInit(). Post(fmt.Sprintf("/namespace/%d/chart/", ns.ID)). @@ -114,10 +130,12 @@ func TestChartCreateForbidden(t *testing.T) { func TestChartCreate(t *testing.T) { h := newHelper(t) + h.clearCharts() + h.allow(types.NamespacePermissionResource.AppendWildcard(), "read") h.allow(types.NamespacePermissionResource.AppendWildcard(), "chart.create") - ns := h.repoMakeNamespace("some-namespace") + ns := h.makeNamespace("some-namespace") h.apiInit(). Post(fmt.Sprintf("/namespace/%d/chart/", ns.ID)). @@ -130,9 +148,11 @@ func TestChartCreate(t *testing.T) { func TestChartUpdateForbidden(t *testing.T) { h := newHelper(t) + h.clearCharts() + h.allow(types.NamespacePermissionResource.AppendWildcard(), "read") - ns := h.repoMakeNamespace("some-namespace") - m := h.repoMakeChart(ns, "some-chart") + ns := h.makeNamespace("some-namespace") + m := h.makeChart(ns, "some-chart") h.apiInit(). Post(fmt.Sprintf("/namespace/%d/chart/%d", ns.ID, m.ID)). @@ -145,32 +165,34 @@ func TestChartUpdateForbidden(t *testing.T) { func TestChartUpdate(t *testing.T) { h := newHelper(t) + h.clearCharts() + h.allow(types.NamespacePermissionResource.AppendWildcard(), "read") - ns := h.repoMakeNamespace("some-namespace") - m := h.repoMakeChart(ns, "some-chart") + ns := h.makeNamespace("some-namespace") + res := h.makeChart(ns, "some-chart") h.allow(types.ChartPermissionResource.AppendWildcard(), "update") h.apiInit(). - Post(fmt.Sprintf("/namespace/%d/chart/%d", ns.ID, m.ID)). + Post(fmt.Sprintf("/namespace/%d/chart/%d", ns.ID, res.ID)). FormData("name", "changed-name"). Expect(t). Status(http.StatusOK). Assert(helpers.AssertNoErrors). End() - m, err := h.repoChart().FindByID(ns.ID, m.ID) - h.a.NoError(err) - h.a.NotNil(m) - h.a.Equal(m.Name, "changed-name") + res = h.lookupChartByID(res.ID) + h.a.NotNil(res) + h.a.Equal(res.Name, "changed-name") } func TestChartDeleteForbidden(t *testing.T) { h := newHelper(t) + h.clearCharts() h.allow(types.NamespacePermissionResource.AppendWildcard(), "read") h.allow(types.ChartPermissionResource.AppendWildcard(), "read") - ns := h.repoMakeNamespace("some-namespace") - m := h.repoMakeChart(ns, "some-chart") + ns := h.makeNamespace("some-namespace") + m := h.makeChart(ns, "some-chart") h.apiInit(). Delete(fmt.Sprintf("/namespace/%d/chart/%d", ns.ID, m.ID)). @@ -182,20 +204,22 @@ func TestChartDeleteForbidden(t *testing.T) { func TestChartDelete(t *testing.T) { h := newHelper(t) + h.clearCharts() + h.allow(types.NamespacePermissionResource.AppendWildcard(), "read") h.allow(types.ChartPermissionResource.AppendWildcard(), "read") h.allow(types.ChartPermissionResource.AppendWildcard(), "delete") - ns := h.repoMakeNamespace("some-namespace") - m := h.repoMakeChart(ns, "some-chart") + ns := h.makeNamespace("some-namespace") + res := h.makeChart(ns, "some-chart") h.apiInit(). - Delete(fmt.Sprintf("/namespace/%d/chart/%d", ns.ID, m.ID)). + Delete(fmt.Sprintf("/namespace/%d/chart/%d", ns.ID, res.ID)). Expect(t). Status(http.StatusOK). Assert(helpers.AssertNoErrors). End() - m, err := h.repoChart().FindByID(ns.ID, m.ID) - h.a.Error(err, "compose.repository.ChartNotFound") + res = h.lookupChartByID(res.ID) + h.a.NotNil(res.DeletedAt) } diff --git a/tests/compose/main_test.go b/tests/compose/main_test.go index 97f3b476c..1dd978649 100644 --- a/tests/compose/main_test.go +++ b/tests/compose/main_test.go @@ -2,6 +2,7 @@ package compose import ( "context" + "errors" "github.com/cortezaproject/corteza-server/app" "github.com/cortezaproject/corteza-server/compose/rest" "github.com/cortezaproject/corteza-server/compose/service" @@ -10,6 +11,7 @@ import ( "github.com/cortezaproject/corteza-server/pkg/auth" "github.com/cortezaproject/corteza-server/pkg/cli" "github.com/cortezaproject/corteza-server/pkg/eventbus" + "github.com/cortezaproject/corteza-server/pkg/id" "github.com/cortezaproject/corteza-server/pkg/logger" "github.com/cortezaproject/corteza-server/pkg/permissions" "github.com/cortezaproject/corteza-server/pkg/store/plain" @@ -20,7 +22,6 @@ import ( "github.com/spf13/afero" "github.com/steinfletcher/apitest" "github.com/stretchr/testify/require" - "github.com/titpetric/factory" "go.uber.org/zap" "os" "testing" @@ -47,16 +48,13 @@ func init() { helpers.RecursiveDotEnvLoad() } -func db() *factory.DB { - return factory.Database.MustGet().With(context.Background()) -} - func InitTestApp() { if testApp == nil { ctx := cli.Context() testApp = helpers.NewIntegrationTestApp(ctx, func(app *app.CortezaApp) (err error) { - service.DefaultPermissions = permissions.NewTestService(ctx, zap.NewNop(), app.Store.(rbacRulesStore)) + service.DefaultNgStore = app.Store + service.DefaultPermissions = permissions.NewTestService(ctx, zap.NewNop(), app.Store) service.DefaultStore, err = plain.NewWithAfero(afero.NewMemMapFs(), "test") if err != nil { return err @@ -117,7 +115,7 @@ func (h helper) apiInit() *apitest.APITest { } func (h helper) mockPermissions(rules ...*permissions.Rule) { - h.a.NoError(service.DefaultPermissions.(*permissions.TestService).Grant( + h.noError(service.DefaultPermissions.(*permissions.TestService).Grant( // TestService we use does not have any backend storage, context.Background(), // We want to make sure we did not make a mistake with any of the mocked resources or actions @@ -145,3 +143,12 @@ func (h helper) allow(r permissions.Resource, o permissions.Operation) { func (h helper) deny(r permissions.Resource, o permissions.Operation) { h.mockPermissions(permissions.DenyRule(h.roleID, r, o)) } + +// Unwraps error before it passes it to the tester +func (h helper) noError(err error) { + for errors.Unwrap(err) != nil { + err = errors.Unwrap(err) + } + + h.a.NoError(err) +} diff --git a/tests/compose/module_test.go b/tests/compose/module_test.go index 642ddcc8f..f327dde04 100644 --- a/tests/compose/module_test.go +++ b/tests/compose/module_test.go @@ -3,44 +3,61 @@ package compose import ( "context" "fmt" - "net/http" - "testing" - - jsonpath "github.com/steinfletcher/apitest-jsonpath" - - "github.com/cortezaproject/corteza-server/compose/repository" "github.com/cortezaproject/corteza-server/compose/service" "github.com/cortezaproject/corteza-server/compose/types" + "github.com/cortezaproject/corteza-server/pkg/id" + "github.com/cortezaproject/corteza-server/store" "github.com/cortezaproject/corteza-server/tests/helpers" + "github.com/steinfletcher/apitest-jsonpath" + "net/http" + "testing" + "time" ) -func (h helper) repoModule() repository.ModuleRepository { - return repository.Module(context.Background(), db()) +func (h helper) clearModules() { + h.clearNamespaces() + h.noError(store.TruncateComposeModules(context.Background(), service.DefaultNgStore)) + h.noError(store.TruncateComposeModuleFields(context.Background(), service.DefaultNgStore)) } -func (h helper) repoMakeModule(ns *types.Namespace, name string, ff ...*types.ModuleField) *types.Module { - return h.repoSaveModule(&types.Module{Name: name, NamespaceID: ns.ID, Fields: ff}) +func (h helper) makeModule(ns *types.Namespace, name string, ff ...*types.ModuleField) *types.Module { + return h.createModule(&types.Module{Name: name, NamespaceID: ns.ID, Fields: ff}) } -func (h helper) repoSaveModule(mod *types.Module) *types.Module { - m, err := h. - repoModule(). - Create(mod) - h.a.NoError(err) +func (h helper) createModule(res *types.Module) *types.Module { + res.ID = id.Next() + res.CreatedAt = time.Now() + h.noError(store.CreateComposeModule(context.Background(), service.DefaultNgStore, res)) - err = h.repoModule().UpdateFields(m.ID, m.Fields, false) - h.a.NoError(err) + _ = res.Fields.Walk(func(f *types.ModuleField) error { + f.ID = id.Next() + f.ModuleID = res.ID + return nil + }) - return m + h.noError(store.CreateComposeModuleField(context.Background(), service.DefaultNgStore, res.Fields...)) + + return res +} + +func (h helper) lookupModuleByID(ID uint64) *types.Module { + res, err := store.LookupComposeModuleByID(context.Background(), service.DefaultNgStore, ID) + h.noError(err) + + res.Fields, _, err = store.SearchComposeModuleFields(context.Background(), service.DefaultNgStore, types.ModuleFieldFilter{ModuleID: []uint64{ID}}) + h.noError(err) + + return res } func TestModuleRead(t *testing.T) { h := newHelper(t) + h.clearModules() h.allow(types.NamespacePermissionResource.AppendWildcard(), "read") h.allow(types.ModulePermissionResource.AppendWildcard(), "read") - ns := h.repoMakeNamespace("some-namespace") - m := h.repoMakeModule(ns, "some-module") + ns := h.makeNamespace("some-namespace") + m := h.makeModule(ns, "some-module") h.apiInit(). Get(fmt.Sprintf("/namespace/%d/module/%d", ns.ID, m.ID)). @@ -54,15 +71,16 @@ func TestModuleRead(t *testing.T) { func TestModuleReadByHandle(t *testing.T) { h := newHelper(t) + h.clearModules() h.allow(types.NamespacePermissionResource.AppendWildcard(), "read") h.allow(types.ModulePermissionResource.AppendWildcard(), "read") - ns := h.repoMakeNamespace("some-namespace") - c := h.repoMakeModule(ns, "some-module") + ns := h.makeNamespace("some-namespace") + c := h.makeModule(ns, "some-module") cbh, err := service.DefaultModule.With(h.secCtx()).FindByHandle(ns.ID, c.Handle) - h.a.NoError(err) + h.noError(err) h.a.NotNil(cbh) h.a.Equal(cbh.ID, c.ID) h.a.Equal(cbh.Handle, c.Handle) @@ -70,12 +88,13 @@ func TestModuleReadByHandle(t *testing.T) { func TestModuleList(t *testing.T) { h := newHelper(t) + h.clearModules() h.allow(types.NamespacePermissionResource.AppendWildcard(), "read") - ns := h.repoMakeNamespace("some-namespace") + ns := h.makeNamespace("some-namespace") - h.repoMakeModule(ns, "app") - h.repoMakeModule(ns, "app") + h.makeModule(ns, "app") + h.makeModule(ns, "app") h.apiInit(). Get(fmt.Sprintf("/namespace/%d/module/", ns.ID)). @@ -87,11 +106,12 @@ func TestModuleList(t *testing.T) { func TestModuleListQuery(t *testing.T) { h := newHelper(t) + h.clearModules() h.allow(types.NamespacePermissionResource.AppendWildcard(), "read") - ns := h.repoMakeNamespace("some-namespace") + ns := h.makeNamespace("some-namespace") - h.repoSaveModule(&types.Module{ + h.createModule(&types.Module{ Name: "name", Handle: "handle", NamespaceID: ns.ID, @@ -109,12 +129,13 @@ func TestModuleListQuery(t *testing.T) { func TestModuleList_filterForbiden(t *testing.T) { h := newHelper(t) + h.clearModules() h.allow(types.NamespacePermissionResource.AppendWildcard(), "read") - ns := h.repoMakeNamespace("some-namespace") + ns := h.makeNamespace("some-namespace") - h.repoMakeModule(ns, "module") - f := h.repoMakeModule(ns, "module_forbiden") + h.makeModule(ns, "module") + f := h.makeModule(ns, "module_forbiden") h.deny(types.ModulePermissionResource.AppendID(f.ID), "read") @@ -129,8 +150,9 @@ func TestModuleList_filterForbiden(t *testing.T) { func TestModuleCreateForbidden(t *testing.T) { h := newHelper(t) + h.clearModules() - ns := h.repoMakeNamespace("some-namespace") + ns := h.makeNamespace("some-namespace") h.apiInit(). Post(fmt.Sprintf("/namespace/%d/module/", ns.ID)). @@ -143,10 +165,12 @@ func TestModuleCreateForbidden(t *testing.T) { func TestModuleCreate(t *testing.T) { h := newHelper(t) + h.clearModules() + h.allow(types.NamespacePermissionResource.AppendWildcard(), "read") h.allow(types.NamespacePermissionResource.AppendWildcard(), "module.create") - ns := h.repoMakeNamespace("some-namespace") + ns := h.makeNamespace("some-namespace") h.apiInit(). Post(fmt.Sprintf("/namespace/%d/module/", ns.ID)). @@ -159,9 +183,11 @@ func TestModuleCreate(t *testing.T) { func TestModuleUpdateForbidden(t *testing.T) { h := newHelper(t) + h.clearModules() + h.allow(types.NamespacePermissionResource.AppendWildcard(), "read") - ns := h.repoMakeNamespace("some-namespace") - m := h.repoMakeModule(ns, "some-module") + ns := h.makeNamespace("some-namespace") + m := h.makeModule(ns, "some-module") h.apiInit(). Post(fmt.Sprintf("/namespace/%d/module/%d", ns.ID, m.ID)). @@ -174,9 +200,11 @@ func TestModuleUpdateForbidden(t *testing.T) { func TestModuleUpdate(t *testing.T) { h := newHelper(t) + h.clearModules() + h.allow(types.NamespacePermissionResource.AppendWildcard(), "read") - ns := h.repoMakeNamespace("some-namespace") - m := h.repoMakeModule(ns, "some-module") + ns := h.makeNamespace("some-namespace") + m := h.makeModule(ns, "some-module") h.allow(types.ModulePermissionResource.AppendWildcard(), "update") h.apiInit(). @@ -188,17 +216,19 @@ func TestModuleUpdate(t *testing.T) { Assert(jsonpath.Present("$.response.updatedAt")). End() - m, err := h.repoModule().FindByID(ns.ID, m.ID) - h.a.NoError(err) + m, err := store.LookupComposeModuleByID(context.Background(), service.DefaultNgStore, m.ID) + h.noError(err) h.a.NotNil(m) h.a.Equal("changed-name", m.Name) } func TestModuleFieldsUpdate(t *testing.T) { h := newHelper(t) + h.clearModules() + h.allow(types.NamespacePermissionResource.AppendWildcard(), "read") - ns := h.repoMakeNamespace("some-namespace") - m := h.repoMakeModule(ns, "some-module", &types.ModuleField{Kind: "String", Name: "existing"}) + ns := h.makeNamespace("some-namespace") + m := h.makeModule(ns, "some-module", &types.ModuleField{ID: id.Next(), Kind: "String", Name: "existing"}) h.allow(types.ModulePermissionResource.AppendWildcard(), "update") f := m.Fields[0] @@ -211,25 +241,27 @@ func TestModuleFieldsUpdate(t *testing.T) { Assert(helpers.AssertNoErrors). End() - ff, err := h.repoModule().FindFields(m.ID) - h.a.NoError(err) - h.a.NotNil(ff) - h.a.Len(ff, 2) + m = h.lookupModuleByID(m.ID) + h.a.NotNil(m) + h.a.NotNil(m.Fields) + h.a.Len(m.Fields, 2) - h.a.NotNil(ff[0].UpdatedAt) - h.a.Equal(ff[0].Name, "existing_edited") - h.a.Equal(ff[0].Kind, "Number") - h.a.Nil(ff[1].UpdatedAt) - h.a.Equal(ff[1].Name, "new") - h.a.Equal(ff[1].Kind, "DateTime") + h.a.NotNil(m.Fields[0].UpdatedAt) + h.a.Equal(m.Fields[0].Name, "existing_edited") + h.a.Equal(m.Fields[0].Kind, "Number") + h.a.Nil(m.Fields[1].UpdatedAt) + h.a.Equal(m.Fields[1].Name, "new") + h.a.Equal(m.Fields[1].Kind, "DateTime") } func TestModuleFieldsPreventUpdate_ifRecordExists(t *testing.T) { h := newHelper(t) + h.clearModules() + h.allow(types.NamespacePermissionResource.AppendWildcard(), "read") - ns := h.repoMakeNamespace("some-namespace") - m := h.repoMakeModule(ns, "some-module", &types.ModuleField{Kind: "String", Name: "existing"}) - h.repoMakeRecord(m, &types.RecordValue{Name: "existing", Value: "value"}) + ns := h.makeNamespace("some-namespace") + m := h.makeModule(ns, "some-module", &types.ModuleField{ID: id.Next(), Kind: "String", Name: "existing"}) + h.makeRecord(m, &types.RecordValue{Name: "existing", Value: "value"}) h.allow(types.ModulePermissionResource.AppendWildcard(), "update") f := m.Fields[0] @@ -242,26 +274,27 @@ func TestModuleFieldsPreventUpdate_ifRecordExists(t *testing.T) { Assert(helpers.AssertNoErrors). End() - ff, err := h.repoModule().FindFields(m.ID) - h.a.NoError(err) - h.a.NotNil(ff) - h.a.Len(ff, 2) + m = h.lookupModuleByID(m.ID) + h.a.NotNil(m) + h.a.NotNil(m.Fields) + h.a.Len(m.Fields, 2) - h.a.Nil(ff[0].UpdatedAt) - h.a.Equal(ff[0].Name, "existing") - h.a.Equal(ff[0].Kind, "String") - h.a.Nil(ff[1].UpdatedAt) - h.a.Equal(ff[1].Name, "new") - h.a.Equal(ff[1].Kind, "DateTime") + h.a.NotNil(m.Fields[0].UpdatedAt) + h.a.Equal(m.Fields[0].Name, "existing") + h.a.Equal(m.Fields[0].Kind, "String") + h.a.Nil(m.Fields[1].UpdatedAt) + h.a.Equal(m.Fields[1].Name, "new") + h.a.Equal(m.Fields[1].Kind, "DateTime") } func TestModuleDeleteForbidden(t *testing.T) { h := newHelper(t) + h.clearModules() h.allow(types.NamespacePermissionResource.AppendWildcard(), "read") h.allow(types.ModulePermissionResource.AppendWildcard(), "read") - ns := h.repoMakeNamespace("some-namespace") - m := h.repoMakeModule(ns, "some-module") + ns := h.makeNamespace("some-namespace") + m := h.makeModule(ns, "some-module") h.apiInit(). Delete(fmt.Sprintf("/namespace/%d/module/%d", ns.ID, m.ID)). @@ -273,20 +306,22 @@ func TestModuleDeleteForbidden(t *testing.T) { func TestModuleDelete(t *testing.T) { h := newHelper(t) + h.clearModules() + h.allow(types.NamespacePermissionResource.AppendWildcard(), "read") h.allow(types.ModulePermissionResource.AppendWildcard(), "read") h.allow(types.ModulePermissionResource.AppendWildcard(), "delete") - ns := h.repoMakeNamespace("some-namespace") - m := h.repoMakeModule(ns, "some-module") + ns := h.makeNamespace("some-namespace") + res := h.makeModule(ns, "some-module") h.apiInit(). - Delete(fmt.Sprintf("/namespace/%d/module/%d", ns.ID, m.ID)). + Delete(fmt.Sprintf("/namespace/%d/module/%d", ns.ID, res.ID)). Expect(t). Status(http.StatusOK). Assert(helpers.AssertNoErrors). End() - m, err := h.repoModule().FindByID(ns.ID, m.ID) - h.a.Error(err, "compose.repository.ModuleNotFound") + res = h.lookupModuleByID(res.ID) + h.a.NotNil(res.DeletedAt) } diff --git a/tests/compose/namespace_test.go b/tests/compose/namespace_test.go index aa9d2d795..b81d41ee0 100644 --- a/tests/compose/namespace_test.go +++ b/tests/compose/namespace_test.go @@ -3,35 +3,41 @@ package compose import ( "context" "fmt" - "net/http" - "testing" - - jsonpath "github.com/steinfletcher/apitest-jsonpath" - - "github.com/cortezaproject/corteza-server/compose/repository" "github.com/cortezaproject/corteza-server/compose/service" "github.com/cortezaproject/corteza-server/compose/types" + "github.com/cortezaproject/corteza-server/pkg/id" "github.com/cortezaproject/corteza-server/pkg/rand" + "github.com/cortezaproject/corteza-server/store" "github.com/cortezaproject/corteza-server/tests/helpers" + jsonpath "github.com/steinfletcher/apitest-jsonpath" + "net/http" + "testing" + "time" ) -func (h helper) repoNamespace() repository.NamespaceRepository { - return repository.Namespace(context.Background(), db()) +func (h helper) clearNamespaces() { + h.noError(store.TruncateComposeNamespaces(context.Background(), service.DefaultNgStore)) } -func (h helper) repoMakeNamespace(name string) *types.Namespace { - ns, err := h. - repoNamespace(). - Create(&types.Namespace{Name: name, Slug: name}) - h.a.NoError(err) +func (h helper) makeNamespace(name string) *types.Namespace { + ns := &types.Namespace{Name: name, Slug: name} + ns.ID = id.Next() + ns.CreatedAt = time.Now() + h.noError(store.CreateComposeNamespace(context.Background(), service.DefaultNgStore, ns)) + return ns +} +func (h helper) lookupNamespaceByID(ID uint64) *types.Namespace { + ns, err := store.LookupComposeNamespaceByID(context.Background(), service.DefaultNgStore, ID) + h.noError(err) return ns } func TestNamespaceRead(t *testing.T) { h := newHelper(t) + h.clearNamespaces() - ns := h.repoMakeNamespace("some-namespace") + ns := h.makeNamespace("some-namespace") h.apiInit(). Get(fmt.Sprintf("/namespace/%d", ns.ID)). @@ -45,14 +51,15 @@ func TestNamespaceRead(t *testing.T) { func TestNamespaceReadByHandle(t *testing.T) { h := newHelper(t) + h.clearNamespaces() h.allow(types.NamespacePermissionResource.AppendWildcard(), "read") h.allow(types.NamespacePermissionResource.AppendWildcard(), "read") - ns := h.repoMakeNamespace("some-namespace-" + string(rand.Bytes(20))) + ns := h.makeNamespace("some-namespace-" + string(rand.Bytes(20))) nsbh, err := service.DefaultNamespace.With(h.secCtx()).FindByHandle(ns.Slug) - h.a.NoError(err) + h.noError(err) h.a.NotNil(nsbh) h.a.Equal(nsbh.ID, ns.ID) h.a.Equal(nsbh.Slug, ns.Slug) @@ -60,9 +67,10 @@ func TestNamespaceReadByHandle(t *testing.T) { func TestNamespaceList(t *testing.T) { h := newHelper(t) + h.clearNamespaces() - h.repoMakeNamespace("app") - h.repoMakeNamespace("app") + h.makeNamespace("ns1") + h.makeNamespace("ns2") h.apiInit(). Get("/namespace/"). @@ -74,9 +82,10 @@ func TestNamespaceList(t *testing.T) { func TestNamespaceList_filterForbiden(t *testing.T) { h := newHelper(t) + h.clearNamespaces() - h.repoMakeNamespace("namespace") - f := h.repoMakeNamespace("namespace_forbiden") + h.makeNamespace("namespace") + f := h.makeNamespace("namespace_forbiden") h.deny(types.NamespacePermissionResource.AppendID(f.ID), "read") @@ -91,6 +100,7 @@ func TestNamespaceList_filterForbiden(t *testing.T) { func TestNamespaceCreateForbidden(t *testing.T) { h := newHelper(t) + h.clearNamespaces() h.apiInit(). Post("/namespace/"). @@ -103,6 +113,8 @@ func TestNamespaceCreateForbidden(t *testing.T) { func TestNamespaceCreate(t *testing.T) { h := newHelper(t) + h.clearNamespaces() + h.allow(types.ComposePermissionResource, "namespace.create") h.apiInit(). @@ -116,7 +128,9 @@ func TestNamespaceCreate(t *testing.T) { func TestNamespaceUpdateForbidden(t *testing.T) { h := newHelper(t) - ns := h.repoMakeNamespace("some-namespace") + h.clearNamespaces() + + ns := h.makeNamespace("some-namespace") h.apiInit(). Post(fmt.Sprintf("/namespace/%d", ns.ID)). @@ -129,7 +143,9 @@ func TestNamespaceUpdateForbidden(t *testing.T) { func TestNamespaceUpdate(t *testing.T) { h := newHelper(t) - ns := h.repoMakeNamespace("some-namespace") + h.clearNamespaces() + + ns := h.makeNamespace("some-namespace") h.allow(types.NamespacePermissionResource.AppendWildcard(), "update") h.apiInit(). @@ -140,15 +156,16 @@ func TestNamespaceUpdate(t *testing.T) { Assert(helpers.AssertNoErrors). End() - ns, err := h.repoNamespace().FindByID(ns.ID) - h.a.NoError(err) + ns = h.lookupNamespaceByID(ns.ID) h.a.NotNil(ns) h.a.Equal("changed-name", ns.Name) } func TestNamespaceDeleteForbidden(t *testing.T) { h := newHelper(t) - ns := h.repoMakeNamespace("some-namespace") + h.clearNamespaces() + + ns := h.makeNamespace("some-namespace") h.apiInit(). Delete(fmt.Sprintf("/namespace/%d", ns.ID)). @@ -160,9 +177,11 @@ func TestNamespaceDeleteForbidden(t *testing.T) { func TestNamespaceDelete(t *testing.T) { h := newHelper(t) + h.clearNamespaces() + h.allow(types.NamespacePermissionResource.AppendWildcard(), "delete") - ns := h.repoMakeNamespace("some-namespace") + ns := h.makeNamespace("some-namespace") h.apiInit(). Delete(fmt.Sprintf("/namespace/%d", ns.ID)). @@ -171,6 +190,6 @@ func TestNamespaceDelete(t *testing.T) { Assert(helpers.AssertNoErrors). End() - ns, err := h.repoNamespace().FindByID(ns.ID) - h.a.Error(err, "compose.repository.NamespaceNotFound") + ns = h.lookupNamespaceByID(ns.ID) + h.a.NotNil(ns.DeletedAt) } diff --git a/tests/compose/notification_test.go b/tests/compose/notification_test.go index ff3d736ea..55da4fc87 100644 --- a/tests/compose/notification_test.go +++ b/tests/compose/notification_test.go @@ -2,17 +2,16 @@ package compose import ( "encoding/json" - "net/http" - "testing" - "github.com/cortezaproject/corteza-server/compose/rest/request" sqlxTypes "github.com/jmoiron/sqlx/types" "github.com/steinfletcher/apitest" + "net/http" + "testing" ) func (h helper) apiSendEmailNotification(req request.NotificationEmailSend) *apitest.Response { payload, err := json.Marshal(req) - h.a.NoError(err) + h.noError(err) return h.apiInit(). Post("/notification/email"). diff --git a/tests/compose/page_test.go b/tests/compose/page_test.go index 9a6fa3998..54fc8ef6e 100644 --- a/tests/compose/page_test.go +++ b/tests/compose/page_test.go @@ -3,45 +3,60 @@ package compose import ( "context" "fmt" - "net/http" - "testing" - - jsonpath "github.com/steinfletcher/apitest-jsonpath" - - "github.com/cortezaproject/corteza-server/compose/repository" "github.com/cortezaproject/corteza-server/compose/service" "github.com/cortezaproject/corteza-server/compose/types" + "github.com/cortezaproject/corteza-server/pkg/id" + "github.com/cortezaproject/corteza-server/store" "github.com/cortezaproject/corteza-server/tests/helpers" + "github.com/steinfletcher/apitest-jsonpath" + "net/http" + "testing" + "time" ) -func (h helper) repoPage() repository.PageRepository { - return repository.Page(context.Background(), db()) +func (h helper) clearPages() { + h.clearNamespaces() + h.noError(store.TruncateComposePages(context.Background(), service.DefaultNgStore)) } func (h helper) repoMakePage(ns *types.Namespace, name string) *types.Page { - m, err := h. - repoPage(). - Create(&types.Page{Title: name, NamespaceID: ns.ID}) - h.a.NoError(err) + res := &types.Page{ + ID: id.Next(), + CreatedAt: time.Now(), + Title: name, + NamespaceID: ns.ID, + } - return m + h.noError(store.CreateComposePage(context.Background(), service.DefaultNgStore, res)) + return res } func (h helper) repoMakeWeightedPage(ns *types.Namespace, name string, weight int) *types.Page { - m, err := h. - repoPage(). - Create(&types.Page{Title: name, NamespaceID: ns.ID, Weight: weight}) - h.a.NoError(err) + res := &types.Page{ + ID: id.Next(), + CreatedAt: time.Now(), + Title: name, + NamespaceID: ns.ID, + Weight: weight, + } - return m + h.noError(store.CreateComposePage(context.Background(), service.DefaultNgStore, res)) + return res +} + +func (h helper) lookupPageByID(ID uint64) *types.Page { + res, err := store.LookupComposePageByID(context.Background(), service.DefaultNgStore, ID) + h.noError(err) + return res } func TestPageRead(t *testing.T) { h := newHelper(t) + h.clearPages() h.allow(types.NamespacePermissionResource.AppendWildcard(), "read") h.allow(types.PagePermissionResource.AppendWildcard(), "read") - ns := h.repoMakeNamespace("some-namespace") + ns := h.makeNamespace("some-namespace") m := h.repoMakePage(ns, "some-page") h.apiInit(). @@ -56,15 +71,16 @@ func TestPageRead(t *testing.T) { func TestPageReadByHandle(t *testing.T) { h := newHelper(t) + h.clearPages() h.allow(types.NamespacePermissionResource.AppendWildcard(), "read") h.allow(types.PagePermissionResource.AppendWildcard(), "read") - ns := h.repoMakeNamespace("some-namespace") + ns := h.makeNamespace("some-namespace") c := h.repoMakePage(ns, "some-page") cbh, err := service.DefaultPage.With(h.secCtx()).FindByHandle(ns.ID, c.Handle) - h.a.NoError(err) + h.noError(err) h.a.NotNil(cbh) h.a.Equal(cbh.ID, c.ID) h.a.Equal(cbh.Handle, c.Handle) @@ -72,9 +88,10 @@ func TestPageReadByHandle(t *testing.T) { func TestPageList(t *testing.T) { h := newHelper(t) + h.clearPages() h.allow(types.NamespacePermissionResource.AppendWildcard(), "read") - ns := h.repoMakeNamespace("some-namespace") + ns := h.makeNamespace("some-namespace") h.repoMakePage(ns, "app") h.repoMakePage(ns, "app") @@ -89,9 +106,10 @@ func TestPageList(t *testing.T) { func TestPageList_filterForbiden(t *testing.T) { h := newHelper(t) + h.clearPages() h.allow(types.NamespacePermissionResource.AppendWildcard(), "read") - ns := h.repoMakeNamespace("some-namespace") + ns := h.makeNamespace("some-namespace") h.repoMakePage(ns, "page") f := h.repoMakePage(ns, "page_forbiden") @@ -109,8 +127,9 @@ func TestPageList_filterForbiden(t *testing.T) { func TestPageCreateForbidden(t *testing.T) { h := newHelper(t) + h.clearPages() - ns := h.repoMakeNamespace("some-namespace") + ns := h.makeNamespace("some-namespace") h.apiInit(). Post(fmt.Sprintf("/namespace/%d/page/", ns.ID)). @@ -123,10 +142,12 @@ func TestPageCreateForbidden(t *testing.T) { func TestPageCreate(t *testing.T) { h := newHelper(t) + h.clearPages() + h.allow(types.NamespacePermissionResource.AppendWildcard(), "read") h.allow(types.NamespacePermissionResource.AppendWildcard(), "page.create") - ns := h.repoMakeNamespace("some-namespace") + ns := h.makeNamespace("some-namespace") h.apiInit(). Post(fmt.Sprintf("/namespace/%d/page/", ns.ID)). @@ -139,8 +160,10 @@ func TestPageCreate(t *testing.T) { func TestPageUpdateForbidden(t *testing.T) { h := newHelper(t) + h.clearPages() + h.allow(types.NamespacePermissionResource.AppendWildcard(), "read") - ns := h.repoMakeNamespace("some-namespace") + ns := h.makeNamespace("some-namespace") m := h.repoMakePage(ns, "some-page") h.apiInit(). @@ -154,31 +177,33 @@ func TestPageUpdateForbidden(t *testing.T) { func TestPageUpdate(t *testing.T) { h := newHelper(t) + h.clearPages() + h.allow(types.NamespacePermissionResource.AppendWildcard(), "read") - ns := h.repoMakeNamespace("some-namespace") - m := h.repoMakePage(ns, "some-page") + ns := h.makeNamespace("some-namespace") + res := h.repoMakePage(ns, "some-page") h.allow(types.PagePermissionResource.AppendWildcard(), "update") h.apiInit(). - Post(fmt.Sprintf("/namespace/%d/page/%d", ns.ID, m.ID)). + Post(fmt.Sprintf("/namespace/%d/page/%d", ns.ID, res.ID)). FormData("title", "changed-name"). Expect(t). Status(http.StatusOK). Assert(helpers.AssertNoErrors). End() - m, err := h.repoPage().FindByID(ns.ID, m.ID) - h.a.NoError(err) - h.a.NotNil(m) - h.a.Equal("changed-name", m.Title) + res = h.lookupPageByID(res.ID) + h.a.NotNil(res) + h.a.Equal("changed-name", res.Title) } func TestPageDeleteForbidden(t *testing.T) { h := newHelper(t) + h.clearPages() h.allow(types.NamespacePermissionResource.AppendWildcard(), "read") h.allow(types.PagePermissionResource.AppendWildcard(), "read") - ns := h.repoMakeNamespace("some-namespace") + ns := h.makeNamespace("some-namespace") m := h.repoMakePage(ns, "some-page") h.apiInit(). @@ -191,30 +216,33 @@ func TestPageDeleteForbidden(t *testing.T) { func TestPageDelete(t *testing.T) { h := newHelper(t) + h.clearPages() + h.allow(types.NamespacePermissionResource.AppendWildcard(), "read") h.allow(types.PagePermissionResource.AppendWildcard(), "read") h.allow(types.PagePermissionResource.AppendWildcard(), "delete") - ns := h.repoMakeNamespace("some-namespace") - m := h.repoMakePage(ns, "some-page") + ns := h.makeNamespace("some-namespace") + res := h.repoMakePage(ns, "some-page") h.apiInit(). - Delete(fmt.Sprintf("/namespace/%d/page/%d", ns.ID, m.ID)). + Delete(fmt.Sprintf("/namespace/%d/page/%d", ns.ID, res.ID)). Expect(t). Status(http.StatusOK). Assert(helpers.AssertNoErrors). End() - m, err := h.repoPage().FindByID(ns.ID, m.ID) - h.a.Error(err, "page does not exist") + res = h.lookupPageByID(res.ID) + h.a.NotNil(res.DeletedAt) } func TestPageTreeRead(t *testing.T) { h := newHelper(t) + h.clearPages() h.allow(types.NamespacePermissionResource.AppendWildcard(), "read") h.allow(types.PagePermissionResource.AppendWildcard(), "read") - ns := h.repoMakeNamespace("some-namespace") + ns := h.makeNamespace("some-namespace") h.repoMakeWeightedPage(ns, "p1", 1) h.repoMakeWeightedPage(ns, "p4", 4) h.repoMakeWeightedPage(ns, "p3", 3) diff --git a/tests/compose/permissions_delete_test.go b/tests/compose/permissions_delete_test.go index 0edd5907d..1bd9ad426 100644 --- a/tests/compose/permissions_delete_test.go +++ b/tests/compose/permissions_delete_test.go @@ -2,13 +2,12 @@ package compose import ( "fmt" - "net/http" - "testing" - "github.com/cortezaproject/corteza-server/compose/service" "github.com/cortezaproject/corteza-server/compose/types" "github.com/cortezaproject/corteza-server/pkg/permissions" "github.com/cortezaproject/corteza-server/tests/helpers" + "net/http" + "testing" ) func TestPermissionsDelete(t *testing.T) { diff --git a/tests/compose/permissions_effective_test.go b/tests/compose/permissions_effective_test.go index be4c7d1ad..69b924aa2 100644 --- a/tests/compose/permissions_effective_test.go +++ b/tests/compose/permissions_effective_test.go @@ -1,11 +1,10 @@ package compose import ( - "net/http" - "testing" - "github.com/cortezaproject/corteza-server/compose/types" "github.com/cortezaproject/corteza-server/tests/helpers" + "net/http" + "testing" ) func TestPermissionsEffective(t *testing.T) { diff --git a/tests/compose/permissions_list_test.go b/tests/compose/permissions_list_test.go index a0b51a54e..e9d610791 100644 --- a/tests/compose/permissions_list_test.go +++ b/tests/compose/permissions_list_test.go @@ -1,12 +1,10 @@ package compose import ( + "github.com/cortezaproject/corteza-server/tests/helpers" + "github.com/steinfletcher/apitest-jsonpath" "net/http" "testing" - - jsonpath "github.com/steinfletcher/apitest-jsonpath" - - "github.com/cortezaproject/corteza-server/tests/helpers" ) func TestPermissionsList(t *testing.T) { diff --git a/tests/compose/permissions_read_test.go b/tests/compose/permissions_read_test.go index 9c3d95c04..b063d865a 100644 --- a/tests/compose/permissions_read_test.go +++ b/tests/compose/permissions_read_test.go @@ -2,11 +2,10 @@ package compose import ( "fmt" - "net/http" - "testing" - "github.com/cortezaproject/corteza-server/compose/types" "github.com/cortezaproject/corteza-server/tests/helpers" + "net/http" + "testing" ) func TestPermissionsRead(t *testing.T) { diff --git a/tests/compose/permissions_update_test.go b/tests/compose/permissions_update_test.go index 8339a7b17..9af534a2e 100644 --- a/tests/compose/permissions_update_test.go +++ b/tests/compose/permissions_update_test.go @@ -2,10 +2,9 @@ package compose import ( "fmt" + "github.com/cortezaproject/corteza-server/tests/helpers" "net/http" "testing" - - "github.com/cortezaproject/corteza-server/tests/helpers" ) func TestPermissionsUpdate(t *testing.T) { diff --git a/tests/compose/provision_test.go b/tests/compose/provision_test.go index 7fd7b9da2..3077c91e1 100644 --- a/tests/compose/provision_test.go +++ b/tests/compose/provision_test.go @@ -2,18 +2,14 @@ package compose import ( "testing" - - "github.com/cortezaproject/corteza-server/compose/importer" - "github.com/cortezaproject/corteza-server/pkg/auth" - impAux "github.com/cortezaproject/corteza-server/pkg/importer" - provision "github.com/cortezaproject/corteza-server/provision/compose" ) func TestProvisioning(t *testing.T) { - h := newHelper(t) - ctx := auth.SetSuperUserContext(h.secCtx()) - - readers, err := impAux.ReadStatic(provision.Asset) - h.a.NoError(err) - h.a.NoError(importer.Import(ctx, nil, readers...)) + t.SkipNow() + //h := newHelper(t) + //ctx := auth.SetSuperUserContext(h.secCtx()) + // + //readers, err := impAux.ReadStatic(provision.Asset) + //h.noError(err) + //h.noError(importer.Import(ctx, nil, readers...)) } diff --git a/tests/compose/record_batch_test.go b/tests/compose/record_batch_test.go index 7d97d76ba..329e93685 100644 --- a/tests/compose/record_batch_test.go +++ b/tests/compose/record_batch_test.go @@ -2,21 +2,21 @@ package compose import ( "fmt" + "github.com/cortezaproject/corteza-server/compose/types" + "github.com/cortezaproject/corteza-server/tests/helpers" + "github.com/steinfletcher/apitest-jsonpath" "net/http" "strconv" "testing" - - "github.com/cortezaproject/corteza-server/compose/types" - "github.com/cortezaproject/corteza-server/tests/helpers" - jsonpath "github.com/steinfletcher/apitest-jsonpath" ) func TestRecordCreate_batch(t *testing.T) { h := newHelper(t) + h.clearRecords() - ns := h.repoMakeNamespace("batch testing namespace") - module := h.repoMakeRecordModuleWithFieldsOnNs("record testing module", ns) - childModule := h.repoMakeRecordModuleWithFieldsOnNs("record testing module child", ns) + ns := h.makeNamespace("batch testing namespace") + module := h.makeRecordModuleWithFieldsOnNs("record testing module", ns) + childModule := h.makeRecordModuleWithFieldsOnNs("record testing module child", ns) h.allow(types.ModulePermissionResource.AppendWildcard(), "record.create") h.apiInit(). @@ -33,14 +33,15 @@ func TestRecordCreate_batch(t *testing.T) { func TestRecordUpdate_batch(t *testing.T) { h := newHelper(t) + h.clearRecords() - ns := h.repoMakeNamespace("batch testing namespace") - module := h.repoMakeRecordModuleWithFieldsOnNs("record testing module", ns) - childModule := h.repoMakeRecordModuleWithFieldsOnNs("record testing module child", ns) + ns := h.makeNamespace("batch testing namespace") + module := h.makeRecordModuleWithFieldsOnNs("record testing module", ns) + childModule := h.makeRecordModuleWithFieldsOnNs("record testing module child", ns) h.allow(types.ModulePermissionResource.AppendWildcard(), "record.update") - record := h.repoMakeRecord(module) - childRecord := h.repoMakeRecord(childModule, &types.RecordValue{Name: "another_record", Value: strconv.FormatUint(record.ID, 10), Ref: record.ID}) + record := h.makeRecord(module) + childRecord := h.makeRecord(childModule, &types.RecordValue{Name: "another_record", Value: strconv.FormatUint(record.ID, 10), Ref: record.ID}) h.apiInit(). Post(fmt.Sprintf("/namespace/%d/module/%d/record/%d", module.NamespaceID, module.ID, record.ID)). @@ -56,15 +57,16 @@ func TestRecordUpdate_batch(t *testing.T) { func TestRecordDelete_batch(t *testing.T) { h := newHelper(t) + h.clearRecords() - ns := h.repoMakeNamespace("batch testing namespace") - module := h.repoMakeRecordModuleWithFieldsOnNs("record testing module", ns) - childModule := h.repoMakeRecordModuleWithFieldsOnNs("record testing module child", ns) + ns := h.makeNamespace("batch testing namespace") + module := h.makeRecordModuleWithFieldsOnNs("record testing module", ns) + childModule := h.makeRecordModuleWithFieldsOnNs("record testing module child", ns) h.allow(types.ModulePermissionResource.AppendWildcard(), "record.update") h.allow(types.ModulePermissionResource.AppendWildcard(), "record.delete") - record := h.repoMakeRecord(module) - childRecord := h.repoMakeRecord(childModule, &types.RecordValue{Name: "another_record", Value: strconv.FormatUint(record.ID, 10), Ref: record.ID}) + record := h.makeRecord(module) + childRecord := h.makeRecord(childModule, &types.RecordValue{Name: "another_record", Value: strconv.FormatUint(record.ID, 10), Ref: record.ID}) h.apiInit(). Post(fmt.Sprintf("/namespace/%d/module/%d/record/%d", module.NamespaceID, module.ID, record.ID)). @@ -77,21 +79,22 @@ func TestRecordDelete_batch(t *testing.T) { Assert(jsonpath.Equal(`$.response.records[0].recordID`, strconv.FormatUint(childRecord.ID, 10))). End() - _, err := h.repoRecord().FindByID(module.NamespaceID, childRecord.ID) - h.a.Error(err, "compose.repository.RecordNotFound") + record = h.lookupRecordByID(module, childRecord.ID) + h.a.NotNil(record.DeletedAt) } func TestRecordMixed_batch(t *testing.T) { h := newHelper(t) + h.clearRecords() - ns := h.repoMakeNamespace("batch testing namespace") - module := h.repoMakeRecordModuleWithFieldsOnNs("record testing module", ns) - childModule := h.repoMakeRecordModuleWithFieldsOnNs("record testing module child", ns) + ns := h.makeNamespace("batch testing namespace") + module := h.makeRecordModuleWithFieldsOnNs("record testing module", ns) + childModule := h.makeRecordModuleWithFieldsOnNs("record testing module child", ns) h.allow(types.ModulePermissionResource.AppendWildcard(), "record.update") h.allow(types.ModulePermissionResource.AppendWildcard(), "record.create") - record := h.repoMakeRecord(module) - childRecord := h.repoMakeRecord(childModule, &types.RecordValue{Name: "another_record", Value: strconv.FormatUint(record.ID, 10), Ref: record.ID}) + record := h.makeRecord(module) + childRecord := h.makeRecord(childModule, &types.RecordValue{Name: "another_record", Value: strconv.FormatUint(record.ID, 10), Ref: record.ID}) h.apiInit(). Post(fmt.Sprintf("/namespace/%d/module/%d/record/%d", module.NamespaceID, module.ID, record.ID)). diff --git a/tests/compose/record_exec_test.go b/tests/compose/record_exec_test.go index 60938b1e3..586bc84c7 100644 --- a/tests/compose/record_exec_test.go +++ b/tests/compose/record_exec_test.go @@ -3,22 +3,20 @@ package compose import ( "encoding/json" "fmt" - "github.com/cortezaproject/corteza-server/pkg/filter" - "net/http" - "strconv" - "testing" - - "github.com/steinfletcher/apitest" - "github.com/cortezaproject/corteza-server/compose/rest/request" "github.com/cortezaproject/corteza-server/compose/service" "github.com/cortezaproject/corteza-server/compose/types" + "github.com/cortezaproject/corteza-server/pkg/filter" "github.com/cortezaproject/corteza-server/tests/helpers" + "github.com/steinfletcher/apitest" + "net/http" + "strconv" + "testing" ) func (h helper) apiSendRecordExec(nsID, modID uint64, proc string, args []request.ProcedureArg) *apitest.Response { payload, err := json.Marshal(request.RecordExec{Args: args}) - h.a.NoError(err) + h.noError(err) return h.apiInit(). Post(fmt.Sprintf("/namespace/%d/module/%d/record/exec/%s", nsID, modID, proc)). @@ -53,7 +51,7 @@ func TestRecordExec(t *testing.T) { ) makeRecord := func(position int, handle, cat string) *types.Record { - return h.repoMakeRecord(module, + return h.makeRecord(module, &types.RecordValue{Name: "position", Value: strconv.Itoa(position)}, &types.RecordValue{Name: "handle", Value: handle}, &types.RecordValue{Name: "category", Value: cat}, @@ -69,7 +67,7 @@ func TestRecordExec(t *testing.T) { Sorting: sorting, }) - h.a.NoError(err) + h.noError(err) h.a.NotNil(set) actualHandles := "" @@ -174,9 +172,11 @@ func TestRecordExec(t *testing.T) { // ^ assertSort("icdebfagh", "312222133") - rsv, err := h.repoRecord().LoadValues([]string{"category"}, []uint64{bRec.ID}) - h.a.NoError(err) - h.a.NotNil(rsv) - h.a.Len(rsv.FilterByName("category"), 1) - h.a.Equal("CAT2", rsv.FilterByName("category")[0].Value) + lRec := h.lookupRecordByID(module, bRec.ID) + + //rsv, err := h.repoRecord().LoadValues([]string{"category"}, []uint64{bRec.ID}) + //h.noError(err) + h.a.NotNil(lRec.Values) + h.a.Len(lRec.Values.FilterByName("category"), 1) + h.a.Equal("CAT2", lRec.Values.FilterByName("category")[0].Value) } diff --git a/tests/compose/record_test.go b/tests/compose/record_test.go index 445e12694..ae6b3e4e0 100644 --- a/tests/compose/record_test.go +++ b/tests/compose/record_test.go @@ -4,20 +4,26 @@ import ( "bytes" "context" "fmt" + "github.com/cortezaproject/corteza-server/compose/service" + "github.com/cortezaproject/corteza-server/compose/types" + "github.com/cortezaproject/corteza-server/pkg/id" + "github.com/cortezaproject/corteza-server/store" + "github.com/cortezaproject/corteza-server/tests/helpers" + "github.com/steinfletcher/apitest" + "github.com/steinfletcher/apitest-jsonpath" "io/ioutil" "mime/multipart" "net/http" "testing" "time" - - "github.com/steinfletcher/apitest" - jsonpath "github.com/steinfletcher/apitest-jsonpath" - - "github.com/cortezaproject/corteza-server/compose/repository" - "github.com/cortezaproject/corteza-server/compose/types" - "github.com/cortezaproject/corteza-server/tests/helpers" ) +func (h helper) clearRecords() { + h.clearNamespaces() + h.clearModules() + h.noError(store.TruncateComposeRecords(context.Background(), service.DefaultNgStore, nil)) +} + type ( rImportSession struct { Response struct { @@ -26,11 +32,7 @@ type ( } ) -func (h helper) repoRecord() repository.RecordRepository { - return repository.Record(context.Background(), db()) -} - -func (h helper) repoMakeRecordModuleWithFieldsOnNs(name string, namespace *types.Namespace, ff ...*types.ModuleField) *types.Module { +func (h helper) makeRecordModuleWithFieldsOnNs(name string, namespace *types.Namespace, ff ...*types.ModuleField) *types.Module { h.allow(types.NamespacePermissionResource.AppendWildcard(), "read") h.allow(types.ModulePermissionResource.AppendWildcard(), "read") h.allow(types.ModulePermissionResource.AppendWildcard(), "record.read") @@ -58,11 +60,11 @@ func (h helper) repoMakeRecordModuleWithFieldsOnNs(name string, namespace *types } } - return h.repoMakeModule(namespace, name, ff...) + return h.makeModule(namespace, name, ff...) } func (h helper) repoMakeRecordModuleWithFields(name string, ff ...*types.ModuleField) *types.Module { - namespace := h.repoMakeNamespace("record testing namespace") + namespace := h.makeNamespace("record testing namespace") h.allow(types.NamespacePermissionResource.AppendWildcard(), "read") h.allow(types.ModulePermissionResource.AppendWildcard(), "read") @@ -91,32 +93,35 @@ func (h helper) repoMakeRecordModuleWithFields(name string, ff ...*types.ModuleF } } - return h.repoMakeModule(namespace, name, ff...) + return h.makeModule(namespace, name, ff...) } -func (h helper) repoMakeRecord(module *types.Module, rvs ...*types.RecordValue) *types.Record { - record, err := h. - repoRecord(). - Create(&types.Record{ - ModuleID: module.ID, - NamespaceID: module.NamespaceID, - // @todo createdAt should be auto-populated by record repo! - // (same as we do everywhere else) - CreatedAt: time.Now(), - }) - h.a.NoError(err) +func (h helper) makeRecord(module *types.Module, rvs ...*types.RecordValue) *types.Record { + rec := &types.Record{ + ID: id.Next(), + CreatedAt: time.Now(), + ModuleID: module.ID, + NamespaceID: module.NamespaceID, + Values: rvs, + } - err = h.repoRecord().UpdateValues(record.ID, rvs) - h.a.NoError(err) + h.noError(store.CreateComposeRecord(context.Background(), service.DefaultNgStore, module, rec)) - return record + return rec +} + +func (h helper) lookupRecordByID(module *types.Module, ID uint64) *types.Record { + res, err := store.LookupComposeRecordByID(context.Background(), service.DefaultNgStore, module, ID) + h.noError(err) + return res } func TestRecordRead(t *testing.T) { h := newHelper(t) + h.clearRecords() module := h.repoMakeRecordModuleWithFields("record testing module") - record := h.repoMakeRecord(module) + record := h.makeRecord(module) h.apiInit(). Get(fmt.Sprintf("/namespace/%d/module/%d/record/%d", module.NamespaceID, module.ID, record.ID)). @@ -129,11 +134,12 @@ func TestRecordRead(t *testing.T) { func TestRecordList(t *testing.T) { h := newHelper(t) + h.clearRecords() module := h.repoMakeRecordModuleWithFields("record testing module") - h.repoMakeRecord(module) - h.repoMakeRecord(module) + h.makeRecord(module) + h.makeRecord(module) h.apiInit(). Get(fmt.Sprintf("/namespace/%d/module/%d/record/", module.NamespaceID, module.ID)). @@ -145,6 +151,7 @@ func TestRecordList(t *testing.T) { func TestRecordCreateForbidden(t *testing.T) { h := newHelper(t) + h.clearRecords() module := h.repoMakeRecordModuleWithFields("record testing module") @@ -159,6 +166,7 @@ func TestRecordCreateForbidden(t *testing.T) { func TestRecordCreate(t *testing.T) { h := newHelper(t) + h.clearRecords() module := h.repoMakeRecordModuleWithFields("record testing module") h.allow(types.ModulePermissionResource.AppendWildcard(), "record.create") @@ -174,12 +182,15 @@ func TestRecordCreate(t *testing.T) { func TestRecordCreateWithErrors(t *testing.T) { h := newHelper(t) + h.clearRecords() fields := types.ModuleFieldSet{ &types.ModuleField{ + ID: id.Next(), Name: "name", }, &types.ModuleField{ + ID: id.Next(), Name: "required", Required: true, }, @@ -203,9 +214,10 @@ func TestRecordCreateWithErrors(t *testing.T) { func TestRecordUpdateForbidden(t *testing.T) { h := newHelper(t) + h.clearRecords() module := h.repoMakeRecordModuleWithFields("record testing module") - record := h.repoMakeRecord(module) + record := h.makeRecord(module) h.apiInit(). Post(fmt.Sprintf("/namespace/%d/module/%d/record/%d", module.NamespaceID, module.ID, record.ID)). @@ -218,9 +230,10 @@ func TestRecordUpdateForbidden(t *testing.T) { func TestRecordUpdate(t *testing.T) { h := newHelper(t) + h.clearRecords() module := h.repoMakeRecordModuleWithFields("record testing module") - record := h.repoMakeRecord(module) + record := h.makeRecord(module) h.allow(types.ModulePermissionResource.AppendWildcard(), "record.update") h.apiInit(). @@ -231,17 +244,16 @@ func TestRecordUpdate(t *testing.T) { Assert(helpers.AssertNoErrors). End() - r, err := h.repoRecord().FindByID(module.NamespaceID, record.ID) - h.a.NoError(err) + r := h.lookupRecordByID(module, record.ID) h.a.NotNil(r) - // h.a.Equal(5, r.OwnedBy) } func TestRecordDeleteForbidden(t *testing.T) { h := newHelper(t) + h.clearRecords() module := h.repoMakeRecordModuleWithFields("record testing module") - record := h.repoMakeRecord(module) + record := h.makeRecord(module) h.apiInit(). Delete(fmt.Sprintf("/namespace/%d/module/%d/record/%d", module.NamespaceID, module.ID, record.ID)). @@ -253,9 +265,10 @@ func TestRecordDeleteForbidden(t *testing.T) { func TestRecordDelete(t *testing.T) { h := newHelper(t) + h.clearRecords() module := h.repoMakeRecordModuleWithFields("record testing module") - record := h.repoMakeRecord(module) + record := h.makeRecord(module) h.allow(types.ModulePermissionResource.AppendWildcard(), "record.delete") @@ -266,16 +279,17 @@ func TestRecordDelete(t *testing.T) { Assert(helpers.AssertNoErrors). End() - _, err := h.repoRecord().FindByID(module.NamespaceID, record.ID) - h.a.Error(err, "record does not exist") + r := h.lookupRecordByID(module, record.ID) + h.a.NotNil(r.DeletedAt) } func TestRecordExport(t *testing.T) { h := newHelper(t) + h.clearRecords() module := h.repoMakeRecordModuleWithFields("record export module") for i := 0; i < 10; i++ { - h.repoMakeRecord(module, &types.RecordValue{Name: "name", Value: fmt.Sprintf("d%d", i)}) + h.makeRecord(module, &types.RecordValue{Name: "name", Value: fmt.Sprintf("d%d", i), Place: uint(i)}) } // we'll not use standard asserts (AssertNoErrors) here, @@ -288,7 +302,7 @@ func TestRecordExport(t *testing.T) { End() b, err := ioutil.ReadAll(r.Response.Body) - h.a.NoError(err) + h.noError(err) h.a.Equal("name\nd0\nd1\nd2\nd3\nd4\nd5\nd6\nd7\nd8\nd9\n", string(b)) } @@ -296,11 +310,11 @@ func (h helper) apiInitRecordImport(api *apitest.APITest, url, f string, file [] body := &bytes.Buffer{} writer := multipart.NewWriter(body) part, err := writer.CreateFormFile("upload", f) - h.a.NoError(err) + h.noError(err) _, err = part.Write(file) - h.a.NoError(err) - h.a.NoError(writer.Close()) + h.noError(err) + h.noError(writer.Close()) return api. Post(url). @@ -320,6 +334,7 @@ func (h helper) apiRunRecordImport(api *apitest.APITest, url, b string) *apitest func TestRecordImportInit(t *testing.T) { h := newHelper(t) + h.clearRecords() module := h.repoMakeRecordModuleWithFields("record import init module") tests := []struct { @@ -352,6 +367,7 @@ func TestRecordImportInit(t *testing.T) { func TestRecordImportInit_invalidFileFormat(t *testing.T) { h := newHelper(t) + h.clearRecords() module := h.repoMakeRecordModuleWithFields("record import init module") url := fmt.Sprintf("/namespace/%d/module/%d/record/import", module.NamespaceID, module.ID) @@ -362,6 +378,7 @@ func TestRecordImportInit_invalidFileFormat(t *testing.T) { func TestRecordImportRun(t *testing.T) { h := newHelper(t) + h.clearRecords() module := h.repoMakeRecordModuleWithFields("record import run module") tests := []struct { @@ -395,6 +412,7 @@ func TestRecordImportRun(t *testing.T) { func TestRecordImportRun_sessionNotFound(t *testing.T) { h := newHelper(t) + h.clearRecords() module := h.repoMakeRecordModuleWithFields("record import run module") h.apiRunRecordImport(h.apiInit(), fmt.Sprintf("/namespace/%d/module/%d/record/import/123", module.NamespaceID, module.ID), `{"fields":{"fname":"name","femail":"email"},"onError":"fail"}`). @@ -404,6 +422,7 @@ func TestRecordImportRun_sessionNotFound(t *testing.T) { func TestRecordImportImportProgress(t *testing.T) { h := newHelper(t) + h.clearRecords() module := h.repoMakeRecordModuleWithFields("record import session module") tests := []struct { @@ -437,6 +456,7 @@ func TestRecordImportImportProgress(t *testing.T) { func TestRecordImportImportProgress_sessionNotFound(t *testing.T) { h := newHelper(t) + h.clearRecords() module := h.repoMakeRecordModuleWithFields("record import module") h.apiInit(). @@ -449,8 +469,9 @@ func TestRecordImportImportProgress_sessionNotFound(t *testing.T) { func TestRecordFieldModulePermissionCheck(t *testing.T) { h := newHelper(t) + h.clearRecords() - // make a standad module, and prevent current user to + // make a standard module, and prevent current user to // read from "name" and update "email" fields module := h.repoMakeRecordModuleWithFields("record testing module") h.deny(module.Fields.FindByName("name").PermissionResource(), "record.value.read") @@ -458,7 +479,7 @@ func TestRecordFieldModulePermissionCheck(t *testing.T) { h.allow(types.ModulePermissionResource.AppendWildcard(), "record.create") h.allow(types.ModulePermissionResource.AppendWildcard(), "record.update") - record := h.repoMakeRecord( + record := h.makeRecord( module, &types.RecordValue{Name: "name", Value: "should not be readable"}, &types.RecordValue{Name: "email", Value: "should not be writable"}, @@ -476,6 +497,18 @@ func TestRecordFieldModulePermissionCheck(t *testing.T) { Assert(jsonpath.Present(`$.response.values[? @.name=="email"]`)). End() + // Searching records should work as before but without read-protected fields + h.apiInit(). + Get(fmt.Sprintf("/namespace/%d/module/%d/record/", module.NamespaceID, module.ID)). + Expect(t). + Status(http.StatusOK). + Assert(helpers.AssertNoErrors). + // should not return name + Assert(jsonpath.NotPresent(`$.response.set[0].values[? @.name=="name"]`)). + // should return email + Assert(jsonpath.Present(`$.response.set[0].values[? @.name=="email"]`)). + End() + bb := map[string]func() *apitest.Request{ "update": func() *apitest.Request { return h.apiInit(). diff --git a/tests/helpers/app.go b/tests/helpers/app.go index 75b66c22e..cccb7d23b 100644 --- a/tests/helpers/app.go +++ b/tests/helpers/app.go @@ -6,11 +6,19 @@ import ( "github.com/cortezaproject/corteza-server/pkg/cli" "github.com/cortezaproject/corteza-server/pkg/logger" "github.com/cortezaproject/corteza-server/pkg/rand" + "github.com/cortezaproject/corteza-server/store/sqlite" "time" ) func NewIntegrationTestApp(ctx context.Context, initTestServices func(*app.CortezaApp) error) *app.CortezaApp { - a := app.New() + var ( + a = app.New() + err error + ) + + // Make sure SQLite is registered + a.Store, err = sqlite.ConnectInMemory(ctx) + cli.HandleError(err) // When running integration tests, we want to upgrade the db. Always. a.Opt.Upgrade.Always = true diff --git a/tests/messaging/channel_update_test.go b/tests/messaging/channel_update_test.go index 73185f2f4..52054eb4d 100644 --- a/tests/messaging/channel_update_test.go +++ b/tests/messaging/channel_update_test.go @@ -3,17 +3,15 @@ package messaging import ( "encoding/json" "fmt" + "github.com/cortezaproject/corteza-server/messaging/rest/request" + "github.com/cortezaproject/corteza-server/messaging/types" + "github.com/cortezaproject/corteza-server/pkg/id" + "github.com/cortezaproject/corteza-server/tests/helpers" + "github.com/steinfletcher/apitest" + "github.com/steinfletcher/apitest-jsonpath" "net/http" "strconv" "testing" - - "github.com/steinfletcher/apitest" - jsonpath "github.com/steinfletcher/apitest-jsonpath" - "github.com/titpetric/factory" - - "github.com/cortezaproject/corteza-server/messaging/rest/request" - "github.com/cortezaproject/corteza-server/messaging/types" - "github.com/cortezaproject/corteza-server/tests/helpers" ) func (h helper) chUpdate(ch *request.ChannelUpdate) *apitest.Response { diff --git a/tests/messaging/main_test.go b/tests/messaging/main_test.go index 6ca5d01c4..e288b3e48 100644 --- a/tests/messaging/main_test.go +++ b/tests/messaging/main_test.go @@ -10,6 +10,7 @@ import ( "github.com/cortezaproject/corteza-server/pkg/auth" "github.com/cortezaproject/corteza-server/pkg/cli" "github.com/cortezaproject/corteza-server/pkg/eventbus" + "github.com/cortezaproject/corteza-server/pkg/id" "github.com/cortezaproject/corteza-server/pkg/logger" "github.com/cortezaproject/corteza-server/pkg/permissions" "github.com/cortezaproject/corteza-server/pkg/store/plain" @@ -55,7 +56,7 @@ func InitTestApp() { ctx := cli.Context() testApp = helpers.NewIntegrationTestApp(ctx, func(app *app.CortezaApp) (err error) { - service.DefaultPermissions = permissions.NewTestService(ctx, zap.NewNop(), app.Store.(rbacRulesStore)) + service.DefaultPermissions = permissions.NewTestService(ctx, zap.NewNop(), app.Store) service.DefaultStore, err = plain.NewWithAfero(afero.NewMemMapFs(), "test") if err != nil { return err diff --git a/tests/system/application_test.go b/tests/system/application_test.go index 9a3caa15e..382096be2 100644 --- a/tests/system/application_test.go +++ b/tests/system/application_test.go @@ -1,4 +1,5 @@ -//package system +package system + // //import ( // "context" diff --git a/tests/system/main_test.go b/tests/system/main_test.go index 29808d1be..6585f6001 100644 --- a/tests/system/main_test.go +++ b/tests/system/main_test.go @@ -7,6 +7,7 @@ import ( "github.com/cortezaproject/corteza-server/pkg/auth" "github.com/cortezaproject/corteza-server/pkg/cli" "github.com/cortezaproject/corteza-server/pkg/eventbus" + "github.com/cortezaproject/corteza-server/pkg/id" "github.com/cortezaproject/corteza-server/pkg/logger" "github.com/cortezaproject/corteza-server/pkg/permissions" "github.com/cortezaproject/corteza-server/pkg/rand" @@ -21,7 +22,6 @@ import ( "github.com/spf13/afero" "github.com/steinfletcher/apitest" "github.com/stretchr/testify/require" - "github.com/titpetric/factory" "go.uber.org/zap" "os" "testing" @@ -58,22 +58,18 @@ func rs(a ...int) string { return string(rand.Bytes(l)) } -func db() *factory.DB { - return factory.Database.MustGet().With(context.Background()) -} - func InitTestApp() { if testApp == nil { ctx := cli.Context() testApp = helpers.NewIntegrationTestApp(ctx, func(app *app.CortezaApp) (err error) { - service.DefaultPermissions = permissions.NewTestService(ctx, zap.NewNop(), app.Store.(rbacRulesStore)) + service.DefaultPermissions = permissions.NewTestService(ctx, zap.NewNop(), app.Store) service.DefaultStore, err = plain.NewWithAfero(afero.NewMemMapFs(), "test") if err != nil { return err } - service.DefaultNgStore, err = sqlite.NewInMemory(ctx) + service.DefaultNgStore, err = sqlite.ConnectInMemory(ctx) if err != nil { return err }