From a82c82d49f8f0f0cdd060838241bdfceb4a1f42b Mon Sep 17 00:00:00 2001 From: qshuai Date: Sat, 26 Nov 2022 18:44:01 +0800 Subject: [PATCH] fix(config): fix codec NPE as parsing format wrongly, fix #2517 (#2518) * fix[config]: fix codec NPE as parsing format wrongly, fix #2517 * feat: add unit testing for namespace parsing --- contrib/config/apollo/apollo.go | 36 ++++++++--- contrib/config/apollo/apollo_test.go | 90 ++++++++++++++++++++++++++++ contrib/config/apollo/watcher.go | 2 +- 3 files changed, 119 insertions(+), 9 deletions(-) create mode 100644 contrib/config/apollo/apollo_test.go diff --git a/contrib/config/apollo/apollo.go b/contrib/config/apollo/apollo.go index bd96ef11d..d463df29e 100644 --- a/contrib/config/apollo/apollo.go +++ b/contrib/config/apollo/apollo.go @@ -25,6 +25,8 @@ const ( properties = "properties" ) +var formats map[string]struct{} + // Option is apollo option type Option func(*options) @@ -129,10 +131,16 @@ func NewSource(opts ...Option) config.Source { func format(ns string) string { arr := strings.Split(ns, ".") - if len(arr) <= 1 || arr[len(arr)-1] == properties { + suffix := arr[len(arr)-1] + if len(arr) <= 1 || suffix == properties { + return json + } + if _, ok := formats[suffix]; !ok { + // fallback return json } - return arr[len(arr)-1] + + return suffix } func (e *apollo) load() []*config.KeyValue { @@ -149,7 +157,7 @@ func (e *apollo) load() []*config.KeyValue { kvs = append(kvs, kv) continue } - if strings.Contains(ns, ".") && !strings.Contains(ns, properties) && + if strings.Contains(ns, ".") && !strings.HasSuffix(ns, "."+properties) && (format(ns) == yaml || format(ns) == yml || format(ns) == json) { kv, err := e.getOriginConfig(ns) if err != nil { @@ -252,16 +260,28 @@ func resolve(key string, value interface{}, target map[string]interface{}) { // eg: namespace.ext with subKey got namespace.subKey func genKey(ns, sub string) string { arr := strings.Split(ns, ".") - if len(arr) < 1 { - return sub - } - if len(arr) == 1 { if ns == "" { return sub } + return ns + "." + sub } - return strings.Join(arr[:len(arr)-1], ".") + "." + sub + suffix := arr[len(arr)-1] + _, ok := formats[suffix] + if ok { + return strings.Join(arr[:len(arr)-1], ".") + "." + sub + } + + return ns + "." + sub +} + +func init() { + formats = make(map[string]struct{}) + + formats[yaml] = struct{}{} + formats[yml] = struct{}{} + formats[json] = struct{}{} + formats[properties] = struct{}{} } diff --git a/contrib/config/apollo/apollo_test.go b/contrib/config/apollo/apollo_test.go new file mode 100644 index 000000000..185ca4c64 --- /dev/null +++ b/contrib/config/apollo/apollo_test.go @@ -0,0 +1,90 @@ +package apollo + +import ( + "testing" +) + +func Test_genKey(t *testing.T) { + type args struct { + ns string + sub string + } + tests := []struct { + name string + args args + want string + }{ + { + name: "blank namespace", + args: args{ + ns: "", + sub: "x.y", + }, + want: "x.y", + }, + { + name: "properties namespace", + args: args{ + ns: "application", + sub: "x.y", + }, + want: "application.x.y", + }, + { + name: "namespace with format", + args: args{ + ns: "app.yaml", + sub: "x.y", + }, + want: "app.x.y", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := genKey(tt.args.ns, tt.args.sub); got != tt.want { + t.Errorf("genKey() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_format(t *testing.T) { + tests := []struct { + name string + namespace string + want string + }{ + { + name: "properties namespace", + namespace: "application", + want: "json", + }, + { + name: "properties namespace #1", + namespace: "app.setting", + want: "json", + }, + { + name: "namespace with format[yaml]", + namespace: "app.yaml", + want: "yaml", + }, + { + name: "namespace with format[yml]", + namespace: "app.yml", + want: "yml", + }, + { + name: "namespace with format[json]", + namespace: "app.json", + want: "json", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := format(tt.namespace); got != tt.want { + t.Errorf("format() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/contrib/config/apollo/watcher.go b/contrib/config/apollo/watcher.go index ea5ef1083..d59bdd212 100644 --- a/contrib/config/apollo/watcher.go +++ b/contrib/config/apollo/watcher.go @@ -25,7 +25,7 @@ type customChangeListener struct { func (c *customChangeListener) onChange(namespace string, changes map[string]*storage.ConfigChange) []*config.KeyValue { kv := make([]*config.KeyValue, 0, 2) - if strings.Contains(namespace, ".") && !strings.Contains(namespace, properties) && + if strings.Contains(namespace, ".") && !strings.HasSuffix(namespace, "."+properties) && (format(namespace) == yaml || format(namespace) == yml || format(namespace) == json) { value, err := c.apollo.client.GetConfigCache(namespace).Get("content") if err != nil {