diff --git a/Readme.md b/Readme.md index bd1b544..f5d7025 100644 --- a/Readme.md +++ b/Readme.md @@ -26,8 +26,7 @@ Loggers: `logger.NewFmtLogger`, `logger.NewSlogLogger` (Go 1.21+), and the adapt | Method | Description | |---|---| | `Register(conf any) error` | registers the config, `conf` should be a pointer to struct | -| `Parse(conf any) error` | fills the registered config, or its field with struct type (sub config), with values from drivers | -| `ParseContext(ctx, conf any) error` | `Parse` with the context for the requests of the drivers to the remote storages | +| `Parse(ctx context.Context, conf any) error` | fills the registered config, or its field with struct type (sub config), with values from drivers; the context stops the requests of the drivers to the remote storages | | `GenDoc(driverName string) string` | generates documentation of all registered configs in the driver format | | `Sources(conf any) []FieldSource` | returns which driver has set the value of every field in the last `Parse` call | | `tinyconf.Subscribe(ctx, m, onChange) error` | calls `onChange(prev, next *T)` after the changes of the config or the sub config `T` | @@ -245,7 +244,7 @@ func main() { panic(err) } fmt.Println(config.GenDoc("yaml")) - if err = config.Parse(c); err != nil { + if err = config.Parse(context.Background(), c); err != nil { panic(err) } for _, source := range config.Sources(c) { @@ -254,7 +253,7 @@ func main() { // configs can be parsed partially, by the fields of the registered configs http := &HTTP{} - if err = config.Parse(http); err != nil { + if err = config.Parse(context.Background(), http); err != nil { panic(err) } fmt.Println(*http) @@ -302,7 +301,7 @@ and `tinyconf.ErrIncorrectTagSettings` if the field has no settings for the driv To support the same types as the built-in drivers, use the `convert` package: `convert.StringToField` for string values and `convert.TreeToField` for values decoded from formats like yaml or json. -If the driver implements the optional `tinyconf.Loader` or `tinyconf.ContextLoader` interface, `Load` (or `LoadContext` with the context of `ParseContext`) is called once at the start of every `Parse` call, +If the driver implements the optional `tinyconf.Loader` or `tinyconf.ContextLoader` interface, `Load` (or `LoadContext` with the context of `Parse`) is called once at the start of every `Parse` call, so the driver can read its source once and not for every field. If the driver implements the optional `tinyconf.Watcher` interface, it can report changes of its source for reloading. diff --git a/bench_test.go b/bench_test.go index dbf3c8d..5297317 100644 --- a/bench_test.go +++ b/bench_test.go @@ -1,6 +1,7 @@ package tinyconf import ( + "context" "testing" "time" ) @@ -35,7 +36,7 @@ func newBenchManager(b *testing.B) *Manager { if err = c.Register(conf); err != nil { b.Fatal(err) } - if err = c.Parse(conf); err != nil { + if err = c.Parse(context.Background(), conf); err != nil { b.Fatal(err) } return c @@ -47,7 +48,7 @@ func BenchmarkParse(b *testing.B) { b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { - if err := c.Parse(conf); err != nil { + if err := c.Parse(context.Background(), conf); err != nil { b.Fatal(err) } } @@ -59,7 +60,7 @@ func BenchmarkParse_SubConfig(b *testing.B) { b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { - if err := c.Parse(http); err != nil { + if err := c.Parse(context.Background(), http); err != nil { b.Fatal(err) } } diff --git a/docs/drivers/custom.md b/docs/drivers/custom.md index 87e9a53..670f19c 100644 --- a/docs/drivers/custom.md +++ b/docs/drivers/custom.md @@ -56,7 +56,7 @@ type Loader interface { `Load` is called once at the start of every `Parse` call, before any `GetValue` call. If it returns an error, the driver is skipped in this `Parse` call and the error is returned from `Parse`. -A driver that reads its source by the network should implement `tinyconf.ContextLoader` instead: `LoadContext` gets the context of [`ParseContext`](../features/manager.md#parse), or the context of watching for reloads, and the requests should stop when it is done. +A driver that reads its source by the network should implement `tinyconf.ContextLoader` instead: `LoadContext` gets the context of [`Parse`](../features/manager.md#parse), or the context of watching for reloads, and the requests should stop when it is done. ```go type ContextLoader interface { diff --git a/docs/features/gendoc.md b/docs/features/gendoc.md index a66f805..e202c5c 100644 --- a/docs/features/gendoc.md +++ b/docs/features/gendoc.md @@ -7,7 +7,7 @@ c := &Config{} if err := config.Register(c); err != nil { panic(err) } -if err := config.Parse(c); err != nil { +if err := config.Parse(context.Background(), c); err != nil { panic(err) } fmt.Println(config.GenDoc("yaml")) diff --git a/docs/features/manager.md b/docs/features/manager.md index 38e9bfa..e211143 100644 --- a/docs/features/manager.md +++ b/docs/features/manager.md @@ -38,21 +38,24 @@ err := config.Register(c) ## Parse ```go -err := config.Parse(c) +err := config.Parse(context.Background(), c) ``` `Parse` fills the registered config with values from drivers. The config can be a registered one or a field of the registered config with struct type, see [sub configs](structs.md#sub-configs). `tinyconf.ErrNotRegisteredConfig` is returned for all other configs. -`ParseContext` is `Parse` with the context for the drivers that read their sources by the network — [consul](../drivers/consul.md), [vault](../drivers/vault.md), [etcd](../drivers/etcd.md) and the remote documents: their requests are stopped when the context is done. A start of the application in Kubernetes is a typical case: +The context is used by the drivers that read their sources by the network — [consul](../drivers/consul.md), [vault](../drivers/vault.md), [etcd](../drivers/etcd.md) and the remote documents: their requests are stopped when the context is done. A start of the application in Kubernetes is a typical case: ```go ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() -if err := config.ParseContext(ctx, c); err != nil { +if err := config.Parse(ctx, c); err != nil { log.Fatal(err) // errors.Is(err, context.DeadlineExceeded) if the storage is not available in time } ``` +!!! note "Migration" + `Parse(conf)` of the previous versions is `Parse(context.Background(), conf)`, and `ParseContext(ctx, conf)` is `Parse(ctx, conf)`. + Every request of the drivers is limited to 30 seconds anyway. The reloads use the context of watching, so the requests are stopped when the last subscription is canceled. ## Other methods @@ -70,7 +73,7 @@ Every request of the drivers is limited to 30 seconds anyway. The reloads use th `Parse` does not stop on the first error: all fields are parsed, and all errors are returned as one error. It can be checked with `errors.Is` and `errors.As`. ```go -if err := config.Parse(c); err != nil { +if err := config.Parse(context.Background(), c); err != nil { // env driver: field HTTP.Port: failed to parse env value from key HTTP_PORT ... log.Fatal(err) } diff --git a/docs/features/reloading.md b/docs/features/reloading.md index 2d8f22a..f05798c 100644 --- a/docs/features/reloading.md +++ b/docs/features/reloading.md @@ -7,7 +7,7 @@ c := &Config{} if err := config.Register(c); err != nil { panic(err) } -if err := config.Parse(c); err != nil { +if err := config.Parse(context.Background(), c); err != nil { panic(err) } diff --git a/docs/features/required.md b/docs/features/required.md index e1b7092..bd588cd 100644 --- a/docs/features/required.md +++ b/docs/features/required.md @@ -11,7 +11,7 @@ type Config struct { ``` ```go -err := config.Parse(c) +err := config.Parse(context.Background(), c) if errors.Is(err, tinyconf.ErrRequired) { // field DSN: required value is not set; field Password: required value is not set log.Fatal(err) @@ -29,7 +29,7 @@ So a required field without sources can still be filled in the code before `Pars ```go c := &Config{DSN: "postgres://localhost/dev"} -err := config.Parse(c) // DSN is not required to be in the environment +err := config.Parse(context.Background(), c) // DSN is not required to be in the environment ``` ## All at once diff --git a/docs/features/sources.md b/docs/features/sources.md index 1baa1b1..18623c9 100644 --- a/docs/features/sources.md +++ b/docs/features/sources.md @@ -3,7 +3,7 @@ With several drivers it is not always obvious where the final value came from. `Sources` returns which driver has set every field in the last `Parse` call. ```go -if err := config.Parse(c); err != nil { +if err := config.Parse(context.Background(), c); err != nil { panic(err) } for _, source := range config.Sources(c) { diff --git a/docs/features/structs.md b/docs/features/structs.md index a71bb13..449afbc 100644 --- a/docs/features/structs.md +++ b/docs/features/structs.md @@ -77,7 +77,7 @@ The pointer makes the section **optional**: * an existing struct is filled in place, it is not replaced with a new one. ```go -if err := config.Parse(c); err != nil { +if err := config.Parse(context.Background(), c); err != nil { panic(err) } if c.TLS != nil { @@ -102,7 +102,7 @@ if err := config.Register(c); err != nil { // HTTP is a type of the field in the registered Config http := &HTTP{} -if err := config.Parse(http); err != nil { +if err := config.Parse(context.Background(), http); err != nil { panic(err) } ``` diff --git a/docs/index.md b/docs/index.md index 8295447..5adf4b6 100644 --- a/docs/index.md +++ b/docs/index.md @@ -71,7 +71,7 @@ func main() { if err = config.Register(c); err != nil { panic(err) } - if err = config.Parse(c); err != nil { + if err = config.Parse(context.Background(), c); err != nil { panic(err) } fmt.Printf("%+v\n", *c) diff --git a/docs/use-cases.md b/docs/use-cases.md index f06898f..f6e772b 100644 --- a/docs/use-cases.md +++ b/docs/use-cases.md @@ -274,7 +274,7 @@ c := &Config{} if err := config.Register(c); err != nil { panic(err) } -if err := config.Parse(c); err != nil { +if err := config.Parse(context.Background(), c); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(2) } @@ -384,7 +384,7 @@ type Config struct { func New(config *tinyconf.Manager) (*Storage, error) { c := &Config{} - if err := config.Parse(c); err != nil { + if err := config.Parse(context.Background(), c); err != nil { return nil, err } return connect(c) @@ -412,7 +412,7 @@ The package gets a [sub config](features/structs.md#sub-configs): its own fields Check everything at start and report all problems in one message. ```go -if err := config.Parse(c); err != nil { +if err := config.Parse(context.Background(), c); err != nil { if errors.Is(err, tinyconf.ErrRequired) { fmt.Fprintln(os.Stderr, "some required settings are not set") } @@ -436,7 +436,7 @@ c := &Config{} if err := config.Register(c); err != nil { panic(err) } -if err := config.Parse(c); err != nil { +if err := config.Parse(context.Background(), c); err != nil { panic(err) } @@ -485,7 +485,7 @@ if err := config.Register(c); err != nil { if len(os.Args) > 1 && os.Args[1] == "-doc" { // fills the defaults and the values of this environment, // missing required values are not a problem for the template - _ = config.Parse(c) + _ = config.Parse(context.Background(), c) fmt.Println(config.GenDoc("yaml")) fmt.Println(config.GenDoc("env")) return @@ -533,7 +533,7 @@ func newTestConfig(t *testing.T, yamlDoc string, args ...string) *Config { if err := config.Register(c); err != nil { t.Fatal(err) } - if err := config.Parse(c); err != nil { + if err := config.Parse(context.Background(), c); err != nil { t.Fatal(err) } return c diff --git a/docs/why-tinyconf.md b/docs/why-tinyconf.md index 78f8065..2ecd173 100644 --- a/docs/why-tinyconf.md +++ b/docs/why-tinyconf.md @@ -73,7 +73,7 @@ Checked against the current documentation of the libraries on 2026-10-16. | viper `SetDefault("http.port", 8080)` | `initial:"8080"` with the [tag driver](drivers/tag.md) | | viper `AutomaticEnv()` | [`env.WithAutoKeys()`](drivers/env.md#auto-keys) | | viper `WatchConfig()` + `OnConfigChange` | [`tinyconf.Subscribe`](features/reloading.md) per package | -| viper `Sub("http")` | `config.Parse(&HTTP{})` or `tinyconf.Current[HTTP](config)` | +| viper `Sub("http")` | `config.Parse(context.Background(), &HTTP{})` or `tinyconf.Current[HTTP](config)` | | cleanenv `env-default`, `env-required` | `initial:"..."` and `required:"true"` | | cleanenv `env-description` + `Usage` | `doc:"..."` + [`GenDoc("env")`](features/gendoc.md) | | caarlos0/env `envDefault`, `required` | `initial:"..."` and `required:"true"` | diff --git a/drivers/bench_test.go b/drivers/bench_test.go index d73ce72..1216f7b 100644 --- a/drivers/bench_test.go +++ b/drivers/bench_test.go @@ -1,6 +1,7 @@ package drivers_test import ( + "context" "testing" "time" @@ -59,7 +60,7 @@ func BenchmarkParse_Drivers(b *testing.B) { b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { - if err = config.Parse(conf); err != nil { + if err = config.Parse(context.Background(), conf); err != nil { b.Fatal(err) } } diff --git a/drivers/conformance_test.go b/drivers/conformance_test.go index 0d9504c..97106d7 100644 --- a/drivers/conformance_test.go +++ b/drivers/conformance_test.go @@ -2,6 +2,7 @@ package drivers_test import ( "bytes" + "context" "encoding/json" "net" "net/url" @@ -350,7 +351,7 @@ func TestConformance(t *testing.T) { conf := &conformanceConfig{} assert.NoError(t, manager.Register(conf)) - assert.NoError(t, manager.Parse(conf)) + assert.NoError(t, manager.Parse(context.Background(), conf)) expectedOf, confOf := reflect.ValueOf(expected), reflect.ValueOf(*conf) for i := 0; i < expectedOf.NumField(); i++ { @@ -360,13 +361,13 @@ func TestConformance(t *testing.T) { t.Run("sub config", func(t *testing.T) { sub := &conformanceNested{} - assert.NoError(t, manager.Parse(sub)) + assert.NoError(t, manager.Parse(context.Background(), sub)) assert.Equal(t, expected.Nested, *sub) }) t.Run("sub config stored by pointer", func(t *testing.T) { sub := &conformanceNestedPtr{} - assert.NoError(t, manager.Parse(sub)) + assert.NoError(t, manager.Parse(context.Background(), sub)) assert.Equal(t, *expected.NestedPtr, *sub) }) }) @@ -419,7 +420,7 @@ chan: 1 conf := &config{} assert.NoError(t, manager.Register(conf)) - err = manager.Parse(conf) + err = manager.Parse(context.Background(), conf) assert.Error(t, err) for i := 0; i < typeOf.NumField(); i++ { assert.True(t, strings.Contains(err.Error(), "field "+typeOf.Field(i).Name+":"), typeOf.Field(i).Name) diff --git a/drivers/consul/consul.go b/drivers/consul/consul.go index e06fa75..4094514 100644 --- a/drivers/consul/consul.go +++ b/drivers/consul/consul.go @@ -61,7 +61,7 @@ func (d *consulDriver) Load() error { return d.LoadContext(context.Background()) } -// LoadContext is Load with the context of the request, Manager calls it with the context of ParseContext. +// LoadContext is Load with the context of the request, Manager calls it with the context of Parse. func (d *consulDriver) LoadContext(ctx context.Context) error { pairs, index, err := d.client.load(ctx, d.listPrefix(), true) if err != nil { diff --git a/drivers/consul/consul_test.go b/drivers/consul/consul_test.go index 30ff148..97e1797 100644 --- a/drivers/consul/consul_test.go +++ b/drivers/consul/consul_test.go @@ -71,7 +71,7 @@ func TestDriver_Parse(t *testing.T) { manager := newManager(t, driver) conf := &testConfig{} assert.NoError(t, manager.Register(conf)) - assert.NoError(t, manager.Parse(conf)) + assert.NoError(t, manager.Parse(context.Background(), conf)) assert.Equal(t, "app", conf.Name) assert.Equal(t, server{Host: "localhost", Port: 8080}, conf.Server) @@ -268,7 +268,7 @@ func TestDriver_Watch(t *testing.T) { manager := newManager(t, driver) conf := &testConfig{} assert.NoError(t, manager.Register(conf)) - assert.NoError(t, manager.Parse(conf)) + assert.NoError(t, manager.Parse(context.Background(), conf)) ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -312,7 +312,7 @@ func TestDriver_WatchAfterFailedLoad(t *testing.T) { assert.NoError(t, manager.Register(conf)) // Consul is not available at the start consul.setFails(2) - assert.Error(t, manager.Parse(conf)) + assert.Error(t, manager.Parse(context.Background(), conf)) assert.Equal(t, config{}, *conf) ctx, cancel := context.WithCancel(context.Background()) @@ -457,7 +457,7 @@ func TestDocument(t *testing.T) { manager := newManager(t, driver) conf := &config{} assert.NoError(t, manager.Register(conf)) - assert.NoError(t, manager.Parse(conf)) + assert.NoError(t, manager.Parse(context.Background(), conf)) // the document is merged with the file by the yaml tags assert.Equal(t, config{Name: "consul", Server: yamlServer{Host: "localhost", Port: 9090}}, *conf) @@ -483,7 +483,7 @@ func TestDocument_Absent(t *testing.T) { manager := newManager(t, driver) conf := &config{} assert.NoError(t, manager.Register(conf)) - err = manager.Parse(conf) + err = manager.Parse(context.Background(), conf) assert.ErrorIs(t, err, fs.ErrNotExist) assert.ErrorContains(t, err, "failed to load consul key app/config") @@ -491,15 +491,15 @@ func TestDocument_Absent(t *testing.T) { assert.NoError(t, err) manager = newManager(t, driver) assert.NoError(t, manager.Register(conf)) - assert.NoError(t, manager.Parse(conf)) + assert.NoError(t, manager.Parse(context.Background(), conf)) consul.setFails(1) - err = manager.Parse(conf) + err = manager.Parse(context.Background(), conf) assert.ErrorContains(t, err, "500 Internal Server Error") assert.False(t, errors.Is(err, fs.ErrNotExist)) } -func TestDriver_ParseContext(t *testing.T) { +func TestDriver_ParseCancel(t *testing.T) { consul := newFakeConsul(map[string]string{"app/name": "app", "app/config": "name: document\n"}) defer consul.Close() type config struct { @@ -514,13 +514,13 @@ func TestDriver_ParseContext(t *testing.T) { assert.NoError(t, err) conf := &config{} assert.NoError(t, manager.Register(conf)) - assert.NoError(t, manager.ParseContext(context.Background(), conf)) + assert.NoError(t, manager.Parse(context.Background(), conf)) assert.Equal(t, config{Name: "app", Document: "document"}, *conf) - // the requests are stopped by the context of ParseContext + // the requests are stopped by the context of Parse ctx, cancel := context.WithCancel(context.Background()) cancel() - err = manager.ParseContext(ctx, &config{}) + err = manager.Parse(ctx, &config{}) assert.ErrorIs(t, err, context.Canceled) assert.ErrorContains(t, err, "consul driver") assert.ErrorContains(t, err, "yaml driver") diff --git a/drivers/embedded_test.go b/drivers/embedded_test.go index 2d1d67a..d0eb48f 100644 --- a/drivers/embedded_test.go +++ b/drivers/embedded_test.go @@ -1,6 +1,7 @@ package drivers_test import ( + "context" "strings" "testing" @@ -62,7 +63,7 @@ func TestEmbeddedStructs(t *testing.T) { assert.NoError(t, err) conf := &embeddedConfig{} assert.NoError(t, manager.Register(conf)) - assert.NoError(t, manager.Parse(conf)) + assert.NoError(t, manager.Parse(context.Background(), conf)) assert.Equal(t, 1, conf.Port) assert.Equal(t, "app", conf.Name) @@ -99,7 +100,7 @@ func TestEmbeddedStructs_Env(t *testing.T) { assert.NoError(t, err) conf := &config{} assert.NoError(t, manager.Register(conf)) - assert.NoError(t, manager.Parse(conf)) + assert.NoError(t, manager.Parse(context.Background(), conf)) // auto keys are built without the names of the embedded structs assert.Equal(t, 1, conf.Port) diff --git a/drivers/env/env_test.go b/drivers/env/env_test.go index 2cf894f..81d71bf 100644 --- a/drivers/env/env_test.go +++ b/drivers/env/env_test.go @@ -1,6 +1,7 @@ package env import ( + "context" "os" "path" "testing" @@ -422,7 +423,7 @@ func TestEnvDriver_Options(t *testing.T) { t.Setenv("TINYCONF_OPT_HOSTS", "a,b") manager := newManager(t, WithPrefix("TINYCONF_OPT_")) conf := &config{} - assert.NoError(t, manager.Parse(conf)) + assert.NoError(t, manager.Parse(context.Background(), conf)) assert.Equal(t, "localhost", conf.HTTP.Host) assert.Equal(t, []string{"a", "b"}, conf.Hosts) assert.Equal(t, 0, conf.HTTP.MaxConns) @@ -438,7 +439,7 @@ func TestEnvDriver_Options(t *testing.T) { t.Setenv("TINYCONF_OPT_HTTP_HOST", "localhost") manager := newManager(t, WithPrefix("TINYCONF_OPT_"), WithAutoKeys()) conf := &config{} - assert.NoError(t, manager.Parse(conf)) + assert.NoError(t, manager.Parse(context.Background(), conf)) assert.Equal(t, 10, conf.HTTP.MaxConns) assert.Equal(t, "localhost", conf.HTTP.Host) assert.Equal(t, "", conf.HTTP.Excluded) @@ -453,7 +454,7 @@ func TestEnvDriver_Options(t *testing.T) { t.Setenv("HTTP_MAX_CONNS", "10") manager := newManager(t) conf := &config{} - assert.NoError(t, manager.Parse(conf)) + assert.NoError(t, manager.Parse(context.Background(), conf)) assert.Equal(t, 0, conf.HTTP.MaxConns) }) @@ -463,23 +464,23 @@ func TestEnvDriver_Options(t *testing.T) { t.Setenv("TOKEN_FILE", secretPath) conf := &config{} - assert.NoError(t, newManager(t).Parse(conf)) + assert.NoError(t, newManager(t).Parse(context.Background(), conf)) assert.Equal(t, "", conf.Token) manager := newManager(t, WithSecretFiles()) - assert.NoError(t, manager.Parse(conf)) + assert.NoError(t, manager.Parse(context.Background(), conf)) assert.Equal(t, "from file", conf.Token) // variable has priority over file t.Setenv("TOKEN", "from env") - assert.NoError(t, manager.Parse(conf)) + assert.NoError(t, manager.Parse(context.Background(), conf)) assert.Equal(t, "from env", conf.Token) }) t.Run("absent secret file", func(t *testing.T) { t.Setenv("TOKEN_FILE", path.Join(t.TempDir(), "absent")) conf := &config{} - assert.Error(t, newManager(t, WithSecretFiles()).Parse(conf)) + assert.Error(t, newManager(t, WithSecretFiles()).Parse(context.Background(), conf)) }) } @@ -512,7 +513,7 @@ func TestEnvDriver_Files(t *testing.T) { assert.NoError(t, err) conf := &config{} assert.NoError(t, manager.Register(conf)) - assert.NoError(t, manager.Parse(conf)) + assert.NoError(t, manager.Parse(context.Background(), conf)) return *conf } @@ -602,7 +603,7 @@ func TestEnvDriver_IndexedKeys(t *testing.T) { assert.NoError(t, err) conf := &config{} assert.NoError(t, manager.Register(conf)) - err = manager.Parse(conf) + err = manager.Parse(context.Background(), conf) return *conf, err } vars := map[string]string{ @@ -715,7 +716,7 @@ func TestEnvDriver_IndexedKeysEmbedded(t *testing.T) { assert.NoError(t, err) conf := &config{} assert.NoError(t, manager.Register(conf)) - err = manager.Parse(conf) + err = manager.Parse(context.Background(), conf) return *conf, err } diff --git a/drivers/env/example_test.go b/drivers/env/example_test.go index f45d99c..3f4b57b 100644 --- a/drivers/env/example_test.go +++ b/drivers/env/example_test.go @@ -1,6 +1,7 @@ package env_test import ( + "context" "fmt" "os" @@ -40,7 +41,7 @@ func ExampleNew() { if err = config.Register(conf); err != nil { panic(err) } - if err = config.Parse(conf); err != nil { + if err = config.Parse(context.Background(), conf); err != nil { panic(err) } fmt.Printf("%+v\n", *conf) diff --git a/drivers/etcd/etcd.go b/drivers/etcd/etcd.go index dbc08a0..994f786 100644 --- a/drivers/etcd/etcd.go +++ b/drivers/etcd/etcd.go @@ -61,7 +61,7 @@ func (d *etcdDriver) Load() error { return d.LoadContext(context.Background()) } -// LoadContext is Load with the context of the request, Manager calls it with the context of ParseContext. +// LoadContext is Load with the context of the request, Manager calls it with the context of Parse. func (d *etcdDriver) LoadContext(ctx context.Context) error { kvs, revision, err := d.client.get(ctx, d.listPrefix(), true) if err != nil { diff --git a/drivers/etcd/etcd_test.go b/drivers/etcd/etcd_test.go index 090b9ef..41c562d 100644 --- a/drivers/etcd/etcd_test.go +++ b/drivers/etcd/etcd_test.go @@ -53,7 +53,7 @@ func parse(t *testing.T, driver tinyconf.Driver) (*testConfig, *tinyconf.Manager manager := newManager(t, driver) conf := &testConfig{} assert.NoError(t, manager.Register(conf)) - return conf, manager, manager.Parse(conf) + return conf, manager, manager.Parse(context.Background(), conf) } func TestDriver_Parse(t *testing.T) { @@ -191,13 +191,13 @@ func TestDriver_Auth(t *testing.T) { assert.NoError(t, err) assert.Equal(t, "app", conf.Name) // the token is used for the next requests - assert.NoError(t, manager.Parse(conf)) + assert.NoError(t, manager.Parse(context.Background(), conf)) assert.Equal(t, []string{"/v3/auth/authenticate", "/v3/kv/range", "/v3/kv/range"}, requests()) // the expired token is taken again once requests = since() etcd.set(func(f *fakeEtcd) { f.tokens = map[string]bool{} }) - assert.NoError(t, manager.Parse(conf)) + assert.NoError(t, manager.Parse(context.Background(), conf)) assert.Equal(t, []string{"/v3/kv/range", "/v3/auth/authenticate", "/v3/kv/range"}, requests()) // the token is expired and the password is changed @@ -205,7 +205,7 @@ func TestDriver_Auth(t *testing.T) { f.tokens = map[string]bool{} f.users["user"] = "changed" }) - err = manager.Parse(conf) + err = manager.Parse(context.Background(), conf) assert.ErrorIs(t, err, tinyconf.ErrAccessDenied) assert.ErrorContains(t, err, "failed to authenticate user user") @@ -232,7 +232,7 @@ func TestDriver_Endpoints(t *testing.T) { assert.Equal(t, "app", conf.Name) // the endpoint that has answered is used first etcd.Close() - assert.Error(t, manager.Parse(conf)) + assert.Error(t, manager.Parse(context.Background(), conf)) } func TestNewClient(t *testing.T) { @@ -373,7 +373,7 @@ func TestDriver_WatchAfterFailedLoad(t *testing.T) { assert.NoError(t, manager.Register(conf)) // etcd denies the access at the start etcd.set(func(f *fakeEtcd) { f.denied = []string{"app/"} }) - assert.Error(t, manager.Parse(conf)) + assert.Error(t, manager.Parse(context.Background(), conf)) etcd.set(func(f *fakeEtcd) { f.denied = nil }) ctx, cancel := context.WithCancel(context.Background()) @@ -538,7 +538,7 @@ func TestDocument(t *testing.T) { manager := newManager(t, driver) conf := &config{} assert.NoError(t, manager.Register(conf)) - assert.NoError(t, manager.Parse(conf)) + assert.NoError(t, manager.Parse(context.Background(), conf)) // the document is merged with the data by the yaml tags assert.Equal(t, config{Name: "etcd", Server: yamlServer{Host: "localhost", Port: 9090}}, *conf) @@ -557,20 +557,20 @@ func TestDocument(t *testing.T) { } manager = newManager(t, must(yaml.New("", yaml.WithSource(Document("app/absent", WithEndpoints(etcd.URL)))))) assert.NoError(t, manager.Register(&nameConfig{})) - err := manager.Parse(&nameConfig{}) + err := manager.Parse(context.Background(), &nameConfig{}) assert.ErrorIs(t, err, fs.ErrNotExist) assert.ErrorContains(t, err, "failed to load etcd key app/absent") manager = newManager(t, must(yaml.New("", yaml.WithOptional(), yaml.WithSource(Document("app/absent", WithEndpoints(etcd.URL)))))) assert.NoError(t, manager.Register(&nameConfig{})) - assert.NoError(t, manager.Parse(&nameConfig{})) + assert.NoError(t, manager.Parse(context.Background(), &nameConfig{})) etcd.set(func(f *fakeEtcd) { f.denied = []string{"app/absent"} }) - err = manager.Parse(&nameConfig{}) + err = manager.Parse(context.Background(), &nameConfig{}) assert.ErrorIs(t, err, tinyconf.ErrAccessDenied) } -func TestDriver_ParseContext(t *testing.T) { +func TestDriver_ParseCancel(t *testing.T) { etcd := newFakeEtcd(map[string]string{"app/name": "app", "app/config": "name: document\n"}) t.Cleanup(etcd.Close) type config struct { @@ -584,13 +584,13 @@ func TestDriver_ParseContext(t *testing.T) { assert.NoError(t, err) conf := &config{} assert.NoError(t, manager.Register(conf)) - assert.NoError(t, manager.ParseContext(context.Background(), conf)) + assert.NoError(t, manager.Parse(context.Background(), conf)) assert.Equal(t, config{Name: "app", Document: "document"}, *conf) - // the requests are stopped by the context of ParseContext + // the requests are stopped by the context of Parse ctx, cancel := context.WithCancel(context.Background()) cancel() - err = manager.ParseContext(ctx, &config{}) + err = manager.Parse(ctx, &config{}) assert.ErrorIs(t, err, context.Canceled) assert.ErrorContains(t, err, "etcd driver") assert.ErrorContains(t, err, "yaml driver") diff --git a/drivers/flag/example_test.go b/drivers/flag/example_test.go index ef30864..aea0185 100644 --- a/drivers/flag/example_test.go +++ b/drivers/flag/example_test.go @@ -1,6 +1,7 @@ package flag_test import ( + "context" "fmt" "github.com/insei/tinyconf" @@ -26,7 +27,7 @@ func ExampleNew() { if err = config.Register(conf); err != nil { panic(err) } - if err = config.Parse(conf); err != nil { + if err = config.Parse(context.Background(), conf); err != nil { panic(err) } fmt.Printf("%+v\n", *conf) diff --git a/drivers/flag/flag_test.go b/drivers/flag/flag_test.go index 8a628eb..16f3f7e 100644 --- a/drivers/flag/flag_test.go +++ b/drivers/flag/flag_test.go @@ -1,6 +1,7 @@ package flag import ( + "context" "errors" "os" "testing" @@ -98,7 +99,7 @@ func TestFlagDriver_Parse(t *testing.T) { conf := &testConfig{} conf.HTTP.Port = 80 assert.NoError(t, manager.Register(conf)) - assert.NoError(t, manager.Parse(conf)) + assert.NoError(t, manager.Parse(context.Background(), conf)) want := &testConfig{Debug: true, Hosts: []string{"a", "b"}} want.HTTP.Host, want.HTTP.Port = "localhost", 80 diff --git a/drivers/format/example_test.go b/drivers/format/example_test.go index c2b3421..aecda62 100644 --- a/drivers/format/example_test.go +++ b/drivers/format/example_test.go @@ -1,6 +1,7 @@ package format_test import ( + "context" "encoding/json" "fmt" "strings" @@ -41,7 +42,7 @@ func ExampleNew() { if err = config.Register(conf); err != nil { panic(err) } - if err = config.Parse(conf); err != nil { + if err = config.Parse(context.Background(), conf); err != nil { panic(err) } fmt.Println(conf.HTTP.Port) diff --git a/drivers/format/format_test.go b/drivers/format/format_test.go index 6cfa22a..fa466b9 100644 --- a/drivers/format/format_test.go +++ b/drivers/format/format_test.go @@ -64,7 +64,7 @@ func parse(t *testing.T, driver tinyconf.Driver) (*testConfig, *tinyconf.Manager assert.NoError(t, err) conf := &testConfig{} assert.NoError(t, manager.Register(conf)) - return conf, manager, manager.Parse(conf) + return conf, manager, manager.Parse(context.Background(), conf) } func writeFile(t *testing.T, name, content string) string { diff --git a/drivers/ini/ini_test.go b/drivers/ini/ini_test.go index b3308c4..add0138 100644 --- a/drivers/ini/ini_test.go +++ b/drivers/ini/ini_test.go @@ -40,7 +40,7 @@ func parse(t *testing.T, driver tinyconf.Driver) (*testConfig, *tinyconf.Manager assert.NoError(t, err) conf := &testConfig{} assert.NoError(t, manager.Register(conf)) - return conf, manager, manager.Parse(conf) + return conf, manager, manager.Parse(context.Background(), conf) } func TestDecode(t *testing.T) { diff --git a/drivers/internal/tree/tree.go b/drivers/internal/tree/tree.go index fdcd639..fda4179 100644 --- a/drivers/internal/tree/tree.go +++ b/drivers/internal/tree/tree.go @@ -155,7 +155,7 @@ func (d *Driver) Load() error { return d.LoadContext(context.Background()) } -// LoadContext is Load with the context for the remote sources, Manager calls it with the context of ParseContext. +// LoadContext is Load with the context for the remote sources, Manager calls it with the context of Parse. func (d *Driver) LoadContext(ctx context.Context) error { // state is taken before reading, so the changes made during the reading will be detected by Watch state := d.stat(ctx) diff --git a/drivers/json/json_source_test.go b/drivers/json/json_source_test.go index 6fdde5d..3d72a8e 100644 --- a/drivers/json/json_source_test.go +++ b/drivers/json/json_source_test.go @@ -1,6 +1,7 @@ package json import ( + "context" "testing" "github.com/stretchr/testify/assert" @@ -19,6 +20,6 @@ func TestJSONDriver_WithSource(t *testing.T) { assert.NoError(t, err) conf := &config{} assert.NoError(t, manager.Register(conf)) - assert.NoError(t, manager.Parse(conf)) + assert.NoError(t, manager.Parse(context.Background(), conf)) assert.Equal(t, "source", conf.Name) } diff --git a/drivers/json/json_test.go b/drivers/json/json_test.go index 2a61ac7..8de6d89 100644 --- a/drivers/json/json_test.go +++ b/drivers/json/json_test.go @@ -1,6 +1,7 @@ package json import ( + "context" "os" "path/filepath" "testing" @@ -139,7 +140,7 @@ func TestJSONDriver(t *testing.T) { conf, want := &testConfig{}, &testConfig{} tt.want(want) assert.NoError(t, manager.Register(conf)) - err = manager.Parse(conf) + err = manager.Parse(context.Background(), conf) if tt.wantErr { assert.Error(t, err) } else { @@ -190,7 +191,7 @@ func TestJSONDriver_GenDoc(t *testing.T) { assert.NoError(t, err) parsed := &testConfig{} assert.NoError(t, manager.Register(parsed)) - assert.NoError(t, manager.Parse(parsed)) + assert.NoError(t, manager.Parse(context.Background(), parsed)) conf.Password, conf.Skipped = "", "" assert.Equal(t, conf, parsed) }) diff --git a/drivers/json/json_watch_test.go b/drivers/json/json_watch_test.go index 09db123..6a94312 100644 --- a/drivers/json/json_watch_test.go +++ b/drivers/json/json_watch_test.go @@ -24,7 +24,7 @@ func TestJSONDriver_Watch(t *testing.T) { conf := &config{Default: "default"} assert.NoError(t, manager.Register(conf)) - assert.NoError(t, manager.Parse(conf)) + assert.NoError(t, manager.Parse(context.Background(), conf)) ctx, cancel := context.WithCancel(context.Background()) defer cancel() diff --git a/drivers/merge_test.go b/drivers/merge_test.go index c806fb9..f4d7fcb 100644 --- a/drivers/merge_test.go +++ b/drivers/merge_test.go @@ -1,6 +1,7 @@ package drivers_test import ( + "context" "testing" "github.com/stretchr/testify/assert" @@ -28,7 +29,7 @@ func TestMergeTag(t *testing.T) { assert.NoError(t, err) conf := &config{} assert.NoError(t, manager.Register(conf)) - assert.NoError(t, manager.Parse(conf)) + assert.NoError(t, manager.Parse(context.Background(), conf)) // the values of all drivers in the order of the drivers assert.Equal(t, []string{"default", "from-file", "from-env"}, conf.Hosts) assert.Equal(t, map[string]string{"env": "prod", "team": "core", "region": "eu"}, conf.Labels) diff --git a/drivers/properties/properties_test.go b/drivers/properties/properties_test.go index 92714c5..b634d02 100644 --- a/drivers/properties/properties_test.go +++ b/drivers/properties/properties_test.go @@ -36,7 +36,7 @@ func parse(t *testing.T, driver tinyconf.Driver) (*testConfig, *tinyconf.Manager assert.NoError(t, err) conf := &testConfig{} assert.NoError(t, manager.Register(conf)) - return conf, manager, manager.Parse(conf) + return conf, manager, manager.Parse(context.Background(), conf) } func TestDecode(t *testing.T) { diff --git a/drivers/struct_pointers_test.go b/drivers/struct_pointers_test.go index ce2a185..347c8da 100644 --- a/drivers/struct_pointers_test.go +++ b/drivers/struct_pointers_test.go @@ -48,7 +48,7 @@ func TestStructPointers_NoValues(t *testing.T) { conf := &pointersConfig{} assert.NoError(t, manager.Register(conf)) - assert.NoError(t, manager.Parse(conf)) + assert.NoError(t, manager.Parse(context.Background(), conf)) // structs are not created without values assert.Nil(t, conf.Server) } @@ -69,7 +69,7 @@ func TestStructPointers_Parse(t *testing.T) { conf := &pointersConfig{} assert.NoError(t, manager.Register(conf)) - assert.NoError(t, manager.Parse(conf)) + assert.NoError(t, manager.Parse(context.Background(), conf)) assert.Equal(t, pointersConfig{ Name: "app", Server: &pointersServer{ @@ -96,14 +96,14 @@ func TestStructPointers_Parse(t *testing.T) { server, tls := existing.Server, existing.Server.TLS another := newPointersManager(t, tagDriver, yamlDriver, envDriver) assert.NoError(t, another.Register(existing)) - assert.NoError(t, another.Parse(existing)) + assert.NoError(t, another.Parse(context.Background(), existing)) assert.Same(t, server, existing.Server) assert.Same(t, tls, existing.Server.TLS) assert.Equal(t, *conf, *existing) t.Run("sub config", func(t *testing.T) { sub := &pointersTLS{} - assert.NoError(t, manager.Parse(sub)) + assert.NoError(t, manager.Parse(context.Background(), sub)) assert.Equal(t, pointersTLS{Cert: "yaml.pem", Key: "env.key"}, *sub) }) } @@ -122,13 +122,13 @@ func TestStructPointers_Required(t *testing.T) { conf := &config{} assert.NoError(t, manager.Register(conf)) - err = manager.Parse(conf) + err = manager.Parse(context.Background(), conf) assert.ErrorIs(t, err, tinyconf.ErrRequired) assert.ErrorContains(t, err, "DB.DSN") assert.Nil(t, conf.DB) t.Setenv("POINTERS_REQUIRED_DSN", "dsn") - assert.NoError(t, manager.Parse(conf)) + assert.NoError(t, manager.Parse(context.Background(), conf)) assert.Equal(t, &db{DSN: "dsn"}, conf.DB) } @@ -164,7 +164,7 @@ func TestStructPointers_Watch(t *testing.T) { conf := &pointersConfig{} assert.NoError(t, manager.Register(conf)) - assert.NoError(t, manager.Parse(conf)) + assert.NoError(t, manager.Parse(context.Background(), conf)) server, tls := conf.Server, conf.Server.TLS ctx, cancel := context.WithCancel(context.Background()) diff --git a/drivers/toml/toml_source_test.go b/drivers/toml/toml_source_test.go index ea651a5..9d5a4ac 100644 --- a/drivers/toml/toml_source_test.go +++ b/drivers/toml/toml_source_test.go @@ -1,6 +1,7 @@ package toml import ( + "context" "testing" "github.com/stretchr/testify/assert" @@ -19,6 +20,6 @@ func TestTomlDriver_WithSource(t *testing.T) { assert.NoError(t, err) conf := &config{} assert.NoError(t, manager.Register(conf)) - assert.NoError(t, manager.Parse(conf)) + assert.NoError(t, manager.Parse(context.Background(), conf)) assert.Equal(t, "source", conf.Name) } diff --git a/drivers/toml/toml_test.go b/drivers/toml/toml_test.go index ff11f99..67d90b5 100644 --- a/drivers/toml/toml_test.go +++ b/drivers/toml/toml_test.go @@ -1,6 +1,7 @@ package toml import ( + "context" "os" "path/filepath" "testing" @@ -154,7 +155,7 @@ host = "b" conf, want := &testConfig{}, &testConfig{} tt.want(want) assert.NoError(t, manager.Register(conf)) - err = manager.Parse(conf) + err = manager.Parse(context.Background(), conf) if tt.wantErr { assert.Error(t, err) } else { @@ -196,7 +197,7 @@ func TestTOMLDriver_GenDoc(t *testing.T) { assert.NoError(t, err) parsed := &testConfig{} assert.NoError(t, manager.Register(parsed)) - assert.NoError(t, manager.Parse(parsed)) + assert.NoError(t, manager.Parse(context.Background(), parsed)) conf.Password, conf.Skipped = "", "" assert.Equal(t, conf, parsed) }) diff --git a/drivers/toml/toml_watch_test.go b/drivers/toml/toml_watch_test.go index 0ca1341..111590f 100644 --- a/drivers/toml/toml_watch_test.go +++ b/drivers/toml/toml_watch_test.go @@ -24,7 +24,7 @@ func TestTOMLDriver_Watch(t *testing.T) { conf := &config{Default: "default"} assert.NoError(t, manager.Register(conf)) - assert.NoError(t, manager.Parse(conf)) + assert.NoError(t, manager.Parse(context.Background(), conf)) ctx, cancel := context.WithCancel(context.Background()) defer cancel() diff --git a/drivers/vault/vault_test.go b/drivers/vault/vault_test.go index 764c065..f865846 100644 --- a/drivers/vault/vault_test.go +++ b/drivers/vault/vault_test.go @@ -112,7 +112,7 @@ func parse(t *testing.T, driver tinyconf.Driver) (*testConfig, *tinyconf.Manager assert.NoError(t, err) conf := &testConfig{} assert.NoError(t, manager.Register(conf)) - return conf, manager, manager.Parse(conf) + return conf, manager, manager.Parse(context.Background(), conf) } func TestDriver_Parse(t *testing.T) { @@ -260,10 +260,10 @@ func TestDriver_TokenFile(t *testing.T) { // the renewed token is read from the file before every request vault.token = "second" assert.NoError(t, os.WriteFile(tokenFile, []byte("second"), 0o600)) - assert.NoError(t, manager.Parse(&testConfig{})) + assert.NoError(t, manager.Parse(context.Background(), &testConfig{})) assert.NoError(t, os.Remove(tokenFile)) - assert.ErrorContains(t, manager.Parse(&testConfig{}), "failed to read the token") + assert.ErrorContains(t, manager.Parse(context.Background(), &testConfig{}), "failed to read the token") } func TestNewClient(t *testing.T) { @@ -388,7 +388,7 @@ func TestDriver_Watch(t *testing.T) { } } -func TestDriver_ParseContext(t *testing.T) { +func TestDriver_ParseCancel(t *testing.T) { vault := newFakeVault(map[string]map[string]any{"app": {"name": "app"}}) defer vault.Close() driver, err := New("app", WithAddress(vault.URL)) @@ -397,11 +397,11 @@ func TestDriver_ParseContext(t *testing.T) { assert.NoError(t, err) conf := &testConfig{} assert.NoError(t, manager.Register(conf)) - assert.NoError(t, manager.ParseContext(context.Background(), conf)) + assert.NoError(t, manager.Parse(context.Background(), conf)) assert.Equal(t, "app", conf.Name) - // the requests are stopped by the context of ParseContext + // the requests are stopped by the context of Parse ctx, cancel := context.WithCancel(context.Background()) cancel() - assert.ErrorIs(t, manager.ParseContext(ctx, &testConfig{}), context.Canceled) + assert.ErrorIs(t, manager.Parse(ctx, &testConfig{}), context.Canceled) } diff --git a/drivers/yaml/example_test.go b/drivers/yaml/example_test.go index ae9bdd1..5721153 100644 --- a/drivers/yaml/example_test.go +++ b/drivers/yaml/example_test.go @@ -1,6 +1,7 @@ package yaml_test import ( + "context" "fmt" "github.com/insei/tinyconf" @@ -31,7 +32,7 @@ func ExampleNew() { if err = config.Register(conf); err != nil { panic(err) } - if err = config.Parse(conf); err != nil { + if err = config.Parse(context.Background(), conf); err != nil { panic(err) } fmt.Printf("%+v\n", *conf) diff --git a/drivers/yaml/yaml_source_test.go b/drivers/yaml/yaml_source_test.go index b86a344..778aecd 100644 --- a/drivers/yaml/yaml_source_test.go +++ b/drivers/yaml/yaml_source_test.go @@ -1,6 +1,7 @@ package yaml import ( + "context" "testing" "github.com/stretchr/testify/assert" @@ -19,6 +20,6 @@ func TestYamlDriver_WithSource(t *testing.T) { assert.NoError(t, err) conf := &config{} assert.NoError(t, manager.Register(conf)) - assert.NoError(t, manager.Parse(conf)) + assert.NoError(t, manager.Parse(context.Background(), conf)) assert.Equal(t, "source", conf.Name) } diff --git a/drivers/yaml/yaml_test.go b/drivers/yaml/yaml_test.go index 459981c..980d98b 100644 --- a/drivers/yaml/yaml_test.go +++ b/drivers/yaml/yaml_test.go @@ -348,7 +348,7 @@ func TestYamlDriver_Sources(t *testing.T) { conf, want := &config{}, &config{} tt.want(want) assert.NoError(t, manager.Register(conf)) - err = manager.Parse(conf) + err = manager.Parse(context.Background(), conf) if tt.wantErr { assert.Error(t, err) } else { @@ -371,12 +371,12 @@ func TestYamlDriver_Reload(t *testing.T) { conf := &config{} assert.NoError(t, manager.Register(conf)) - assert.NoError(t, manager.Parse(conf)) + assert.NoError(t, manager.Parse(context.Background(), conf)) assert.Equal(t, "first", conf.Name) // file is read again on every Parse assert.NoError(t, os.WriteFile(filePath, []byte("name: second\n"), 0o600)) - assert.NoError(t, manager.Parse(conf)) + assert.NoError(t, manager.Parse(context.Background(), conf)) assert.Equal(t, "second", conf.Name) } @@ -435,7 +435,7 @@ func TestYamlDriver_GenDoc_Types(t *testing.T) { Any any `yaml:"any"` }{} assert.NoError(t, manager.Register(parsed)) - assert.NoError(t, manager.Parse(parsed)) + assert.NoError(t, manager.Parse(context.Background(), parsed)) assert.Equal(t, conf, parsed) }) } @@ -453,7 +453,7 @@ func TestYamlDriver_Watch(t *testing.T) { conf := &config{Default: "default"} assert.NoError(t, manager.Register(conf)) - assert.NoError(t, manager.Parse(conf)) + assert.NoError(t, manager.Parse(context.Background(), conf)) ctx, cancel := context.WithCancel(context.Background()) defer cancel() diff --git a/e2e/consul_test.go b/e2e/consul_test.go index b95e523..7c467ae 100644 --- a/e2e/consul_test.go +++ b/e2e/consul_test.go @@ -161,7 +161,7 @@ func TestConsul(t *testing.T) { manager := newManager(t, driver) conf := &keysConfig{} require.NoError(t, manager.Register(conf)) - require.NoError(t, manager.Parse(conf)) + require.NoError(t, manager.Parse(context.Background(), conf)) assert.Equal(t, keysConfig{ Name: "app", Server: server{Host: "example.com", Port: 9090, Timeout: 90 * time.Second}, @@ -194,7 +194,7 @@ func TestConsul(t *testing.T) { parsed := &keysConfig{} manager = newManager(t, driver) require.NoError(t, manager.Register(parsed)) - require.NoError(t, manager.Parse(parsed)) + require.NoError(t, manager.Parse(context.Background(), parsed)) assert.Equal(t, *conf, *parsed) }) @@ -212,7 +212,7 @@ func TestConsul(t *testing.T) { manager := newManager(t, driver) conf := &config{} require.NoError(t, manager.Register(conf)) - require.NoError(t, manager.Parse(conf)) + require.NoError(t, manager.Parse(context.Background(), conf)) assert.Equal(t, config{Name: "consul", Server: server{Host: "localhost", Port: 9090}}, *conf) // absent document is an error, unless the driver has the optional option @@ -220,7 +220,7 @@ func TestConsul(t *testing.T) { require.NoError(t, err) manager = newManager(t, driver) require.NoError(t, manager.Register(conf)) - assert.ErrorContains(t, manager.Parse(conf), "failed to load consul key document/absent") + assert.ErrorContains(t, manager.Parse(context.Background(), conf), "failed to load consul key document/absent") }) t.Run("watch", func(t *testing.T) { @@ -238,7 +238,7 @@ func TestConsul(t *testing.T) { manager := newManager(t, yamlDriver, consulDriver) conf := &config{} require.NoError(t, manager.Register(conf)) - require.NoError(t, manager.Parse(conf)) + require.NoError(t, manager.Parse(context.Background(), conf)) changes := subscribe[config](t, manager) srv.put(t, "watch/keys/level", "debug") @@ -281,7 +281,7 @@ func TestConsul_ACL(t *testing.T) { manager := newManager(t, driver) conf := &config{} require.NoError(t, manager.Register(conf)) - return conf, manager.Parse(conf) + return conf, manager.Parse(context.Background(), conf) } // Consul answers as if there are no keys, the driver checks the permission @@ -304,7 +304,7 @@ func TestConsul_ACL(t *testing.T) { require.NoError(t, err) manager := newManager(t, driver) require.NoError(t, manager.Register(conf)) - err = manager.Parse(conf) + err = manager.Parse(context.Background(), conf) assert.ErrorIs(t, err, tinyconf.ErrAccessDenied) assert.ErrorContains(t, err, "403 Forbidden") } @@ -336,7 +336,7 @@ func TestConsul_RestartWhileWatching(t *testing.T) { manager := newManager(t, driver) conf := &config{} require.NoError(t, manager.Register(conf)) - require.NoError(t, manager.Parse(conf)) + require.NoError(t, manager.Parse(context.Background(), conf)) changes := subscribe[config](t, manager) // the dev agent keeps the data in memory, after the restart the keys and the indexes start from scratch, @@ -370,7 +370,7 @@ func TestConsul_RestartWhileWatching(t *testing.T) { manager = newManager(t, driver) conf = &config{} require.NoError(t, manager.Register(conf)) - require.Error(t, manager.Parse(conf)) + require.Error(t, manager.Parse(context.Background(), conf)) changes = subscribe[config](t, manager) require.NoError(t, srv.container.Start(ctx)) waitLeader() diff --git a/e2e/etcd_test.go b/e2e/etcd_test.go index 70f6711..0d724b4 100644 --- a/e2e/etcd_test.go +++ b/e2e/etcd_test.go @@ -86,7 +86,7 @@ func parseEtcd(t *testing.T, driver tinyconf.Driver) (*etcdConfig, *tinyconf.Man manager := newManager(t, driver) conf := &etcdConfig{} require.NoError(t, manager.Register(conf)) - return conf, manager, manager.Parse(conf) + return conf, manager, manager.Parse(context.Background(), conf) } func TestEtcd(t *testing.T) { @@ -153,7 +153,7 @@ func TestEtcd(t *testing.T) { manager := newManager(t, driver) conf := &config{} require.NoError(t, manager.Register(conf)) - require.NoError(t, manager.Parse(conf)) + require.NoError(t, manager.Parse(context.Background(), conf)) assert.Equal(t, "etcd", conf.Name) assert.Equal(t, "db", conf.Database.Host) assert.Equal(t, 6432, conf.Database.Port) @@ -248,7 +248,7 @@ func TestEtcd_Cluster(t *testing.T) { } } // the driver reads from the next endpoint - require.NoError(t, manager.Parse(conf)) + require.NoError(t, manager.Parse(context.Background(), conf)) assert.Equal(t, "second", conf.Name) } diff --git a/e2e/vault_test.go b/e2e/vault_test.go index 45afdce..a934bcc 100644 --- a/e2e/vault_test.go +++ b/e2e/vault_test.go @@ -108,7 +108,7 @@ func TestVault(t *testing.T) { manager := newManager(t, driver) conf := &vaultConfig{} require.NoError(t, manager.Register(conf)) - return conf, manager, manager.Parse(conf) + return conf, manager, manager.Parse(context.Background(), conf) } t.Run("secrets merged in the order of the paths", func(t *testing.T) { diff --git a/example/main.go b/example/main.go index 2c3a51e..468ee64 100644 --- a/example/main.go +++ b/example/main.go @@ -77,7 +77,7 @@ func main() { defer stop() parseCtx, cancel := context.WithTimeout(ctx, 10*time.Second) defer cancel() - err := config.ParseContext(parseCtx, conf) + err := config.Parse(parseCtx, conf) if conf.Doc != "" { fmt.Print(config.GenDoc(conf.Doc)) return diff --git a/example_test.go b/example_test.go index 66d70f7..eda9ae2 100644 --- a/example_test.go +++ b/example_test.go @@ -47,7 +47,7 @@ func Example() { if err := config.Register(conf); err != nil { panic(err) } - if err := config.Parse(conf); err != nil { + if err := config.Parse(context.Background(), conf); err != nil { panic(err) } fmt.Printf("%+v\n", *conf) @@ -64,7 +64,7 @@ func ExampleManager_Sources() { if err := config.Register(conf); err != nil { panic(err) } - if err := config.Parse(conf); err != nil { + if err := config.Parse(context.Background(), conf); err != nil { panic(err) } for _, source := range config.Sources(conf) { @@ -86,7 +86,7 @@ func ExampleManager_GenDoc() { if err := config.Register(conf); err != nil { panic(err) } - if err := config.Parse(conf); err != nil { + if err := config.Parse(context.Background(), conf); err != nil { panic(err) } fmt.Print(config.GenDoc("env")) @@ -107,7 +107,7 @@ func ExampleManager_Parse_subConfig() { } http := &HTTP{} - if err := config.Parse(http); err != nil { + if err := config.Parse(context.Background(), http); err != nil { panic(err) } fmt.Printf("%+v\n", *http) @@ -135,7 +135,7 @@ func ExampleSubscribe() { if err = config.Register(conf); err != nil { panic(err) } - if err = config.Parse(conf); err != nil { + if err = config.Parse(context.Background(), conf); err != nil { panic(err) } diff --git a/parser.go b/parser.go index 38614fb..31321f1 100644 --- a/parser.go +++ b/parser.go @@ -211,18 +211,14 @@ func (c *Manager) findSubConfig(confTypeOf reflect.Type) (*Registered, reflect.T // Parse fills the config with values from the drivers, the next driver overrides values of the previous. // Config should be registered, or it should be a field of the registered config (sub config). // +// The context is used by the drivers that read their sources by the network: the requests to the remote storages +// are stopped when ctx is done, the drivers implement ContextLoader. Other drivers do not use the context. +// // All fields are parsed even if some of them has errors, all errors are returned as one error, // it can be checked with errors.Is and errors.As. // Fields with required:"true" tag should have a value from any driver or non-zero value in the config, // otherwise ErrRequired is returned. -func (c *Manager) Parse(conf any) error { - return c.ParseContext(context.Background(), conf) -} - -// ParseContext is Parse with the context for the drivers that read their sources by the network: -// the requests to the remote storages are stopped when ctx is done, the drivers implement ContextLoader. -// Other drivers do not use the context. -func (c *Manager) ParseContext(ctx context.Context, conf any) error { +func (c *Manager) Parse(ctx context.Context, conf any) error { _, err := c.parse(ctx, conf, false) return err } diff --git a/parser_access_test.go b/parser_access_test.go index e94d345..5914080 100644 --- a/parser_access_test.go +++ b/parser_access_test.go @@ -69,7 +69,7 @@ func TestManager_AccessDenied(t *testing.T) { assert.NoError(t, c.Register(conf)) // access denied is logged by its own message and can be checked by errors.Is - err = c.Parse(conf) + err = c.Parse(context.Background(), conf) assert.ErrorIs(t, err, ErrAccessDenied) assert.Equal(t, []string{ "access denied: access denied: no permission to read denied", @@ -78,9 +78,9 @@ func TestManager_AccessDenied(t *testing.T) { logged = nil driver.loadErr = fmt.Errorf("%w: no permission to read the source", ErrAccessDenied) - assert.ErrorIs(t, c.Parse(conf), ErrAccessDenied) + assert.ErrorIs(t, c.Parse(context.Background(), conf), ErrAccessDenied) driver.loadErr = errors.New("source is not available") - assert.Error(t, c.Parse(conf)) + assert.Error(t, c.Parse(context.Background(), conf)) assert.Equal(t, []string{ "access denied: access denied: no permission to read the source", "failed to load: source is not available", diff --git a/parser_context_test.go b/parser_context_test.go index 3b0068d..e06a157 100644 --- a/parser_context_test.go +++ b/parser_context_test.go @@ -29,7 +29,7 @@ func (md *contextLoaderMockDriver) LoadContext(ctx context.Context) error { type contextKey struct{} -func TestManager_ParseContext(t *testing.T) { +func TestManager_ParseCancel(t *testing.T) { type Config struct { Name string } @@ -39,18 +39,18 @@ func TestManager_ParseContext(t *testing.T) { conf := &Config{} assert.NoError(t, c.Register(conf)) - // LoadContext is called instead of Load with the context of ParseContext + // LoadContext is called instead of Load with the context of Parse ctx := context.WithValue(context.Background(), contextKey{}, "value") - assert.NoError(t, c.ParseContext(ctx, conf)) + assert.NoError(t, c.Parse(ctx, conf)) assert.False(t, driver.loaded) assert.Equal(t, "value", driver.context.Value(contextKey{})) // Parse uses the background context - assert.NoError(t, c.Parse(conf)) + assert.NoError(t, c.Parse(context.Background(), conf)) assert.Nil(t, driver.context.Value(contextKey{})) // the canceled context is the error of the driver ctx, cancel := context.WithCancel(context.Background()) cancel() - assert.ErrorIs(t, c.ParseContext(ctx, conf), context.Canceled) + assert.ErrorIs(t, c.Parse(ctx, conf), context.Canceled) } diff --git a/parser_log_test.go b/parser_log_test.go index e256a77..4696fef 100644 --- a/parser_log_test.go +++ b/parser_log_test.go @@ -120,7 +120,7 @@ func TestManager_Parse_Log(t *testing.T) { assert.NoError(t, err) conf := &Config{Host: "initial"} assert.NoError(t, c.Register(conf)) - assert.NoError(t, c.Parse(conf)) + assert.NoError(t, c.Parse(context.Background(), conf)) // initial values of all fields, then every override by every driver assert.Equal(t, []string{ @@ -135,7 +135,7 @@ func TestManager_Parse_Log(t *testing.T) { }, log.take()) // the same values are not overridden - assert.NoError(t, c.Parse(conf)) + assert.NoError(t, c.Parse(context.Background(), conf)) assert.Equal(t, []string{ "initial: config=*tinyconf.Config field=Host value=localhost", "initial: config=*tinyconf.Config field=Port value=9000", @@ -161,7 +161,7 @@ func TestManager_Parse_SubConfigLog(t *testing.T) { // values of the sub config are initial values http := &HTTP{Host: "localhost", Port: 9000} - assert.NoError(t, c.Parse(http)) + assert.NoError(t, c.Parse(context.Background(), http)) assert.Equal(t, HTTP{Host: "localhost", Port: 9000}, *http) assert.Equal(t, []string{ "initial: config=*tinyconf.HTTP field=HTTP.Host value=localhost", @@ -183,7 +183,7 @@ func TestSubscribe_Log(t *testing.T) { assert.NoError(t, err) conf := &Config{} assert.NoError(t, c.Register(conf)) - assert.NoError(t, c.Parse(conf)) + assert.NoError(t, c.Parse(context.Background(), conf)) log.take() configs, _ := subscribe[Config](t, c) diff --git a/parser_merge_test.go b/parser_merge_test.go index 4a9c0c2..bbef54f 100644 --- a/parser_merge_test.go +++ b/parser_merge_test.go @@ -1,6 +1,7 @@ package tinyconf import ( + "context" "testing" "github.com/stretchr/testify/assert" @@ -26,7 +27,7 @@ func TestManager_Parse_Merge(t *testing.T) { // the value of the struct is replaced by the first driver, it is not merged conf := &Config{Hosts: []string{"initial"}} assert.NoError(t, c.Register(conf)) - assert.NoError(t, c.Parse(conf)) + assert.NoError(t, c.Parse(context.Background(), conf)) assert.Equal(t, []string{"a", "b"}, conf.Hosts) assert.Equal(t, map[string]string{"env": "prod", "team": "core"}, conf.Labels) assert.Equal(t, &[]int{80, 443}, conf.Ports) @@ -36,6 +37,6 @@ func TestManager_Parse_Merge(t *testing.T) { assert.Contains(t, log.take(), "override: config=*tinyconf.Config driver=file field=Hosts key=hosts value=[a b]") // the next Parse does not duplicate the items - assert.NoError(t, c.Parse(conf)) + assert.NoError(t, c.Parse(context.Background(), conf)) assert.Equal(t, []string{"a", "b"}, conf.Hosts) } diff --git a/parser_register_test.go b/parser_register_test.go index d6589a1..c401148 100644 --- a/parser_register_test.go +++ b/parser_register_test.go @@ -1,6 +1,7 @@ package tinyconf import ( + "context" "reflect" "testing" @@ -18,11 +19,11 @@ func TestManager_Parse_NotRegistered(t *testing.T) { assert.NoError(t, err) // there are no registered configs - assert.ErrorIs(t, manager.Parse(&other{}), ErrNotRegisteredConfig) + assert.ErrorIs(t, manager.Parse(context.Background(), &other{}), ErrNotRegisteredConfig) // config is not registered and it is not a field of the registered config assert.NoError(t, manager.Register(®istered{})) - assert.ErrorIs(t, manager.Parse(&other{}), ErrNotRegisteredConfig) + assert.ErrorIs(t, manager.Parse(context.Background(), &other{}), ErrNotRegisteredConfig) assert.Nil(t, manager.Sources(&other{})) } diff --git a/parser_test.go b/parser_test.go index 68d1ff0..228f3dc 100644 --- a/parser_test.go +++ b/parser_test.go @@ -379,7 +379,7 @@ func TestManager_ParseSubConfig(t *testing.T) { } conf := &Config{Field: FieldConfig{}} assert.NoError(t, c.Register(conf)) - assert.NoError(t, c.Parse(testCase.config)) + assert.NoError(t, c.Parse(context.Background(), testCase.config)) assert.Equal(t, testCase.expectedFieldValues, testCase.config.Test) assert.Equal(t, testCase.expectedFieldValues, testCase.config.Test2) }) @@ -465,7 +465,7 @@ func TestManager_Parse(t *testing.T) { assert.NoError(t, c.Register(tc.Config)) - _ = c.Parse(tc.Config) + _ = c.Parse(context.Background(), tc.Config) logger := c.log.(*testLogger) @@ -582,7 +582,7 @@ func TestManager_Parse_UncomparableValues(t *testing.T) { conf := &Config{} assert.NoError(t, c.Register(conf)) assert.NotPanics(t, func() { - assert.NoError(t, c.Parse(conf)) + assert.NoError(t, c.Parse(context.Background(), conf)) }) assert.Equal(t, []any{"a", "b"}, conf.List) assert.Equal(t, map[string]any{"a": 1}, conf.Map) @@ -605,7 +605,7 @@ func TestManager_Parse_InvalidConfig(t *testing.T) { c := newPathMockManager(&pathMockDriver{values: map[string]any{"Test": "test"}}) assert.NoError(t, c.Register(&Config{})) assert.NotPanics(t, func() { - assert.Error(t, c.Parse(testCase.Config)) + assert.Error(t, c.Parse(context.Background(), testCase.Config)) }) }) } @@ -634,7 +634,7 @@ func TestManager_Parse_DriverErrors(t *testing.T) { }) conf := &Config{} assert.NoError(t, c.Register(conf)) - err := c.Parse(conf) + err := c.Parse(context.Background(), conf) if testCase.WantError { assert.ErrorIs(t, err, driverErr) assert.Contains(t, err.Error(), "Port") @@ -682,7 +682,7 @@ func TestManager_ParseSubConfig_SiblingPrefix(t *testing.T) { c := newPathMockManager(testCase.Driver) assert.NoError(t, c.Register(&Config{})) conf := &HTTP{} - assert.NoError(t, c.Parse(conf)) + assert.NoError(t, c.Parse(context.Background(), conf)) assert.Equal(t, 1, conf.Port) }) } @@ -701,7 +701,7 @@ func TestManager_ParseSubConfig_RepeatedName(t *testing.T) { c := newPathMockManager(&pathMockDriver{values: map[string]any{"Auth.Auth.Token": "token"}}) assert.NoError(t, c.Register(&Config{})) conf := &Auth{} - assert.NoError(t, c.Parse(conf)) + assert.NoError(t, c.Parse(context.Background(), conf)) assert.Equal(t, "token", conf.Auth.Token) } @@ -716,7 +716,7 @@ func TestManager_ParseSubConfig_ZeroValue(t *testing.T) { c := newPathMockManager(&pathMockDriver{values: map[string]any{"HTTP.Host": "", "HTTP.Port": 0}}) assert.NoError(t, c.Register(&Config{})) conf := &HTTP{Host: "default", Port: 8080} - assert.NoError(t, c.Parse(conf)) + assert.NoError(t, c.Parse(context.Background(), conf)) assert.Equal(t, "", conf.Host) assert.Equal(t, 0, conf.Port) } @@ -785,7 +785,7 @@ func TestManager_Parse_Types(t *testing.T) { c := newPathMockManager(driver) conf := &Config{} assert.NoError(t, c.Register(conf)) - assert.NoError(t, c.Parse(conf)) + assert.NoError(t, c.Parse(context.Background(), conf)) assert.Equal(t, expected, *conf) // fields of the types that are parsed from a single value are not requested from drivers assert.NotContains(t, driver.requested, "At.wall") @@ -795,7 +795,7 @@ func TestManager_Parse_Types(t *testing.T) { t.Run("sub config", func(t *testing.T) { sub := &Nested{} - assert.NoError(t, c.Parse(sub)) + assert.NoError(t, c.Parse(context.Background(), sub)) assert.Equal(t, expected.Nested, *sub) }) } @@ -833,14 +833,14 @@ func TestManager_Parse_Loader(t *testing.T) { conf := &Config{} assert.NoError(t, c.Register(conf)) - err := c.Parse(conf) + err := c.Parse(context.Background(), conf) assert.ErrorIs(t, err, loadErr) assert.True(t, c.log.(*testLogger).ErrorLogged) // values of the failed driver are not used assert.Equal(t, Config{Host: "localhost", Port: 80}, *conf) assert.Empty(t, failed.requested) - assert.Error(t, c.Parse(conf)) + assert.Error(t, c.Parse(context.Background(), conf)) // Load is called once per Parse assert.Equal(t, 2, loaded.loaded) assert.Equal(t, 2, failed.loaded) @@ -923,7 +923,7 @@ func TestManager_Parse_Required(t *testing.T) { c := newPathMockManager(&pathMockDriver{values: testCase.Values}) conf := testCase.Config assert.NoError(t, c.Register(&conf)) - err := c.Parse(&conf) + err := c.Parse(context.Background(), &conf) if len(testCase.Missing) == 0 { assert.NoError(t, err) } else { @@ -936,7 +936,7 @@ func TestManager_Parse_Required(t *testing.T) { t.Run("sub config", func(t *testing.T) { sub := testCase.Config.HTTP - err := c.Parse(&sub) + err := c.Parse(context.Background(), &sub) var missing []string for _, path := range testCase.Missing { if strings.HasPrefix(path, "HTTP.") { @@ -983,7 +983,7 @@ func TestManager_Sources(t *testing.T) { assert.NoError(t, c.Register(conf)) assert.Nil(t, c.Sources(conf)) - assert.NoError(t, c.Parse(conf)) + assert.NoError(t, c.Parse(context.Background(), conf)) expected := []FieldSource{ {Field: "Name", Driver: "first", Source: "first:Name"}, {Field: "HTTP.Host", Driver: "first", Source: "first:HTTP.Host"}, @@ -999,7 +999,7 @@ func TestManager_Sources(t *testing.T) { t.Run("sub config", func(t *testing.T) { sub := &HTTP{} assert.Nil(t, c.Sources(sub)) - assert.NoError(t, c.Parse(sub)) + assert.NoError(t, c.Parse(context.Background(), sub)) assert.Equal(t, []FieldSource{ {Field: "Host", Driver: "first", Source: "first:HTTP.Host"}, {Field: "Port", Driver: "second", Source: "second:HTTP.Port"}, @@ -1010,7 +1010,7 @@ func TestManager_Sources(t *testing.T) { t.Run("sources are updated by the next parse", func(t *testing.T) { delete(second.values, "HTTP.Port") first.errs["Name"] = errors.New("random error") - assert.Error(t, c.Parse(conf)) + assert.Error(t, c.Parse(context.Background(), conf)) assert.Equal(t, []FieldSource{ {Field: "HTTP.Host", Driver: "first", Source: "first:HTTP.Host"}, {Field: "HTTP.Port", Driver: "first", Source: "first:HTTP.Port"}, @@ -1058,7 +1058,7 @@ func TestManager_RegistrationOrder(t *testing.T) { // sub config is parsed from the first registered config with this type sub := &Shared{} - assert.NoError(t, c.Parse(sub)) + assert.NoError(t, c.Parse(context.Background(), sub)) assert.Equal(t, "nested", sub.Value) assert.Equal(t, []string{"Nested.Shared.Value"}, driver.requested) @@ -1087,8 +1087,8 @@ func TestManager_Concurrency(t *testing.T) { conf, sub := &Config{}, &HTTP{} assert.NoError(t, c.Register(&struct{ Other string }{})) assert.NoError(t, c.Register(conf)) - assert.NoError(t, c.Parse(conf)) - assert.NoError(t, c.Parse(sub)) + assert.NoError(t, c.Parse(context.Background(), conf)) + assert.NoError(t, c.Parse(context.Background(), sub)) assert.Equal(t, "static", conf.HTTP.Host) assert.Equal(t, "static", sub.Host) assert.Len(t, c.Sources(conf), 1) diff --git a/parser_warning_test.go b/parser_warning_test.go index 1d96295..592996a 100644 --- a/parser_warning_test.go +++ b/parser_warning_test.go @@ -1,6 +1,7 @@ package tinyconf import ( + "context" "testing" "github.com/insei/fmap/v3" @@ -48,7 +49,7 @@ func TestManager_Parse_ValueWarning(t *testing.T) { assert.NoError(t, err) conf := &Config{} assert.NoError(t, c.Register(conf)) - assert.NoError(t, c.Parse(conf)) + assert.NoError(t, c.Parse(context.Background(), conf)) // the value is set, the warning of the driver is logged assert.Equal(t, Config{Usual: "value", Suspicious: "value"}, *conf) diff --git a/secret_test.go b/secret_test.go index a80157e..77b2bd5 100644 --- a/secret_test.go +++ b/secret_test.go @@ -1,6 +1,7 @@ package tinyconf import ( + "context" "encoding/json" "fmt" "testing" @@ -58,7 +59,7 @@ func TestSecret_Parse(t *testing.T) { assert.NoError(t, err) conf := &secretConfig{} assert.NoError(t, c.Register(conf)) - assert.NoError(t, c.Parse(conf)) + assert.NoError(t, c.Parse(context.Background(), conf)) assert.Equal(t, Secret("password value"), conf.Password) assert.Equal(t, []Secret{"first", "second"}, conf.Keys) } diff --git a/status_test.go b/status_test.go index 34c8945..f502b8e 100644 --- a/status_test.go +++ b/status_test.go @@ -16,7 +16,7 @@ func TestManager_ReloadStatus(t *testing.T) { assert.NoError(t, err) conf := &subConfig{} assert.NoError(t, c.Register(conf)) - assert.NoError(t, c.Parse(conf)) + assert.NoError(t, c.Parse(context.Background(), conf)) assert.Equal(t, ReloadStatus{}, c.ReloadStatus()) ctx, cancel := context.WithCancel(context.Background()) diff --git a/subscribe_test.go b/subscribe_test.go index 915ed02..8253cd2 100644 --- a/subscribe_test.go +++ b/subscribe_test.go @@ -74,7 +74,7 @@ func TestSubscribe(t *testing.T) { assert.NoError(t, err) conf := &subConfig{Default: "default"} assert.NoError(t, c.Register(conf)) - assert.NoError(t, c.Parse(conf)) + assert.NoError(t, c.Parse(context.Background(), conf)) configs, _ := subscribe[subConfig](t, c) https, _ := subscribe[subHTTP](t, c) @@ -147,7 +147,7 @@ func TestSubscribe_Parse(t *testing.T) { configs, _ := subscribe[subConfig](t, c) // Parse updates the current version without the handlers - assert.NoError(t, c.Parse(conf)) + assert.NoError(t, c.Parse(context.Background(), conf)) nothing(t, configs) current := Current[subConfig](c) assert.Equal(t, "first", current.Name) @@ -159,7 +159,7 @@ func TestSubscribe_Parse(t *testing.T) { // Parse of the sub config does not change the current version file.values = map[string]any{"HTTP.Host": "b"} http := &subHTTP{} - assert.NoError(t, c.Parse(http)) + assert.NoError(t, c.Parse(context.Background(), http)) assert.Equal(t, "b", http.Host) assert.Equal(t, "a", Current[subHTTP](c).Host) } @@ -270,7 +270,7 @@ func TestSubscribe_LoggedErrors(t *testing.T) { assert.NoError(t, err) conf := &subConfig{} assert.NoError(t, c.Register(conf)) - assert.NoError(t, c.Parse(conf)) + assert.NoError(t, c.Parse(context.Background(), conf)) ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -301,7 +301,7 @@ func TestManager_reload(t *testing.T) { assert.NoError(t, err) conf := &subConfig{} assert.NoError(t, c.Register(conf)) - assert.NoError(t, c.Parse(conf)) + assert.NoError(t, c.Parse(context.Background(), conf)) called := false ctx, cancel := context.WithCancel(context.Background()) cancel() diff --git a/types.go b/types.go index 7deaa53..2b97605 100644 --- a/types.go +++ b/types.go @@ -86,7 +86,7 @@ type Loader interface { } // ContextLoader is an optional interface of the driver that reads its source by the network, a remote storage for example. -// Manager calls LoadContext instead of Load with the context of ParseContext, or with the context of watching for reloads, +// Manager calls LoadContext instead of Load with the context of Parse, or with the context of watching for reloads, // the driver should stop the requests when the context is done. type ContextLoader interface { LoadContext(ctx context.Context) error diff --git a/types_test.go b/types_test.go index 0c5e925..7198f1b 100644 --- a/types_test.go +++ b/types_test.go @@ -1,6 +1,7 @@ package tinyconf import ( + "context" "errors" "fmt" "testing" @@ -58,5 +59,5 @@ func TestManager_StorageErrors(t *testing.T) { } assert.ErrorIs(t, manager.Register(&Other{}), storageErr) // fields of the sub config are not found - assert.ErrorIs(t, manager.Parse(&Sub{}), storageErr) + assert.ErrorIs(t, manager.Parse(context.Background(), &Sub{}), storageErr) }