From 2c16c7b917e5e699da5d9eb4699313a0cc38f012 Mon Sep 17 00:00:00 2001 From: Ming Deng Date: Wed, 19 Aug 2020 22:08:29 +0800 Subject: [PATCH] Add more methods to Configer --- pkg/config.go | 3 +- pkg/config/base_config_test.go | 71 ++++++++++++++ pkg/config/config.go | 135 +++++++++++++++++++++++++-- pkg/config/fake.go | 1 + pkg/config/ini.go | 1 + pkg/config/json/json.go | 1 + pkg/config/xml/xml.go | 1 + pkg/config/yaml/yaml.go | 1 + pkg/orm/filter_orm_decorator_test.go | 4 +- 9 files changed, 208 insertions(+), 10 deletions(-) create mode 100644 pkg/config/base_config_test.go diff --git a/pkg/config.go b/pkg/config.go index 0cfb7a4c..e8bde705 100644 --- a/pkg/config.go +++ b/pkg/config.go @@ -411,6 +411,7 @@ func LoadAppConfig(adapterName, configPath string) error { } type beegoAppConfig struct { + config.BaseConfiger innerConfig config.Configer } @@ -419,7 +420,7 @@ func newAppConfig(appConfigProvider, appConfigPath string) (*beegoAppConfig, err if err != nil { return nil, err } - return &beegoAppConfig{ac}, nil + return &beegoAppConfig{innerConfig: ac}, nil } func (b *beegoAppConfig) Set(key, val string) error { diff --git a/pkg/config/base_config_test.go b/pkg/config/base_config_test.go new file mode 100644 index 00000000..3d37bc91 --- /dev/null +++ b/pkg/config/base_config_test.go @@ -0,0 +1,71 @@ +// Copyright 2020 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package config + +import ( + "errors" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestBaseConfiger_DefaultBool(t *testing.T) { + bc := newBaseConfier("true") + assert.True(t, bc.DefaultBool("key1", false)) + assert.True(t, bc.DefaultBool("key2", true)) +} + +func TestBaseConfiger_DefaultFloat(t *testing.T) { + bc := newBaseConfier("12.3") + assert.Equal(t, 12.3, bc.DefaultFloat("key1", 0.1)) + assert.Equal(t, 0.1, bc.DefaultFloat("key2", 0.1)) +} + +func TestBaseConfiger_DefaultInt(t *testing.T) { + bc := newBaseConfier("10") + assert.Equal(t, 10, bc.DefaultInt("key1", 8)) + assert.Equal(t, 8, bc.DefaultInt("key2", 8)) +} + +func TestBaseConfiger_DefaultInt64(t *testing.T) { + bc := newBaseConfier("64") + assert.Equal(t, int64(64), bc.DefaultInt64("key1", int64(8))) + assert.Equal(t, int64(8), bc.DefaultInt64("key2", int64(8))) +} + +func TestBaseConfiger_DefaultString(t *testing.T) { + bc := newBaseConfier("Hello") + assert.Equal(t, "Hello", bc.DefaultString("key1", "world")) + assert.Equal(t, "world", bc.DefaultString("key2", "world")) +} + +func TestBaseConfiger_DefaultStrings(t *testing.T) { + bc := newBaseConfier("Hello;world") + assert.Equal(t, []string{"Hello", "world"}, bc.DefaultStrings("key1", []string{"world"})) + assert.Equal(t, []string{"world"}, bc.DefaultStrings("key2", []string{"world"})) +} + +func newBaseConfier(str1 string) *BaseConfiger { + return &BaseConfiger{ + reader: func(key string) (string, error) { + if key == "key1" { + return str1, nil + } else { + return "", errors.New("mock error") + } + + }, + } +} diff --git a/pkg/config/config.go b/pkg/config/config.go index bfd79e85..b17f6208 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -15,7 +15,7 @@ // Package config is used to parse config. // Usage: // import "github.com/astaxie/beego/config" -//Examples. +// Examples. // // cnf, err := config.NewConfig("ini", "config.conf") // @@ -37,36 +37,157 @@ // cnf.DIY(key string) (interface{}, error) // cnf.GetSection(section string) (map[string]string, error) // cnf.SaveConfigFile(filename string) error -//More docs http://beego.me/docs/module/config.md +// More docs http://beego.me/docs/module/config.md package config import ( + "errors" "fmt" "os" "reflect" + "strconv" + "strings" "time" ) // Configer defines how to get and set value from configuration raw data. type Configer interface { - Set(key, val string) error //support section::key type in given key when using ini type. - String(key string) string //support section::key type in key string when using ini and json type; Int,Int64,Bool,Float,DIY are same. - Strings(key string) []string //get string slice + // support section::key type in given key when using ini type. + Set(key, val string) error + + // support section::key type in key string when using ini and json type; Int,Int64,Bool,Float,DIY are same. + String(key string) string + // get string slice + Strings(key string) []string Int(key string) (int, error) Int64(key string) (int64, error) Bool(key string) (bool, error) Float(key string) (float64, error) - DefaultString(key string, defaultVal string) string // support section::key type in key string when using ini and json type; Int,Int64,Bool,Float,DIY are same. - DefaultStrings(key string, defaultVal []string) []string //get string slice + // support section::key type in key string when using ini and json type; Int,Int64,Bool,Float,DIY are same. + DefaultString(key string, defaultVal string) string + // get string slice + DefaultStrings(key string, defaultVal []string) []string DefaultInt(key string, defaultVal int) int DefaultInt64(key string, defaultVal int64) int64 DefaultBool(key string, defaultVal bool) bool DefaultFloat(key string, defaultVal float64) float64 DIY(key string) (interface{}, error) GetSection(section string) (map[string]string, error) + + Unmarshaler(obj interface{}) error + Sub(key string) (Configer, error) + OnChange(fn func(cfg Configer)) + // GetByPrefix(prefix string) ([]byte, error) + // GetSerializer() Serializer SaveConfigFile(filename string) error } +type BaseConfiger struct { + // The reader should support key like "a.b.c" + reader func(key string) (string, error) +} + +func (c *BaseConfiger) Int(key string) (int, error) { + res, err := c.reader(key) + if err != nil { + return 0, err + } + return strconv.Atoi(res) +} + +func (c *BaseConfiger) Int64(key string) (int64, error) { + res, err := c.reader(key) + if err != nil { + return 0, err + } + return strconv.ParseInt(res, 10, 64) +} + +func (c *BaseConfiger) Bool(key string) (bool, error) { + res, err := c.reader(key) + if err != nil { + return false, err + } + return strconv.ParseBool(res) +} + +func (c *BaseConfiger) Float(key string) (float64, error) { + res, err := c.reader(key) + if err != nil { + return 0, err + } + return strconv.ParseFloat(res, 64) +} + +func (c *BaseConfiger) DefaultString(key string, defaultVal string) string { + if res := c.String(key); res != "" { + return res + } + return defaultVal +} + +func (c *BaseConfiger) DefaultStrings(key string, defaultVal []string) []string { + if res := c.Strings(key); len(res) > 0 { + return res + } + return defaultVal +} + +func (c *BaseConfiger) DefaultInt(key string, defaultVal int) int { + if res, err := c.Int(key); err == nil { + return res + } + return defaultVal +} + +func (c *BaseConfiger) DefaultInt64(key string, defaultVal int64) int64 { + if res, err := c.Int64(key); err == nil { + return res + } + return defaultVal +} + +func (c *BaseConfiger) DefaultBool(key string, defaultVal bool) bool { + if res, err := c.Bool(key); err == nil { + return res + } + return defaultVal +} +func (c *BaseConfiger) DefaultFloat(key string, defaultVal float64) float64 { + if res, err := c.Float(key); err == nil { + return res + } + return defaultVal +} + +func (c *BaseConfiger) String(key string) string { + res, _ := c.reader(key) + return res +} + +func (c *BaseConfiger) Strings(key string) []string { + res, err := c.reader(key) + if err != nil || res == "" { + return nil + } + return strings.Split(res, ";") +} + +// TODO remove this before release v2.0.0 +func (c *BaseConfiger) Unmarshaler(obj interface{}) error { + return errors.New("unsupported operation") +} + +// TODO remove this before release v2.0.0 +func (c *BaseConfiger) Sub(key string) (Configer, error) { + return nil, errors.New("unsupported operation") +} + +// TODO remove this before release v2.0.0 +func (c *BaseConfiger) OnChange(fn func(cfg Configer)) { + // do nothing +} + // Config is the adapter interface for parsing config file to get raw data to Configer. type Config interface { Parse(key string) (Configer, error) diff --git a/pkg/config/fake.go b/pkg/config/fake.go index d21ab820..ddbc99b8 100644 --- a/pkg/config/fake.go +++ b/pkg/config/fake.go @@ -21,6 +21,7 @@ import ( ) type fakeConfigContainer struct { + BaseConfiger data map[string]string } diff --git a/pkg/config/ini.go b/pkg/config/ini.go index f5921308..0bef67d4 100644 --- a/pkg/config/ini.go +++ b/pkg/config/ini.go @@ -225,6 +225,7 @@ func (ini *IniConfig) ParseData(data []byte) (Configer, error) { // IniConfigContainer is a config which represents the ini configuration. // When set and get value, support key as section:name type. type IniConfigContainer struct { + BaseConfiger data map[string]map[string]string // section=> key:val sectionComment map[string]string // section : comment keyComment map[string]string // id: []{comment, key...}; id 1 is for main comment. diff --git a/pkg/config/json/json.go b/pkg/config/json/json.go index ede3cce5..876077e1 100644 --- a/pkg/config/json/json.go +++ b/pkg/config/json/json.go @@ -69,6 +69,7 @@ func (js *JSONConfig) ParseData(data []byte) (config.Configer, error) { // JSONConfigContainer is a config which represents the json configuration. // Only when get value, support key as section:name type. type JSONConfigContainer struct { + config.BaseConfiger data map[string]interface{} sync.RWMutex } diff --git a/pkg/config/xml/xml.go b/pkg/config/xml/xml.go index d8c018e6..9b5ec791 100644 --- a/pkg/config/xml/xml.go +++ b/pkg/config/xml/xml.go @@ -74,6 +74,7 @@ func (xc *Config) ParseData(data []byte) (config.Configer, error) { // ConfigContainer is a Config which represents the xml configuration. type ConfigContainer struct { + config.BaseConfiger data map[string]interface{} sync.Mutex } diff --git a/pkg/config/yaml/yaml.go b/pkg/config/yaml/yaml.go index 63a30208..5c77e88f 100644 --- a/pkg/config/yaml/yaml.go +++ b/pkg/config/yaml/yaml.go @@ -118,6 +118,7 @@ func parseYML(buf []byte) (cnf map[string]interface{}, err error) { // ConfigContainer is a config which represents the yaml configuration. type ConfigContainer struct { + config.BaseConfiger data map[string]interface{} sync.RWMutex } diff --git a/pkg/orm/filter_orm_decorator_test.go b/pkg/orm/filter_orm_decorator_test.go index d52ce27b..47f20854 100644 --- a/pkg/orm/filter_orm_decorator_test.go +++ b/pkg/orm/filter_orm_decorator_test.go @@ -115,7 +115,7 @@ func TestFilterOrmDecorator_Delete(t *testing.T) { register() o := &filterMockOrm{} od := NewFilterOrmDecorator(o, func(next Filter) Filter { - return func(ctx context.Context, inv *Invocation) []interface{} { + return func(ctx context.Context, inv *Invocation) []interface{} { assert.Equal(t, "DeleteWithCtx", inv.Method) assert.Equal(t, 2, len(inv.Args)) assert.Equal(t, "FILTER_TEST", inv.GetTableName()) @@ -311,7 +311,7 @@ func TestFilterOrmDecorator_Raw(t *testing.T) { assert.Nil(t, res) } -func TestFilterOrmDecorator_ReadForUpdate(t *testing.T) { +func TestFilterOrmDecorator_ReadForUpdate(t *testing.T) { register() o := &filterMockOrm{} od := NewFilterOrmDecorator(o, func(next Filter) Filter {