From 95892bff45be9d277c6c6ace62537c8806c6fb5c Mon Sep 17 00:00:00 2001 From: kevin Date: Mon, 27 Jan 2025 20:28:02 +0800 Subject: [PATCH] feat: auto validate config --- core/conf/config.go | 13 ++++++++-- core/conf/config_test.go | 38 +++++++++++++++++++++++++++++ core/conf/validate.go | 11 +++++++++ core/conf/validate_test.go | 50 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 core/conf/validate.go create mode 100644 core/conf/validate_test.go diff --git a/core/conf/config.go b/core/conf/config.go index 743f8c6144e1..6428abd7da95 100644 --- a/core/conf/config.go +++ b/core/conf/config.go @@ -62,7 +62,11 @@ func Load(file string, v any, opts ...Option) error { return loader([]byte(os.ExpandEnv(string(content))), v) } - return loader(content, v) + if err = loader(content, v); err != nil { + return err + } + + return validate(v) } // LoadConfig loads config into v from file, .json, .yaml and .yml are acceptable. @@ -85,7 +89,12 @@ func LoadFromJsonBytes(content []byte, v any) error { lowerCaseKeyMap := toLowerCaseKeyMap(m, info) - return mapping.UnmarshalJsonMap(lowerCaseKeyMap, v, mapping.WithCanonicalKeyFunc(toLowerCase)) + if err = mapping.UnmarshalJsonMap(lowerCaseKeyMap, v, + mapping.WithCanonicalKeyFunc(toLowerCase)); err != nil { + return err + } + + return validate(v) } // LoadConfigFromJsonBytes loads config into v from content json bytes. diff --git a/core/conf/config_test.go b/core/conf/config_test.go index e3025fba89eb..b078a32a1b57 100644 --- a/core/conf/config_test.go +++ b/core/conf/config_test.go @@ -1,6 +1,7 @@ package conf import ( + "errors" "os" "reflect" "testing" @@ -1222,6 +1223,26 @@ func Test_getFullName(t *testing.T) { assert.Equal(t, "a", getFullName("", "a")) } +func TestValidate(t *testing.T) { + t.Run("normal config", func(t *testing.T) { + var c mockConfig + err := LoadFromJsonBytes([]byte(`{"val": "hello", "number": 8}`), &c) + assert.NoError(t, err) + }) + + t.Run("error no int", func(t *testing.T) { + var c mockConfig + err := LoadFromJsonBytes([]byte(`{"val": "hello"}`), &c) + assert.Error(t, err) + }) + + t.Run("error no string", func(t *testing.T) { + var c mockConfig + err := LoadFromJsonBytes([]byte(`{"number": 8}`), &c) + assert.Error(t, err) + }) +} + func Test_buildFieldsInfo(t *testing.T) { type ParentSt struct { Name string @@ -1328,3 +1349,20 @@ func createTempFile(ext, text string) (string, error) { return filename, nil } + +type mockConfig struct { + Val string + Number int +} + +func (m mockConfig) Validate() error { + if len(m.Val) == 0 { + return errors.New("val is empty") + } + + if m.Number == 0 { + return errors.New("number is zero") + } + + return nil +} diff --git a/core/conf/validate.go b/core/conf/validate.go new file mode 100644 index 000000000000..10c1bca28bdd --- /dev/null +++ b/core/conf/validate.go @@ -0,0 +1,11 @@ +package conf + +import "github.com/zeromicro/go-zero/core/validation" + +func validate(v any) error { + if val, ok := v.(validation.Validator); ok { + return val.Validate() + } + + return nil +} diff --git a/core/conf/validate_test.go b/core/conf/validate_test.go new file mode 100644 index 000000000000..bf38c9777d71 --- /dev/null +++ b/core/conf/validate_test.go @@ -0,0 +1,50 @@ +package conf + +import ( + "errors" + "testing" + + "github.com/stretchr/testify/assert" +) + +type mockType int + +func (m mockType) Validate() error { + if m < 10 { + return errors.New("invalid value") + } + + return nil +} + +type anotherMockType int + +func Test_validate(t *testing.T) { + tests := []struct { + name string + v any + wantErr bool + }{ + { + name: "invalid", + v: mockType(5), + wantErr: true, + }, + { + name: "valid", + v: mockType(10), + wantErr: false, + }, + { + name: "not validator", + v: anotherMockType(5), + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := validate(tt.v) + assert.Equal(t, tt.wantErr, err != nil) + }) + } +}