From 2a180927b7af14199eb9ed59eee0a774c778e1b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B0=B7=E6=BA=AA?= Date: Fri, 6 Aug 2021 15:55:02 +0800 Subject: [PATCH] refactor: rename package remote to package etcd (#175) * refactor: etcd != remote. * test: fix unbounded context * feat: add WithKey helper * fix: eliminate pointers BREAKING CHANGE: package remote no longer exists. --- c.go | 9 ---- config/remote/{remote.go => etcd/etcd.go} | 41 +++++++++++-------- .../{remote_test.go => etcd/etcd_test.go} | 27 ++++++------ .../example_test.go} | 22 +++++----- 4 files changed, 52 insertions(+), 47 deletions(-) rename config/remote/{remote.go => etcd/etcd.go} (52%) rename config/remote/{remote_test.go => etcd/etcd_test.go} (82%) rename config/remote/{integration_test.go => etcd/example_test.go} (67%) diff --git a/c.go b/c.go index 9c414f98..19e99964 100644 --- a/c.go +++ b/c.go @@ -15,7 +15,6 @@ import ( "github.com/DoNewsCode/core/codec/yaml" "github.com/DoNewsCode/core/config" - "github.com/DoNewsCode/core/config/remote" "github.com/DoNewsCode/core/config/watcher" "github.com/DoNewsCode/core/container" "github.com/DoNewsCode/core/contract" @@ -24,7 +23,6 @@ import ( "github.com/go-kit/kit/log" "github.com/knadh/koanf/providers/confmap" "github.com/knadh/koanf/providers/file" - clientv3 "go.etcd.io/etcd/client/v3" ) // C stands for the core of the application. It contains service definitions and @@ -93,13 +91,6 @@ func WithYamlFile(path string) (CoreOption, CoreOption) { WithConfigWatcher(watcher.File{Path: path}) } -// WithRemoteYamlFile is a two-in-one coreOption. It uses the remote key on etcd as the -// source of configuration, and watches the change of that key for hot reloading. -func WithRemoteYamlFile(key string, cfg clientv3.Config) (CoreOption, CoreOption) { - r := remote.Provider(key, &cfg) - return WithConfigStack(r, config.CodecParser{Codec: yaml.Codec{}}), WithConfigWatcher(r) -} - // WithInline is a CoreOption that creates a inline config in the configuration stack. func WithInline(key string, entry interface{}) CoreOption { return WithConfigStack(confmap.Provider(map[string]interface{}{ diff --git a/config/remote/remote.go b/config/remote/etcd/etcd.go similarity index 52% rename from config/remote/remote.go rename to config/remote/etcd/etcd.go index 0e89022d..a030dbe0 100644 --- a/config/remote/remote.go +++ b/config/remote/etcd/etcd.go @@ -1,31 +1,41 @@ -package remote +// Package etcd allows the core package to bootstrap its configuration from an etcd server. +package etcd import ( "context" "errors" "fmt" - + "github.com/DoNewsCode/core" + "github.com/DoNewsCode/core/config" + "github.com/DoNewsCode/core/contract" "go.etcd.io/etcd/client/v3" ) -// Remote is a core.ConfProvider and contract.ConfigWatcher implementation to read and watch remote config key. +// ETCD is a core.ConfProvider and contract.ConfigWatcher implementation to read and watch remote config key. // The remote client uses etcd. -type Remote struct { - key string - clientConfig *clientv3.Config +type ETCD struct { + key string + clientConfig clientv3.Config } -// Provider create a *Remote -func Provider(key string, clientConfig *clientv3.Config) *Remote { - return &Remote{ - key: key, +// Provider create a *ETCD +func Provider(clientConfig clientv3.Config, key string) *ETCD { + return &ETCD{ + key: key, clientConfig: clientConfig, } } +// WithKey is a two-in-one coreOption. It uses the remote key on etcd as the +// source of configuration, and watches the change of that key for hot reloading. +func WithKey(cfg clientv3.Config, key string, codec contract.Codec) (core.CoreOption, core.CoreOption) { + r := Provider(cfg, key) + return core.WithConfigStack(r, config.CodecParser{Codec: codec}), core.WithConfigWatcher(r) +} + // ReadBytes reads the contents of a key from etcd and returns the bytes. -func (r *Remote) ReadBytes() ([]byte, error) { - client, err := clientv3.New(*r.clientConfig) +func (r *ETCD) ReadBytes() ([]byte, error) { + client, err := clientv3.New(r.clientConfig) if err != nil { return nil, err } @@ -43,7 +53,7 @@ func (r *Remote) ReadBytes() ([]byte, error) { } // Read is not supported by the remote provider. -func (r *Remote) Read() (map[string]interface{}, error) { +func (r *ETCD) Read() (map[string]interface{}, error) { return nil, errors.New("remote provider does not support this method") } @@ -51,8 +61,8 @@ func (r *Remote) Read() (map[string]interface{}, error) { // will be called. note the reload function should not just load the changes made within this key, but rather // it should reload the whole config stack. For example, if the flag or env takes precedence over the config // key, they should remain to be so after the key changes. -func (r *Remote) Watch(ctx context.Context, reload func() error) error { - client, err := clientv3.New(*r.clientConfig) +func (r *ETCD) Watch(ctx context.Context, reload func() error) error { + client, err := clientv3.New(r.clientConfig) if err != nil { return err } @@ -74,4 +84,3 @@ func (r *Remote) Watch(ctx context.Context, reload func() error) error { } } } - diff --git a/config/remote/remote_test.go b/config/remote/etcd/etcd_test.go similarity index 82% rename from config/remote/remote_test.go rename to config/remote/etcd/etcd_test.go index 07f41596..a8a987ff 100644 --- a/config/remote/remote_test.go +++ b/config/remote/etcd/etcd_test.go @@ -1,4 +1,4 @@ -package remote +package etcd import ( "context" @@ -19,12 +19,12 @@ func TestRemote(t *testing.T) { return } addrs := strings.Split(os.Getenv("ETCD_ADDR"), ",") - cfg := &clientv3.Config{ + cfg := clientv3.Config{ Endpoints: addrs, DialTimeout: 2 * time.Second, } - r := Provider("config.yaml", cfg) + r := Provider(cfg, "config.yaml") var testVal = "name: app" // PREPARE TEST DATA @@ -67,16 +67,16 @@ func TestError(t *testing.T) { } addrs := strings.Split(os.Getenv("ETCD_ADDR"), ",") var ( - r *Remote + r *ETCD err error ) - cfg := &clientv3.Config{ + cfg := clientv3.Config{ Endpoints: []string{}, DialTimeout: 2 * time.Second, } - r = Provider("config.yaml", cfg) + r = Provider(cfg, "config.yaml") err = put(r, "test") assert.Error(t, err) @@ -88,15 +88,15 @@ func TestError(t *testing.T) { }) assert.Error(t, err) - cfg = &clientv3.Config{ + cfg = clientv3.Config{ Endpoints: addrs, DialTimeout: 2 * time.Second, } - r = Provider("config-test1", cfg) + r = Provider(cfg, "config-test1") _, err = r.ReadBytes() assert.Error(t, err) - r = Provider("config-test2", cfg) + r = Provider(cfg, "config-test2") // Confirm that the two coroutines are finished g := sync.WaitGroup{} @@ -126,14 +126,17 @@ func TestError(t *testing.T) { g.Wait() } -func put(r *Remote, val string) error { - client, err := clientv3.New(*r.clientConfig) +func put(r *ETCD, val string) error { + client, err := clientv3.New(r.clientConfig) if err != nil { return err } defer client.Close() - _, err = client.Put(context.Background(), r.key, val) + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + + _, err = client.Put(ctx, r.key, val) if err != nil { return err } diff --git a/config/remote/integration_test.go b/config/remote/etcd/example_test.go similarity index 67% rename from config/remote/integration_test.go rename to config/remote/etcd/example_test.go index ae9c10c5..cadc5789 100644 --- a/config/remote/integration_test.go +++ b/config/remote/etcd/example_test.go @@ -1,20 +1,21 @@ -package remote_test +package etcd_test import ( "context" + "fmt" "github.com/DoNewsCode/core" - "github.com/stretchr/testify/assert" + "github.com/DoNewsCode/core/codec/yaml" + "github.com/DoNewsCode/core/config/remote/etcd" clientv3 "go.etcd.io/etcd/client/v3" "os" "strings" - "testing" "time" ) -func Test_integration(t *testing.T) { +func Example() { addr := os.Getenv("ETCD_ADDR") if addr == "" { - t.Skip("set ETCD_ADDR for run remote test") + fmt.Println("set ETCD_ADDR for run example") return } key := "core.yaml" @@ -23,13 +24,14 @@ func Test_integration(t *testing.T) { Endpoints: envEtcdAddrs, DialTimeout: time.Second, } - if err := put(cfg, key, "name: remote"); err != nil { - t.Fatal(err) - } + _ = put(cfg, key, "name: etcd") - c := core.New(core.WithRemoteYamlFile(key, cfg)) + c := core.New(etcd.WithKey(cfg, key, yaml.Codec{})) c.ProvideEssentials() - assert.Equal(t, "remote", c.String("name")) + fmt.Println(c.String("name")) + + // Output: + // etcd } func put(cfg clientv3.Config, key, val string) error {