diff --git a/compose/service/module.go b/compose/service/module.go index 2adebee1b..afb653a72 100644 --- a/compose/service/module.go +++ b/compose/service/module.go @@ -589,10 +589,19 @@ func updateModuleFields(ctx context.Context, s store.Storer, new, old *types.Mod func moduleFieldDefaultPreparer(ctx context.Context, s store.Storer, m *types.Module, newFields types.ModuleFieldSet) (types.ModuleFieldSet, error) { var err error + // prepare an auxillary module to perform isolated validations on + auxm := &types.Module{ + Handle: "aux_module", + NamespaceID: m.NamespaceID, + Fields: types.ModuleFieldSet{nil}, + } + for _, f := range newFields { if f.DefaultValue == nil || len(f.DefaultValue) == 0 { continue } + auxm.Fields[0] = f + vv := f.DefaultValue vv.SetUpdatedFlag(true) // Module field default values should not have a field name, so let's temporarily add it @@ -601,21 +610,21 @@ func moduleFieldDefaultPreparer(ctx context.Context, s store.Storer, m *types.Mo return nil }) - if err = RecordValueSanitization(m, vv); err != nil { + if err = RecordValueSanitization(auxm, vv); err != nil { return nil, err } - vv = values.Sanitizer().Run(m, vv) + vv = values.Sanitizer().Run(auxm, vv) r := &types.Record{ Values: vv, } - rve := defaultValidator().Run(ctx, s, m, r) + rve := defaultValidator().Run(ctx, s, auxm, r) if !rve.IsValid() { return nil, rve } - vv = values.Formatter().Run(m, vv) + vv = values.Formatter().Run(auxm, vv) // Module field default values should not have a field name, so let's remove it vv.Walk(func(rv *types.RecordValue) error { diff --git a/tests/compose/module_test.go b/tests/compose/module_test.go index 3afa0be57..8c3e56270 100644 --- a/tests/compose/module_test.go +++ b/tests/compose/module_test.go @@ -265,6 +265,39 @@ func TestModuleFieldsUpdate(t *testing.T) { h.a.Equal(m.Fields[1].Kind, "DateTime") } +func TestModuleFieldsUpdate_defaults(t *testing.T) { + h := newHelper(t) + h.clearModules() + + h.allow(types.NamespaceRBACResource.AppendWildcard(), "read") + ns := h.makeNamespace("some-namespace") + m := h.makeModule(ns, "some-module", &types.ModuleField{ID: id.Next(), Kind: "String", Name: "existing", Required: true, DefaultValue: types.RecordValueSet{&types.RecordValue{Value: "test"}}}) + h.allow(types.ModuleRBACResource.AppendWildcard(), "update") + + f := m.Fields[0] + fjs := fmt.Sprintf(`{ "name": "%s", "fields": [{ "fieldID": "%d", "name": "existing_edited", "kind": "String", "isRequired": true, "defaultValue": [{ "value": "test" }] }, { "name": "new", "kind": "Bool", "defaultValue": [{ "value": "1" }] }] }`, m.Name, f.ID) + h.apiInit(). + Post(fmt.Sprintf("/namespace/%d/module/%d", ns.ID, m.ID)). + JSON(fjs). + Expect(t). + Status(http.StatusOK). + Assert(helpers.AssertNoErrors). + End() + + m = h.lookupModuleByID(m.ID) + h.a.NotNil(m) + h.a.NotNil(m.Fields) + h.a.Len(m.Fields, 2) + + h.a.Equal(m.Fields[0].Kind, "String") + h.a.Len(m.Fields[0].DefaultValue, 1) + h.a.Equal("test", m.Fields[0].DefaultValue[0].Value) + + h.a.Equal(m.Fields[1].Kind, "Bool") + h.a.Len(m.Fields[1].DefaultValue, 1) + h.a.Equal("1", m.Fields[1].DefaultValue[0].Value) +} + func TestModuleFieldsDefaultValue(t *testing.T) { var ns *types.Namespace