Better record value sanitization, refactor & split tests
This commit is contained in:
parent
0d299e0f32
commit
59a5df253f
@ -1,8 +1,7 @@
|
||||
package repository
|
||||
|
||||
/*
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@ -10,17 +9,11 @@ import (
|
||||
"github.com/cortezaproject/corteza-server/internal/test"
|
||||
)
|
||||
|
||||
*/
|
||||
|
||||
// This test is a moving target, it doesn't do any good to
|
||||
// test the generated sql query, as you'd need an integration
|
||||
// test to verify that it works correctly.
|
||||
|
||||
/*
|
||||
func TestRecordFinder(t *testing.T) {
|
||||
r := record{}
|
||||
m := &types.Module{
|
||||
ID: 123,
|
||||
ID: 123,
|
||||
NamespaceID: 456,
|
||||
Fields: types.ModuleFieldSet{
|
||||
&types.ModuleField{Name: "foo"},
|
||||
&types.ModuleField{Name: "bar"},
|
||||
@ -28,30 +21,40 @@ func TestRecordFinder(t *testing.T) {
|
||||
}
|
||||
|
||||
ttc := []struct {
|
||||
filter string
|
||||
sort string
|
||||
match []string
|
||||
args []interface{}
|
||||
f types.RecordFilter
|
||||
match []string
|
||||
args []interface{}
|
||||
err error
|
||||
}{
|
||||
{
|
||||
match: []string{"SELECT * FROM crm_record AS r WHERE r.module_id = ? AND r.deleted_at IS NULL"},
|
||||
args: []interface{}{123}},
|
||||
match: []string{"SELECT * FROM compose_record AS r WHERE r.deleted_at IS NULL AND r.module_id = ?"},
|
||||
},
|
||||
{
|
||||
filter: "id = 5 AND foo = 7",
|
||||
f: types.RecordFilter{Filter: "id = 5 AND foo = 7"},
|
||||
match: []string{
|
||||
" AND id = 5",
|
||||
" AND (SELECT value FROM crm_record_value WHERE name = ? AND record_id = crm_record.id AND deleted_at IS NULL) = 7"},
|
||||
args: []interface{}{123}},
|
||||
"id = 5",
|
||||
"rv_foo.value = 7"},
|
||||
args: []interface{}{"foo"},
|
||||
},
|
||||
{
|
||||
sort: "id ASC, foo DESC",
|
||||
f: types.RecordFilter{Sort: "id ASC, bar DESC"},
|
||||
match: []string{
|
||||
" id ASC, (SELECT value FROM crm_record_value WHERE name = 'foo' AND record_id = crm_record.id AND deleted_at IS NULL) DESC"},
|
||||
args: []interface{}{123}},
|
||||
" id ASC",
|
||||
" rv_bar.value DESC",
|
||||
},
|
||||
args: []interface{}{"bar"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range ttc {
|
||||
sb, err := r.buildQuery(m, tc.filter, tc.sort)
|
||||
test.Assert(t, err == nil, "buildQuery(%q, %q) returned an error: %v", tc.filter, tc.sort, err)
|
||||
sb, err := r.buildQuery(m, tc.f)
|
||||
|
||||
if tc.err != nil {
|
||||
test.Assert(t, tc.err.Error() == fmt.Sprintf("%v", err), "buildQuery(%+v) did not return an expected error %q but %q", tc.f, tc.err, err)
|
||||
} else {
|
||||
test.Assert(t, err == nil, "buildQuery(%+v) returned an unexpected error: %v", tc.f, err)
|
||||
}
|
||||
|
||||
sb = sb.Column("*")
|
||||
sql, args, err := sb.ToSql()
|
||||
|
||||
@ -61,10 +64,9 @@ func TestRecordFinder(t *testing.T) {
|
||||
" did not contain %q", sql, m)
|
||||
}
|
||||
|
||||
_ = args
|
||||
// test.Assert(t, reflect.DeepEqual(args, tc.args),
|
||||
// "assertion failed; args %v \n "+
|
||||
// " do not match expected %v", args, tc.args)
|
||||
tc.args = append(tc.args, m.ID, m.NamespaceID)
|
||||
test.Assert(t, fmt.Sprintf("%+v", args) == fmt.Sprintf("%+v", tc.args),
|
||||
"assertion failed; args %+v \n "+
|
||||
" do not match expected %+v", args, tc.args)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
@ -2,6 +2,7 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
@ -161,7 +162,7 @@ func (svc record) Create(mod *types.Record) (r *types.Record, err error) {
|
||||
return nil, ErrNoCreatePermissions.withStack()
|
||||
}
|
||||
|
||||
if err = svc.sanitizeValues(m, mod.Values); err != nil {
|
||||
if mod.Values, err = svc.sanitizeValues(m, mod.Values); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@ -212,7 +213,7 @@ func (svc record) Update(mod *types.Record) (r *types.Record, err error) {
|
||||
return nil, ErrStaleData.withStack()
|
||||
}
|
||||
|
||||
if err = svc.sanitizeValues(m, mod.Values); err != nil {
|
||||
if mod.Values, err = svc.sanitizeValues(m, mod.Values); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@ -268,7 +269,7 @@ func (svc record) DeleteByID(namespaceID, recordID uint64) (err error) {
|
||||
}
|
||||
|
||||
// Validates and filters record values
|
||||
func (svc record) sanitizeValues(module *types.Module, values types.RecordValueSet) (err error) {
|
||||
func (svc record) sanitizeValues(module *types.Module, values types.RecordValueSet) (out types.RecordValueSet, err error) {
|
||||
// Make sure there are no multi values in a non-multi value fields
|
||||
err = module.Fields.Walk(func(field *types.ModuleField) error {
|
||||
if !field.Multi && len(values.FilterByName(field.Name)) > 1 {
|
||||
@ -282,12 +283,17 @@ func (svc record) sanitizeValues(module *types.Module, values types.RecordValueS
|
||||
}
|
||||
|
||||
// Remove all values on un-updatable fields
|
||||
values, err = values.Filter(func(v *types.RecordValue) (bool, error) {
|
||||
out, err = values.Filter(func(v *types.RecordValue) (bool, error) {
|
||||
var field = module.Fields.FindByName(v.Name)
|
||||
if field == nil {
|
||||
return false, errors.Errorf("no such field %q", v.Name)
|
||||
}
|
||||
|
||||
if field.IsRef() && v.Value == "" {
|
||||
// Skip empty values on ref fields
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return svc.ac.CanUpdateRecordValue(svc.ctx, field), nil
|
||||
})
|
||||
|
||||
@ -295,15 +301,22 @@ func (svc record) sanitizeValues(module *types.Module, values types.RecordValueS
|
||||
return
|
||||
}
|
||||
|
||||
var places = map[string]uint{}
|
||||
var (
|
||||
places = map[string]uint{}
|
||||
numeric = regexp.MustCompile(`^(\d+)$`)
|
||||
)
|
||||
|
||||
return values.Walk(func(value *types.RecordValue) (err error) {
|
||||
return out, out.Walk(func(value *types.RecordValue) (err error) {
|
||||
var field = module.Fields.FindByName(value.Name)
|
||||
if field == nil {
|
||||
return errors.Errorf("no such field %q", value.Name)
|
||||
}
|
||||
|
||||
if field.IsRef() {
|
||||
if !numeric.MatchString(value.Value) {
|
||||
return errors.Errorf("invalid reference format")
|
||||
}
|
||||
|
||||
if value.Ref, err = strconv.ParseUint(value.Value, 10, 64); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
253
compose/internal/service/record_integration_test.go
Normal file
253
compose/internal/service/record_integration_test.go
Normal file
@ -0,0 +1,253 @@
|
||||
// +build integration
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/titpetric/factory"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/compose/types"
|
||||
"github.com/cortezaproject/corteza-server/internal/auth"
|
||||
"github.com/cortezaproject/corteza-server/internal/permissions"
|
||||
"github.com/cortezaproject/corteza-server/internal/test"
|
||||
)
|
||||
|
||||
func TestRecord(t *testing.T) {
|
||||
factory.Database.MustGet("compose").Profiler = newTestLogProfiler(t)
|
||||
|
||||
ctx := context.WithValue(context.Background(), "testing", true)
|
||||
|
||||
ctx = auth.SetIdentityToContext(ctx, auth.NewIdentity(1337))
|
||||
|
||||
var err error
|
||||
ns1, ns2 := createTestNamespaces(ctx, t)
|
||||
|
||||
moduleSvc := Module().With(ctx)
|
||||
svc := Record().With(ctx)
|
||||
svc.(*record).ac = AccessControl(&permissions.ServiceAllowAll{})
|
||||
|
||||
module1 := &types.Module{
|
||||
NamespaceID: ns1.ID,
|
||||
Name: "Test",
|
||||
Fields: types.ModuleFieldSet{
|
||||
&types.ModuleField{
|
||||
Name: "name",
|
||||
},
|
||||
&types.ModuleField{
|
||||
Name: "email",
|
||||
},
|
||||
&types.ModuleField{
|
||||
Name: "options",
|
||||
Multi: true,
|
||||
},
|
||||
&types.ModuleField{
|
||||
Name: "description",
|
||||
},
|
||||
&types.ModuleField{
|
||||
Name: "another_record",
|
||||
Kind: "Record",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// set up a module1
|
||||
module1, err = moduleSvc.Create(module1)
|
||||
test.Assert(t, err == nil, "Error when creating module1: %+v", err)
|
||||
test.Assert(t, module1.ID > 0, "Expected auto generated ID")
|
||||
|
||||
module2 := &types.Module{
|
||||
NamespaceID: ns2.ID,
|
||||
Name: "Test Dummy",
|
||||
Fields: types.ModuleFieldSet{
|
||||
&types.ModuleField{
|
||||
Name: "name",
|
||||
},
|
||||
&types.ModuleField{
|
||||
Name: "email",
|
||||
},
|
||||
&types.ModuleField{
|
||||
Name: "options",
|
||||
Multi: true,
|
||||
},
|
||||
&types.ModuleField{
|
||||
Name: "description",
|
||||
},
|
||||
&types.ModuleField{
|
||||
Name: "another_record",
|
||||
Kind: "Record",
|
||||
},
|
||||
},
|
||||
}
|
||||
module2, err = moduleSvc.Create(module2)
|
||||
test.Assert(t, err == nil, "Error when creating module1 in another namespace: %+v", err)
|
||||
|
||||
record1 := &types.Record{
|
||||
NamespaceID: ns1.ID,
|
||||
ModuleID: module1.ID,
|
||||
}
|
||||
|
||||
record2 := &types.Record{
|
||||
NamespaceID: ns1.ID,
|
||||
ModuleID: module1.ID,
|
||||
Values: types.RecordValueSet{
|
||||
&types.RecordValue{
|
||||
Name: "name",
|
||||
Value: "John Doe",
|
||||
},
|
||||
&types.RecordValue{
|
||||
Name: "email",
|
||||
Value: "john.doe@example.com",
|
||||
},
|
||||
&types.RecordValue{
|
||||
Name: "options",
|
||||
Value: "1",
|
||||
},
|
||||
&types.RecordValue{
|
||||
Name: "options",
|
||||
Value: "2",
|
||||
},
|
||||
&types.RecordValue{
|
||||
Name: "options",
|
||||
Value: "3",
|
||||
},
|
||||
&types.RecordValue{
|
||||
Name: "description",
|
||||
Value: "just an example",
|
||||
},
|
||||
&types.RecordValue{
|
||||
Name: "another_record",
|
||||
Value: "918273645",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
{
|
||||
// Let's put something to another namespace...
|
||||
_, err := svc.Create(&types.Record{
|
||||
NamespaceID: ns2.ID,
|
||||
ModuleID: module2.ID,
|
||||
})
|
||||
test.Assert(t, err == nil, "Error when creating record: %+v", err)
|
||||
}
|
||||
|
||||
// now work with records
|
||||
{
|
||||
{
|
||||
record1.UpdatedAt = nil
|
||||
m, err := svc.Update(record1)
|
||||
test.Assert(t, m == nil, "Expected empty return for invalid update, got %#v", m)
|
||||
test.Assert(t, err != nil, "Expected error when updating invalid record")
|
||||
}
|
||||
|
||||
// create record
|
||||
m1, err := svc.Create(record1)
|
||||
test.Assert(t, err == nil, "Error when creating record: %+v", err)
|
||||
test.Assert(t, m1.ID > 0, "Expected auto generated ID")
|
||||
|
||||
// create record
|
||||
m2, err := svc.Create(record2)
|
||||
test.Assert(t, err == nil, "Error when creating record: %+v", err)
|
||||
test.Assert(t, m2.ID > 0, "Expected auto generated ID")
|
||||
|
||||
// fetch created record
|
||||
{
|
||||
ms, err := svc.FindByID(m1.NamespaceID, m1.ID)
|
||||
test.Assert(t, err == nil, "Error when retrieving record by id: %+v", err)
|
||||
test.Assert(t, ms.ID == m1.ID, "Expected ID from database to match, %d != %d", m1.ID, ms.ID)
|
||||
test.Assert(t, ms.ModuleID == m1.ModuleID, "Expected Module ID from database to match, %d != %d", m1.ModuleID, ms.ModuleID)
|
||||
}
|
||||
|
||||
// update created record
|
||||
{
|
||||
m1.UpdatedAt = nil
|
||||
_, err := svc.Update(m1)
|
||||
test.Assert(t, err == nil, "Error when updating record, %+v", err)
|
||||
}
|
||||
|
||||
// re-fetch record
|
||||
{
|
||||
ms, err := svc.FindByID(m1.NamespaceID, m1.ID)
|
||||
test.Assert(t, err == nil, "Error when retrieving record by id: %+v", err)
|
||||
test.Assert(t, ms.ID == m1.ID, "Expected ID from database to match, %d != %d", m1.ID, ms.ID)
|
||||
test.Assert(t, ms.ModuleID == m1.ModuleID, "Expected ID from database to match, %d != %d", m1.ModuleID, ms.ModuleID)
|
||||
}
|
||||
|
||||
// fetch all records
|
||||
{
|
||||
mr, f, err := svc.Find(types.RecordFilter{ModuleID: module1.ID, Sort: "id desc"})
|
||||
test.Assert(t, err == nil, "Error when retrieving records: %+v", err)
|
||||
test.Assert(t, len(mr) == 2, "Expected two record, got %d", len(mr))
|
||||
test.Assert(t, f.Count == 2, "Expected Meta.Count == 2, got %d", f.Count)
|
||||
test.Assert(t, f.Sort == "id desc", "Expected Meta.Sort == id desc, got '%s'", f.Sort)
|
||||
test.Assert(t, mr[0].ModuleID == m1.ModuleID, "Expected record module1 to match, %d != %d", m1.ModuleID, mr[0].ModuleID)
|
||||
test.Assert(t, mr[0].ID > mr[1].ID, "Expected order to be descending")
|
||||
}
|
||||
|
||||
// fetch all records
|
||||
{
|
||||
|
||||
mr, f, err := svc.Find(types.RecordFilter{ModuleID: module1.ID, Sort: "name asc, email desc"})
|
||||
test.Assert(t, err == nil, "Error when retrieving records: %+v", err)
|
||||
test.Assert(t, len(mr) == 2, "Expected two record, got %d", len(mr))
|
||||
test.Assert(t, f.Count == 2, "Expected Meta.Count == 2, got %d", f.Count)
|
||||
test.Assert(t, f.Sort == "name asc, email desc", "Expected Meta.Sort == 'name asc, email desc' '%s'", f.Sort)
|
||||
test.Assert(t, mr[0].ModuleID == m1.ModuleID, "Expected record module1 to match, %d != %d", m1.ModuleID, mr[0].ModuleID)
|
||||
|
||||
// @todo sort is not stable
|
||||
// test.Assert(t, mr[0].ID > mr[1].ID, "Expected order to be ascending")
|
||||
}
|
||||
|
||||
// fetch all records
|
||||
{
|
||||
mr, f, err := svc.Find(types.RecordFilter{ModuleID: module1.ID, Sort: "created_at desc"})
|
||||
test.Assert(t, err == nil, "Error when retrieving records: %+v", err)
|
||||
test.Assert(t, len(mr) == 2, "Expected two record, got %d", len(mr))
|
||||
test.Assert(t, f.Count == 2, "Expected Meta.Count == 2, got %d", f.Count)
|
||||
test.Assert(t, f.Sort == "created_at desc", "Expected Meta.Sort == created_at desc, got '%s'", f.Sort)
|
||||
test.Assert(t, mr[0].ModuleID == m1.ModuleID, "Expected record module1 to match, %d != %d", m1.ModuleID, mr[0].ModuleID)
|
||||
|
||||
// @todo sort is not stable
|
||||
// test.Assert(t, mr[0].ID > mr[1].ID, "Expected order to be ascending")
|
||||
}
|
||||
|
||||
// fetch all records by query
|
||||
{
|
||||
filter := "name='John Doe' AND email='john.doe@example.com'"
|
||||
sort := "id desc"
|
||||
|
||||
mr, f, err := svc.Find(types.RecordFilter{ModuleID: module1.ID, Sort: sort, Filter: filter})
|
||||
test.Assert(t, err == nil, "Error when retrieving records: %+v", err)
|
||||
test.Assert(t, len(mr) == 1, "Expected one record, got %d", len(mr))
|
||||
test.Assert(t, f.Count == 1, "Expected Meta.Count == 1, got %d", f.Count)
|
||||
test.Assert(t, f.Page == 0, "Expected Meta.Page == 0, got %d", f.Page)
|
||||
test.Assert(t, f.PerPage == 50, "Expected Meta.PerPage == 50, got %d", f.PerPage)
|
||||
test.Assert(t, f.Filter == filter, "Expected Meta.Filter == %q, got %q", filter, f.Filter)
|
||||
test.Assert(t, f.Sort == sort, "Expected Meta.Sort == %q, got %q", sort, f.Sort)
|
||||
}
|
||||
|
||||
// fetch all records by query
|
||||
{
|
||||
mr, _, err := svc.Find(types.RecordFilter{ModuleID: module1.ID, Sort: "id asc", Filter: "name='niall'"})
|
||||
test.Assert(t, err == nil, "Error when retrieving records: %+v", err)
|
||||
test.Assert(t, len(mr) == 0, "Expected no records, got %d", len(mr))
|
||||
}
|
||||
|
||||
// delete record
|
||||
{
|
||||
err := svc.DeleteByID(m1.NamespaceID, m1.ID)
|
||||
test.Assert(t, err == nil, "Error when retrieving record by id: %+v", err)
|
||||
|
||||
err = svc.DeleteByID(m2.NamespaceID, m2.ID)
|
||||
test.Assert(t, err == nil, "Error when retrieving record by id: %+v", err)
|
||||
}
|
||||
|
||||
// fetch all records
|
||||
{
|
||||
mr, _, err := svc.Find(types.RecordFilter{ModuleID: module1.ID})
|
||||
test.Assert(t, err == nil, "Error when retrieving records: %+v", err)
|
||||
test.Assert(t, len(mr) == 0, "Expected no record, got %d", len(mr))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,257 +1,13 @@
|
||||
// +build integration
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/titpetric/factory"
|
||||
|
||||
"github.com/cortezaproject/corteza-server/compose/types"
|
||||
"github.com/cortezaproject/corteza-server/internal/auth"
|
||||
"github.com/cortezaproject/corteza-server/internal/permissions"
|
||||
"github.com/cortezaproject/corteza-server/internal/test"
|
||||
)
|
||||
|
||||
func TestRecord(t *testing.T) {
|
||||
factory.Database.MustGet("compose").Profiler = newTestLogProfiler(t)
|
||||
|
||||
ctx := context.WithValue(context.Background(), "testing", true)
|
||||
|
||||
ctx = auth.SetIdentityToContext(ctx, auth.NewIdentity(1337))
|
||||
|
||||
var err error
|
||||
ns1, ns2 := createTestNamespaces(ctx, t)
|
||||
|
||||
moduleSvc := Module().With(ctx)
|
||||
svc := Record().With(ctx)
|
||||
svc.(*record).ac = AccessControl(&permissions.ServiceAllowAll{})
|
||||
|
||||
module1 := &types.Module{
|
||||
NamespaceID: ns1.ID,
|
||||
Name: "Test",
|
||||
Fields: types.ModuleFieldSet{
|
||||
&types.ModuleField{
|
||||
Name: "name",
|
||||
},
|
||||
&types.ModuleField{
|
||||
Name: "email",
|
||||
},
|
||||
&types.ModuleField{
|
||||
Name: "options",
|
||||
Multi: true,
|
||||
},
|
||||
&types.ModuleField{
|
||||
Name: "description",
|
||||
},
|
||||
&types.ModuleField{
|
||||
Name: "another_record",
|
||||
Kind: "Record",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// set up a module1
|
||||
module1, err = moduleSvc.Create(module1)
|
||||
test.Assert(t, err == nil, "Error when creating module1: %+v", err)
|
||||
test.Assert(t, module1.ID > 0, "Expected auto generated ID")
|
||||
|
||||
module2 := &types.Module{
|
||||
NamespaceID: ns2.ID,
|
||||
Name: "Test Dummy",
|
||||
Fields: types.ModuleFieldSet{
|
||||
&types.ModuleField{
|
||||
Name: "name",
|
||||
},
|
||||
&types.ModuleField{
|
||||
Name: "email",
|
||||
},
|
||||
&types.ModuleField{
|
||||
Name: "options",
|
||||
Multi: true,
|
||||
},
|
||||
&types.ModuleField{
|
||||
Name: "description",
|
||||
},
|
||||
&types.ModuleField{
|
||||
Name: "another_record",
|
||||
Kind: "Record",
|
||||
},
|
||||
},
|
||||
}
|
||||
module2, err = moduleSvc.Create(module2)
|
||||
test.Assert(t, err == nil, "Error when creating module1 in another namespace: %+v", err)
|
||||
|
||||
record1 := &types.Record{
|
||||
NamespaceID: ns1.ID,
|
||||
ModuleID: module1.ID,
|
||||
}
|
||||
|
||||
record2 := &types.Record{
|
||||
NamespaceID: ns1.ID,
|
||||
ModuleID: module1.ID,
|
||||
Values: types.RecordValueSet{
|
||||
&types.RecordValue{
|
||||
Name: "name",
|
||||
Value: "John Doe",
|
||||
},
|
||||
&types.RecordValue{
|
||||
Name: "email",
|
||||
Value: "john.doe@example.com",
|
||||
},
|
||||
&types.RecordValue{
|
||||
Name: "options",
|
||||
Value: "1",
|
||||
},
|
||||
&types.RecordValue{
|
||||
Name: "options",
|
||||
Value: "2",
|
||||
},
|
||||
&types.RecordValue{
|
||||
Name: "options",
|
||||
Value: "3",
|
||||
},
|
||||
&types.RecordValue{
|
||||
Name: "description",
|
||||
Value: "just an example",
|
||||
},
|
||||
&types.RecordValue{
|
||||
Name: "another_record",
|
||||
Value: "918273645",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
{
|
||||
// Let's put something to another namespace...
|
||||
_, err := svc.Create(&types.Record{
|
||||
NamespaceID: ns2.ID,
|
||||
ModuleID: module2.ID,
|
||||
})
|
||||
test.Assert(t, err == nil, "Error when creating record: %+v", err)
|
||||
}
|
||||
|
||||
// now work with records
|
||||
{
|
||||
{
|
||||
record1.UpdatedAt = nil
|
||||
m, err := svc.Update(record1)
|
||||
test.Assert(t, m == nil, "Expected empty return for invalid update, got %#v", m)
|
||||
test.Assert(t, err != nil, "Expected error when updating invalid record")
|
||||
}
|
||||
|
||||
// create record
|
||||
m1, err := svc.Create(record1)
|
||||
test.Assert(t, err == nil, "Error when creating record: %+v", err)
|
||||
test.Assert(t, m1.ID > 0, "Expected auto generated ID")
|
||||
|
||||
// create record
|
||||
m2, err := svc.Create(record2)
|
||||
test.Assert(t, err == nil, "Error when creating record: %+v", err)
|
||||
test.Assert(t, m2.ID > 0, "Expected auto generated ID")
|
||||
|
||||
// fetch created record
|
||||
{
|
||||
ms, err := svc.FindByID(m1.NamespaceID, m1.ID)
|
||||
test.Assert(t, err == nil, "Error when retrieving record by id: %+v", err)
|
||||
test.Assert(t, ms.ID == m1.ID, "Expected ID from database to match, %d != %d", m1.ID, ms.ID)
|
||||
test.Assert(t, ms.ModuleID == m1.ModuleID, "Expected Module ID from database to match, %d != %d", m1.ModuleID, ms.ModuleID)
|
||||
}
|
||||
|
||||
// update created record
|
||||
{
|
||||
m1.UpdatedAt = nil
|
||||
_, err := svc.Update(m1)
|
||||
test.Assert(t, err == nil, "Error when updating record, %+v", err)
|
||||
}
|
||||
|
||||
// re-fetch record
|
||||
{
|
||||
ms, err := svc.FindByID(m1.NamespaceID, m1.ID)
|
||||
test.Assert(t, err == nil, "Error when retrieving record by id: %+v", err)
|
||||
test.Assert(t, ms.ID == m1.ID, "Expected ID from database to match, %d != %d", m1.ID, ms.ID)
|
||||
test.Assert(t, ms.ModuleID == m1.ModuleID, "Expected ID from database to match, %d != %d", m1.ModuleID, ms.ModuleID)
|
||||
}
|
||||
|
||||
// fetch all records
|
||||
{
|
||||
mr, f, err := svc.Find(types.RecordFilter{ModuleID: module1.ID, Sort: "id desc"})
|
||||
test.Assert(t, err == nil, "Error when retrieving records: %+v", err)
|
||||
test.Assert(t, len(mr) == 2, "Expected two record, got %d", len(mr))
|
||||
test.Assert(t, f.Count == 2, "Expected Meta.Count == 2, got %d", f.Count)
|
||||
test.Assert(t, f.Sort == "id desc", "Expected Meta.Sort == id desc, got '%s'", f.Sort)
|
||||
test.Assert(t, mr[0].ModuleID == m1.ModuleID, "Expected record module1 to match, %d != %d", m1.ModuleID, mr[0].ModuleID)
|
||||
test.Assert(t, mr[0].ID > mr[1].ID, "Expected order to be descending")
|
||||
}
|
||||
|
||||
// fetch all records
|
||||
{
|
||||
|
||||
mr, f, err := svc.Find(types.RecordFilter{ModuleID: module1.ID, Sort: "name asc, email desc"})
|
||||
test.Assert(t, err == nil, "Error when retrieving records: %+v", err)
|
||||
test.Assert(t, len(mr) == 2, "Expected two record, got %d", len(mr))
|
||||
test.Assert(t, f.Count == 2, "Expected Meta.Count == 2, got %d", f.Count)
|
||||
test.Assert(t, f.Sort == "name asc, email desc", "Expected Meta.Sort == 'name asc, email desc' '%s'", f.Sort)
|
||||
test.Assert(t, mr[0].ModuleID == m1.ModuleID, "Expected record module1 to match, %d != %d", m1.ModuleID, mr[0].ModuleID)
|
||||
|
||||
// @todo sort is not stable
|
||||
// test.Assert(t, mr[0].ID > mr[1].ID, "Expected order to be ascending")
|
||||
}
|
||||
|
||||
// fetch all records
|
||||
{
|
||||
mr, f, err := svc.Find(types.RecordFilter{ModuleID: module1.ID, Sort: "created_at desc"})
|
||||
test.Assert(t, err == nil, "Error when retrieving records: %+v", err)
|
||||
test.Assert(t, len(mr) == 2, "Expected two record, got %d", len(mr))
|
||||
test.Assert(t, f.Count == 2, "Expected Meta.Count == 2, got %d", f.Count)
|
||||
test.Assert(t, f.Sort == "created_at desc", "Expected Meta.Sort == created_at desc, got '%s'", f.Sort)
|
||||
test.Assert(t, mr[0].ModuleID == m1.ModuleID, "Expected record module1 to match, %d != %d", m1.ModuleID, mr[0].ModuleID)
|
||||
|
||||
// @todo sort is not stable
|
||||
// test.Assert(t, mr[0].ID > mr[1].ID, "Expected order to be ascending")
|
||||
}
|
||||
|
||||
// fetch all records by query
|
||||
{
|
||||
filter := "name='John Doe' AND email='john.doe@example.com'"
|
||||
sort := "id desc"
|
||||
|
||||
mr, f, err := svc.Find(types.RecordFilter{ModuleID: module1.ID, Sort: sort, Filter: filter})
|
||||
test.Assert(t, err == nil, "Error when retrieving records: %+v", err)
|
||||
test.Assert(t, len(mr) == 1, "Expected one record, got %d", len(mr))
|
||||
test.Assert(t, f.Count == 1, "Expected Meta.Count == 1, got %d", f.Count)
|
||||
test.Assert(t, f.Page == 0, "Expected Meta.Page == 0, got %d", f.Page)
|
||||
test.Assert(t, f.PerPage == 50, "Expected Meta.PerPage == 50, got %d", f.PerPage)
|
||||
test.Assert(t, f.Filter == filter, "Expected Meta.Filter == %q, got %q", filter, f.Filter)
|
||||
test.Assert(t, f.Sort == sort, "Expected Meta.Sort == %q, got %q", sort, f.Sort)
|
||||
}
|
||||
|
||||
// fetch all records by query
|
||||
{
|
||||
mr, _, err := svc.Find(types.RecordFilter{ModuleID: module1.ID, Sort: "id asc", Filter: "name='niall'"})
|
||||
test.Assert(t, err == nil, "Error when retrieving records: %+v", err)
|
||||
test.Assert(t, len(mr) == 0, "Expected no records, got %d", len(mr))
|
||||
}
|
||||
|
||||
// delete record
|
||||
{
|
||||
err := svc.DeleteByID(m1.NamespaceID, m1.ID)
|
||||
test.Assert(t, err == nil, "Error when retrieving record by id: %+v", err)
|
||||
|
||||
err = svc.DeleteByID(m2.NamespaceID, m2.ID)
|
||||
test.Assert(t, err == nil, "Error when retrieving record by id: %+v", err)
|
||||
}
|
||||
|
||||
// fetch all records
|
||||
{
|
||||
mr, _, err := svc.Find(types.RecordFilter{ModuleID: module1.ID})
|
||||
test.Assert(t, err == nil, "Error when retrieving records: %+v", err)
|
||||
test.Assert(t, len(mr) == 0, "Expected no record, got %d", len(mr))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueSanitizer(t *testing.T) {
|
||||
var (
|
||||
svc = record{
|
||||
@ -265,36 +21,50 @@ func TestValueSanitizer(t *testing.T) {
|
||||
&types.ModuleField{Name: "multiRef1", Kind: "Record", Multi: true},
|
||||
},
|
||||
}
|
||||
rvs types.RecordValueSet
|
||||
|
||||
rvs, out types.RecordValueSet
|
||||
err error
|
||||
)
|
||||
|
||||
rvs = types.RecordValueSet{{Name: "single1", Value: "single"}}
|
||||
test.NoError(t, svc.sanitizeValues(module, rvs), "unexpected error for sanitizeValues() call: %v")
|
||||
test.Assert(t, len(rvs) == 1, "expecting 1 record value after sanitization, got %d", len(rvs))
|
||||
out, err = svc.sanitizeValues(module, rvs)
|
||||
test.NoError(t, err, "unexpected error for sanitizeValues() call: %v")
|
||||
test.Assert(t, len(out) == 1, "expecting 1 record value after sanitization, got %d", len(rvs))
|
||||
|
||||
rvs = types.RecordValueSet{{Name: "unknown", Value: "single"}}
|
||||
test.Assert(t, svc.sanitizeValues(module, rvs) != nil, "expecting sanitizeValues() to return an error, got nil")
|
||||
out, err = svc.sanitizeValues(module, rvs)
|
||||
test.Assert(t, err != nil, "expecting sanitizeValues() to return an error, got nil")
|
||||
|
||||
rvs = types.RecordValueSet{{Name: "single1", Value: "single"}, {Name: "single1", Value: "single2"}}
|
||||
test.Assert(t, svc.sanitizeValues(module, rvs) != nil, "expecting sanitizeValues() to return an error, got nil")
|
||||
out, err = svc.sanitizeValues(module, rvs)
|
||||
test.Assert(t, err != nil, "expecting sanitizeValues() to return an error, got nil")
|
||||
|
||||
rvs = types.RecordValueSet{{Name: "multi1", Value: "multi1"}, {Name: "multi1", Value: "multi1"}}
|
||||
test.NoError(t, svc.sanitizeValues(module, rvs), "unexpected error for sanitizeValues() call: %v")
|
||||
test.Assert(t, len(rvs) == 2, "expecting 2 record values after sanitization, got %d", len(rvs))
|
||||
test.Assert(t, rvs[0].Place == 0, "expecting first value to have place value 0, got %d", rvs[0].Place)
|
||||
test.Assert(t, rvs[1].Place == 1, "expecting second value to have place value 1, got %d", rvs[1].Place)
|
||||
out, err = svc.sanitizeValues(module, rvs)
|
||||
test.NoError(t, err, "unexpected error for sanitizeValues() call: %v")
|
||||
test.Assert(t, len(out) == 2, "expecting 2 record values after sanitization, got %d", len(rvs))
|
||||
test.Assert(t, out[0].Place == 0, "expecting first value to have place value 0, got %d", out[0].Place)
|
||||
test.Assert(t, out[1].Place == 1, "expecting second value to have place value 1, got %d", out[1].Place)
|
||||
|
||||
rvs = types.RecordValueSet{{Name: "ref1", Value: "multi1"}}
|
||||
test.Assert(t, svc.sanitizeValues(module, rvs) != nil, "expecting sanitizeValues() to return an error, got nil")
|
||||
out, err = svc.sanitizeValues(module, rvs)
|
||||
test.Assert(t, err != nil, "expecting sanitizeValues() to return an error, got nil")
|
||||
|
||||
rvs = types.RecordValueSet{{Name: "ref1", Value: "12345"}}
|
||||
test.NoError(t, svc.sanitizeValues(module, rvs), "unexpected error for sanitizeValues() call: %v")
|
||||
test.Assert(t, len(rvs) == 1, "expecting 1 record values after sanitization, got %d", len(rvs))
|
||||
test.Assert(t, rvs[0].Ref == 12345, "expecting parsed ref value to match, got %d", rvs[0].Ref)
|
||||
out, err = svc.sanitizeValues(module, rvs)
|
||||
test.NoError(t, err, "unexpected error for sanitizeValues() call: %v")
|
||||
test.Assert(t, len(out) == 1, "expecting 1 record values after sanitization, got %d", len(rvs))
|
||||
test.Assert(t, out[0].Ref == 12345, "expecting parsed ref value to match, got %d", rvs[0].Ref)
|
||||
|
||||
rvs = types.RecordValueSet{{Name: "multiRef1", Value: "12345"}, {Name: "multiRef1", Value: "67890"}}
|
||||
test.NoError(t, svc.sanitizeValues(module, rvs), "unexpected error for sanitizeValues() call: %v")
|
||||
out, err = svc.sanitizeValues(module, rvs)
|
||||
test.NoError(t, err, "unexpected error for sanitizeValues() call: %v")
|
||||
test.Assert(t, len(rvs) == 2, "expecting 2 record values after sanitization, got %d", len(rvs))
|
||||
test.Assert(t, rvs[0].Ref == 12345, "expecting parsed ref value to match, got %d", rvs[0].Ref)
|
||||
test.Assert(t, rvs[1].Ref == 67890, "expecting parsed ref value to match, got %d", rvs[1].Ref)
|
||||
test.Assert(t, out[0].Ref == 12345, "expecting parsed ref value to match, got %d", out[0].Ref)
|
||||
test.Assert(t, out[1].Ref == 67890, "expecting parsed ref value to match, got %d", out[1].Ref)
|
||||
|
||||
rvs = types.RecordValueSet{{Name: "ref1", Value: ""}}
|
||||
out, err = svc.sanitizeValues(module, rvs)
|
||||
test.NoError(t, err, "unexpected error for sanitizeValues() call: %v")
|
||||
test.Assert(t, len(out) == 0, "expecting 0 record values after sanitization, got %d", len(rvs))
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user