From 089c0985d82df6756b16e67349f05763d37002fd Mon Sep 17 00:00:00 2001 From: bbland1 <104288486+bbland1@users.noreply.github.com> Date: Fri, 21 Feb 2025 15:44:38 -0500 Subject: [PATCH 01/24] feat(multi-provider): set up multi-provider directory Signed-off-by: bbland1 <104288486+bbland1@users.noreply.github.com> --- providers/multi-provider/README.md | 0 providers/multi-provider/go.mod | 5 +++++ providers/multi-provider/go.sum | 2 ++ release-please-config.json | 8 ++++++++ 4 files changed, 15 insertions(+) create mode 100644 providers/multi-provider/README.md create mode 100644 providers/multi-provider/go.mod create mode 100644 providers/multi-provider/go.sum diff --git a/providers/multi-provider/README.md b/providers/multi-provider/README.md new file mode 100644 index 000000000..e69de29bb diff --git a/providers/multi-provider/go.mod b/providers/multi-provider/go.mod new file mode 100644 index 000000000..100a1b2e5 --- /dev/null +++ b/providers/multi-provider/go.mod @@ -0,0 +1,5 @@ +module github.com/open-feature/go-sdk-contrib/providers/multi-provider + +go 1.23.0 + +require github.com/open-feature/go-sdk v1.14.1 // indirect diff --git a/providers/multi-provider/go.sum b/providers/multi-provider/go.sum new file mode 100644 index 000000000..675e06c68 --- /dev/null +++ b/providers/multi-provider/go.sum @@ -0,0 +1,2 @@ +github.com/open-feature/go-sdk v1.14.1 h1:jcxjCIG5Up3XkgYwWN5Y/WWfc6XobOhqrIwjyDBsoQo= +github.com/open-feature/go-sdk v1.14.1/go.mod h1:t337k0VB/t/YxJ9S0prT30ISUHwYmUd/jhUZgFcOvGg= diff --git a/release-please-config.json b/release-please-config.json index ee5b1b009..d1b4c7301 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -139,6 +139,14 @@ "bump-patch-for-minor-pre-major": true, "versioning": "default", "extra-files": [] + }, + "providers/multi-provider": { + "release-type": "go", + "package-name": "providers/multi-provider", + "bump-minor-pre-major": true, + "bump-patch-for-minor-pre-major": true, + "versioning": "default", + "extra-files": [] } }, "changelog-sections": [ From b8275dfeb9b6fd10c781db80ac1d837c82e14af9 Mon Sep 17 00:00:00 2001 From: bbland1 <104288486+bbland1@users.noreply.github.com> Date: Fri, 21 Feb 2025 23:31:02 -0500 Subject: [PATCH 02/24] feat: set up func to create new multiprovider & register passed providers Signed-off-by: bbland1 <104288486+bbland1@users.noreply.github.com> --- providers/multi-provider/go.mod | 7 +- providers/multi-provider/go.sum | 8 ++ providers/multi-provider/providers.go | 88 ++++++++++++++++++++++ providers/multi-provider/providers_test.go | 1 + 4 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 providers/multi-provider/providers.go create mode 100644 providers/multi-provider/providers_test.go diff --git a/providers/multi-provider/go.mod b/providers/multi-provider/go.mod index 100a1b2e5..91a059021 100644 --- a/providers/multi-provider/go.mod +++ b/providers/multi-provider/go.mod @@ -2,4 +2,9 @@ module github.com/open-feature/go-sdk-contrib/providers/multi-provider go 1.23.0 -require github.com/open-feature/go-sdk v1.14.1 // indirect +require github.com/open-feature/go-sdk v1.14.1 + +require ( + github.com/go-logr/logr v1.4.2 // indirect + golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect +) diff --git a/providers/multi-provider/go.sum b/providers/multi-provider/go.sum index 675e06c68..ac0b45fa2 100644 --- a/providers/multi-provider/go.sum +++ b/providers/multi-provider/go.sum @@ -1,2 +1,10 @@ +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/open-feature/go-sdk v1.14.1 h1:jcxjCIG5Up3XkgYwWN5Y/WWfc6XobOhqrIwjyDBsoQo= github.com/open-feature/go-sdk v1.14.1/go.mod h1:t337k0VB/t/YxJ9S0prT30ISUHwYmUd/jhUZgFcOvGg= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= diff --git a/providers/multi-provider/providers.go b/providers/multi-provider/providers.go new file mode 100644 index 000000000..9ec018a1c --- /dev/null +++ b/providers/multi-provider/providers.go @@ -0,0 +1,88 @@ +package multiprovider + +import ( + "errors" + "fmt" + + of "github.com/open-feature/go-sdk/openfeature" +) + +var ( + errUniqueName = errors.New("Provider names must be unique.") +) + +// UniqueNameProvider allows for a unique name to be assigned to a provider during a multi-provider set up. +// The name will be used when reporting errors & results to specify the provider associated. +type UniqueNameProvider struct { + Provider of.FeatureProvider + Name string +} + +type MultiMetadata struct { + Name string + OriginalMetadata map[string]of.Metadata +} + +// MultiProvider implements openfeature `FeatureProvider` in a way to accept an array of providers. +type MultiProvider struct { + providersEntries []UniqueNameProvider + providersEntriesByName map[string]UniqueNameProvider + AggregatedMetadata map[string]of.Metadata +} + +func NewMultiProvider(providers []UniqueNameProvider) (*MultiProvider, error) { + multiProvider := &MultiProvider{ + providersEntries: []UniqueNameProvider{}, + providersEntriesByName: map[string]UniqueNameProvider{}, + } + // for i, provider := range providers { + + // } + + // + + return multiProvider, nil +} + +func (mp MultiProvider) Metadata() of.Metadata { + + return of.Metadata{ + Name: fmt.Sprintf("multiprovider"), + } +} + +// registerProviders ensures that when setting up an instant of MultiProvider the providers provided either have a unique name or the base `metadata.Name` is made unique by adding an indexed based number to it. +// registerProviders also stores the providers by their unique name and in an array for easy usage. +func registerProviders(mp *MultiProvider, providers []UniqueNameProvider) error { + providersByName := make(map[string][]UniqueNameProvider) + + for _, provider := range providers { + uniqueName := provider.Name + + if _, exists := providersByName[uniqueName]; exists { + return errUniqueName + } + + if uniqueName == "" { + providersByName[provider.Provider.Metadata().Name] = append(providersByName[provider.Provider.Metadata().Name], provider) + } else { + providersByName[uniqueName] = append(providersByName[uniqueName], provider) + } + } + + for name, providers := range providersByName { + if len(providers) == 1 { + mp.providersEntries = append(mp.providersEntries, providers[0]) + mp.providersEntriesByName[name] = providers[0] + mp.AggregatedMetadata[name] = providers[0].Provider.Metadata() + } else { + for i, provider := range providers { + uniqueName := fmt.Sprintf("%s-%d", name, i+1) + mp.providersEntries = append(mp.providersEntries, provider) + mp.providersEntriesByName[uniqueName] = provider + mp.AggregatedMetadata[uniqueName] = provider.Provider.Metadata() + } + } + } + return nil +} diff --git a/providers/multi-provider/providers_test.go b/providers/multi-provider/providers_test.go new file mode 100644 index 000000000..c7735289c --- /dev/null +++ b/providers/multi-provider/providers_test.go @@ -0,0 +1 @@ +package multiprovider \ No newline at end of file From 6ef2dd88a720da5e7dcbcbfd8a0295595aa01649 Mon Sep 17 00:00:00 2001 From: bbland1 <104288486+bbland1@users.noreply.github.com> Date: Sat, 22 Feb 2025 16:41:10 -0500 Subject: [PATCH 03/24] feat: added Metadata Method to the multiprovider Signed-off-by: bbland1 <104288486+bbland1@users.noreply.github.com> --- providers/multi-provider/providers.go | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/providers/multi-provider/providers.go b/providers/multi-provider/providers.go index 9ec018a1c..79f06ed47 100644 --- a/providers/multi-provider/providers.go +++ b/providers/multi-provider/providers.go @@ -18,6 +18,7 @@ type UniqueNameProvider struct { Name string } +// MultiMetadata defines the return of the MultiProvider metadata with the aggregated data of all the providers. type MultiMetadata struct { Name string OriginalMetadata map[string]of.Metadata @@ -30,24 +31,27 @@ type MultiProvider struct { AggregatedMetadata map[string]of.Metadata } -func NewMultiProvider(providers []UniqueNameProvider) (*MultiProvider, error) { +func NewMultiProvider(passedProviders []UniqueNameProvider) (*MultiProvider, error) { multiProvider := &MultiProvider{ providersEntries: []UniqueNameProvider{}, providersEntriesByName: map[string]UniqueNameProvider{}, + AggregatedMetadata: map[string]of.Metadata{}, } - // for i, provider := range providers { - // } - - // + err := registerProviders(multiProvider, passedProviders) + if err != nil { + return nil, err + } return multiProvider, nil } -func (mp MultiProvider) Metadata() of.Metadata { +// Metadata provides the name `multiprovider` and the names of each provider passed. +func (mp MultiProvider) Metadata() MultiMetadata { - return of.Metadata{ - Name: fmt.Sprintf("multiprovider"), + return MultiMetadata{ + Name: "multiprovider", + OriginalMetadata: mp.AggregatedMetadata, } } From 63a5300b8bb6b782cabe622a536d8dd5e5d58056 Mon Sep 17 00:00:00 2001 From: bbland1 <104288486+bbland1@users.noreply.github.com> Date: Tue, 25 Feb 2025 01:36:19 -0500 Subject: [PATCH 04/24] feat: added the based of the Init method that will process the initalize of the providers Signed-off-by: bbland1 <104288486+bbland1@users.noreply.github.com> --- .release-please-manifest.json | 3 +- providers/multi-provider/providers.go | 57 +++++++++++++++++++++++++-- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 581add0bd..8f27a29b3 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -15,5 +15,6 @@ "providers/ofrep": "0.1.5", "providers/prefab": "0.0.2", "tests/flagd": "1.4.1", - "providers/go-feature-flag-in-process": "0.1.0" + "providers/go-feature-flag-in-process": "0.1.0", + "providers/multi-provider": "0.0.1" } diff --git a/providers/multi-provider/providers.go b/providers/multi-provider/providers.go index 79f06ed47..6d63ce306 100644 --- a/providers/multi-provider/providers.go +++ b/providers/multi-provider/providers.go @@ -3,6 +3,7 @@ package multiprovider import ( "errors" "fmt" + "sync" of "github.com/open-feature/go-sdk/openfeature" ) @@ -29,13 +30,17 @@ type MultiProvider struct { providersEntries []UniqueNameProvider providersEntriesByName map[string]UniqueNameProvider AggregatedMetadata map[string]of.Metadata + EvaluationStrategy string + event chan of.Event + status of.State + mu sync.Mutex } -func NewMultiProvider(passedProviders []UniqueNameProvider) (*MultiProvider, error) { +func NewMultiProvider(passedProviders []UniqueNameProvider, evaluationStrategy string) (*MultiProvider, error) { multiProvider := &MultiProvider{ providersEntries: []UniqueNameProvider{}, providersEntriesByName: map[string]UniqueNameProvider{}, - AggregatedMetadata: map[string]of.Metadata{}, + AggregatedMetadata: map[string]of.Metadata{}, } err := registerProviders(multiProvider, passedProviders) @@ -43,6 +48,11 @@ func NewMultiProvider(passedProviders []UniqueNameProvider) (*MultiProvider, err return nil, err } + // err = multiProvider.initialize() + // if err != nil { + // return nil, err + // } + return multiProvider, nil } @@ -50,7 +60,7 @@ func NewMultiProvider(passedProviders []UniqueNameProvider) (*MultiProvider, err func (mp MultiProvider) Metadata() MultiMetadata { return MultiMetadata{ - Name: "multiprovider", + Name: "multiprovider", OriginalMetadata: mp.AggregatedMetadata, } } @@ -90,3 +100,44 @@ func registerProviders(mp *MultiProvider, providers []UniqueNameProvider) error } return nil } + +type InitError struct { + ProviderName string + Error error +} + +// Init will run the initialize method for all of provides and aggregate the errors. +func (mp *MultiProvider) Init(evalCtx of.EvaluationContext) error { + var wg sync.WaitGroup + + errChan := make(chan InitError, len(mp.providersEntries)) + for _, provider := range mp.providersEntries { + wg.Add(1) + go func(p UniqueNameProvider) { + defer wg.Done() + if initMethod, ok := p.Provider.(of.StateHandler); ok { + if err := initMethod.Init(evalCtx); err != nil { + errChan <- InitError{ProviderName: p.Name, Error: err} + } + } + }(provider) + } + + wg.Wait() + close(errChan) + + + return nil +} + +func (mp *MultiProvider) Status() of.State { + return of.ReadyState +} + +func (mp *MultiProvider) Shutdown() { + +} + +func (mp *MultiProvider) EventChannel() <-chan of.Event { + return +} From ac9ab37c45c13b5bba995643da6f1b1039709934 Mon Sep 17 00:00:00 2001 From: bbland1 <104288486+bbland1@users.noreply.github.com> Date: Wed, 26 Feb 2025 12:26:36 -0500 Subject: [PATCH 05/24] moved providers into pkg directory Signed-off-by: bbland1 <104288486+bbland1@users.noreply.github.com> --- providers/multi-provider/{ => pkg}/providers.go | 11 +++++++---- providers/multi-provider/{ => pkg}/providers_test.go | 0 2 files changed, 7 insertions(+), 4 deletions(-) rename providers/multi-provider/{ => pkg}/providers.go (95%) rename providers/multi-provider/{ => pkg}/providers_test.go (100%) diff --git a/providers/multi-provider/providers.go b/providers/multi-provider/pkg/providers.go similarity index 95% rename from providers/multi-provider/providers.go rename to providers/multi-provider/pkg/providers.go index 6d63ce306..704612881 100644 --- a/providers/multi-provider/providers.go +++ b/providers/multi-provider/pkg/providers.go @@ -31,7 +31,7 @@ type MultiProvider struct { providersEntriesByName map[string]UniqueNameProvider AggregatedMetadata map[string]of.Metadata EvaluationStrategy string - event chan of.Event + events chan of.Event status of.State mu sync.Mutex } @@ -57,7 +57,7 @@ func NewMultiProvider(passedProviders []UniqueNameProvider, evaluationStrategy s } // Metadata provides the name `multiprovider` and the names of each provider passed. -func (mp MultiProvider) Metadata() MultiMetadata { +func (mp *MultiProvider) Metadata() MultiMetadata { return MultiMetadata{ Name: "multiprovider", @@ -103,7 +103,7 @@ func registerProviders(mp *MultiProvider, providers []UniqueNameProvider) error type InitError struct { ProviderName string - Error error + Error error } // Init will run the initialize method for all of provides and aggregate the errors. @@ -126,6 +126,8 @@ func (mp *MultiProvider) Init(evalCtx of.EvaluationContext) error { wg.Wait() close(errChan) + // var errors []InitError + return nil } @@ -139,5 +141,6 @@ func (mp *MultiProvider) Shutdown() { } func (mp *MultiProvider) EventChannel() <-chan of.Event { - return + ev := make(chan of.Event) + return ev } diff --git a/providers/multi-provider/providers_test.go b/providers/multi-provider/pkg/providers_test.go similarity index 100% rename from providers/multi-provider/providers_test.go rename to providers/multi-provider/pkg/providers_test.go From 65e2f0477e707bf2b6cbe1925267fa70c8c3e407 Mon Sep 17 00:00:00 2001 From: bbland1 <104288486+bbland1@users.noreply.github.com> Date: Thu, 27 Feb 2025 01:46:06 -0500 Subject: [PATCH 06/24] added Init method to handle any providers with intialization Signed-off-by: bbland1 <104288486+bbland1@users.noreply.github.com> --- .../internal/aggregate-errors.go | 30 +++++++++++++ providers/multi-provider/pkg/providers.go | 42 ++++++++++++------- .../multi-provider/pkg/providers_test.go | 6 ++- 3 files changed, 61 insertions(+), 17 deletions(-) create mode 100644 providers/multi-provider/internal/aggregate-errors.go diff --git a/providers/multi-provider/internal/aggregate-errors.go b/providers/multi-provider/internal/aggregate-errors.go new file mode 100644 index 000000000..c4d3e772f --- /dev/null +++ b/providers/multi-provider/internal/aggregate-errors.go @@ -0,0 +1,30 @@ +package internal + +import "fmt" + +// InitError is how the error in the Init stage of a provider is reported. +type InitError struct { + ProviderName string + Err error +} + +func (e *InitError) Error() string { + return fmt.Sprintf("Provider %s had an error: %v", e.ProviderName, e.Err) +} + +type AggregateError struct { + Message string + Errors []InitError +} + +func (ae *AggregateError) Error() string { + return ae.Message +} + +func (ae *AggregateError) Construct(providerErrors []InitError) { + // Show first error message for convenience, but all errors in the object + msg := fmt.Sprintf("Provider errors occurred: %s: %v", providerErrors[0].ProviderName, providerErrors[0].Err) + + ae.Message = msg + ae.Errors = providerErrors +} \ No newline at end of file diff --git a/providers/multi-provider/pkg/providers.go b/providers/multi-provider/pkg/providers.go index 704612881..770d101d2 100644 --- a/providers/multi-provider/pkg/providers.go +++ b/providers/multi-provider/pkg/providers.go @@ -5,7 +5,10 @@ import ( "fmt" "sync" + err "github.com/open-feature/go-sdk-contrib/providers/multi-provider/internal" + of "github.com/open-feature/go-sdk/openfeature" + ofhooks "github.com/open-feature/go-sdk/openfeature/hooks" ) var ( @@ -36,7 +39,8 @@ type MultiProvider struct { mu sync.Mutex } -func NewMultiProvider(passedProviders []UniqueNameProvider, evaluationStrategy string) (*MultiProvider, error) { +// NewMultiProvider returns the unified interface of multiple providers for interaction. +func NewMultiProvider(passedProviders []UniqueNameProvider, evaluationStrategy string, logger ofhooks.LoggingHook) (*MultiProvider, error) { multiProvider := &MultiProvider{ providersEntries: []UniqueNameProvider{}, providersEntriesByName: map[string]UniqueNameProvider{}, @@ -48,10 +52,10 @@ func NewMultiProvider(passedProviders []UniqueNameProvider, evaluationStrategy s return nil, err } - // err = multiProvider.initialize() - // if err != nil { - // return nil, err - // } + err = multiProvider.Init(of.EvaluationContext{}) + if err != nil { + return nil, err + } return multiProvider, nil } @@ -101,32 +105,38 @@ func registerProviders(mp *MultiProvider, providers []UniqueNameProvider) error return nil } -type InitError struct { - ProviderName string - Error error -} - // Init will run the initialize method for all of provides and aggregate the errors. func (mp *MultiProvider) Init(evalCtx of.EvaluationContext) error { var wg sync.WaitGroup - errChan := make(chan InitError, len(mp.providersEntries)) + errChan := make(chan err.InitError, len(mp.providersEntries)) for _, provider := range mp.providersEntries { wg.Add(1) go func(p UniqueNameProvider) { defer wg.Done() if initMethod, ok := p.Provider.(of.StateHandler); ok { - if err := initMethod.Init(evalCtx); err != nil { - errChan <- InitError{ProviderName: p.Name, Error: err} + if initErr := initMethod.Init(evalCtx); initErr != nil { + errChan <- err.InitError{ProviderName: p.Name, Err: initErr} } } }(provider) } - wg.Wait() - close(errChan) + go func() { + wg.Wait() + close(errChan) + }() + + var errors []err.InitError + for err := range errChan { + errors = append(errors, err) + } - // var errors []InitError + if len(errors) > 0 { + var aggErr err.AggregateError + aggErr.Construct(errors) + return &aggErr + } return nil diff --git a/providers/multi-provider/pkg/providers_test.go b/providers/multi-provider/pkg/providers_test.go index c7735289c..ab244afd2 100644 --- a/providers/multi-provider/pkg/providers_test.go +++ b/providers/multi-provider/pkg/providers_test.go @@ -1 +1,5 @@ -package multiprovider \ No newline at end of file +package multiprovider + +import "testing" + +func TestNewMultiProvider(t *testing.T){} \ No newline at end of file From dd933fbce0150cebe467b4ab7cb86b7d67e6c24c Mon Sep 17 00:00:00 2001 From: bbland1 <104288486+bbland1@users.noreply.github.com> Date: Thu, 27 Feb 2025 02:16:26 -0500 Subject: [PATCH 07/24] added the Shutdown method Signed-off-by: bbland1 <104288486+bbland1@users.noreply.github.com> --- .../internal/aggregate-errors.go | 14 ++++----- providers/multi-provider/pkg/providers.go | 31 +++++++++++++------ 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/providers/multi-provider/internal/aggregate-errors.go b/providers/multi-provider/internal/aggregate-errors.go index c4d3e772f..e974e9c05 100644 --- a/providers/multi-provider/internal/aggregate-errors.go +++ b/providers/multi-provider/internal/aggregate-errors.go @@ -2,29 +2,29 @@ package internal import "fmt" -// InitError is how the error in the Init stage of a provider is reported. -type InitError struct { +// StateErr is how the error in the Init of Shutdown stage of a provider is reported. +type StateErr struct { ProviderName string - Err error + Err error } -func (e *InitError) Error() string { +func (e *StateErr) Error() string { return fmt.Sprintf("Provider %s had an error: %v", e.ProviderName, e.Err) } type AggregateError struct { Message string - Errors []InitError + Errors []StateErr } func (ae *AggregateError) Error() string { return ae.Message } -func (ae *AggregateError) Construct(providerErrors []InitError) { +func (ae *AggregateError) Construct(providerErrors []StateErr) { // Show first error message for convenience, but all errors in the object msg := fmt.Sprintf("Provider errors occurred: %s: %v", providerErrors[0].ProviderName, providerErrors[0].Err) ae.Message = msg ae.Errors = providerErrors -} \ No newline at end of file +} diff --git a/providers/multi-provider/pkg/providers.go b/providers/multi-provider/pkg/providers.go index 770d101d2..44de41214 100644 --- a/providers/multi-provider/pkg/providers.go +++ b/providers/multi-provider/pkg/providers.go @@ -52,10 +52,10 @@ func NewMultiProvider(passedProviders []UniqueNameProvider, evaluationStrategy s return nil, err } - err = multiProvider.Init(of.EvaluationContext{}) - if err != nil { - return nil, err - } + // err = multiProvider.Init(of.EvaluationContext{}) + // if err != nil { + // return nil, err + // } return multiProvider, nil } @@ -108,15 +108,15 @@ func registerProviders(mp *MultiProvider, providers []UniqueNameProvider) error // Init will run the initialize method for all of provides and aggregate the errors. func (mp *MultiProvider) Init(evalCtx of.EvaluationContext) error { var wg sync.WaitGroup + errChan := make(chan err.StateErr, len(mp.providersEntries)) - errChan := make(chan err.InitError, len(mp.providersEntries)) for _, provider := range mp.providersEntries { wg.Add(1) go func(p UniqueNameProvider) { defer wg.Done() - if initMethod, ok := p.Provider.(of.StateHandler); ok { - if initErr := initMethod.Init(evalCtx); initErr != nil { - errChan <- err.InitError{ProviderName: p.Name, Err: initErr} + if stateHandle, ok := p.Provider.(of.StateHandler); ok { + if initErr := stateHandle.Init(evalCtx); initErr != nil { + errChan <- err.StateErr{ProviderName: p.Name, Err: initErr} } } }(provider) @@ -127,7 +127,7 @@ func (mp *MultiProvider) Init(evalCtx of.EvaluationContext) error { close(errChan) }() - var errors []err.InitError + var errors []err.StateErr for err := range errChan { errors = append(errors, err) } @@ -138,7 +138,6 @@ func (mp *MultiProvider) Init(evalCtx of.EvaluationContext) error { return &aggErr } - return nil } @@ -147,7 +146,19 @@ func (mp *MultiProvider) Status() of.State { } func (mp *MultiProvider) Shutdown() { + var wg sync.WaitGroup + + for _, provider := range mp.providersEntries { + wg.Add(1) + go func(p UniqueNameProvider) { + defer wg.Done() + if stateHandle, ok := p.Provider.(of.StateHandler); ok { + stateHandle.Shutdown() + } + }(provider) + } + wg.Wait() } func (mp *MultiProvider) EventChannel() <-chan of.Event { From 32af790c82cb26f76fb21af187bcb17d52eac9fe Mon Sep 17 00:00:00 2001 From: bbland1 <104288486+bbland1@users.noreply.github.com> Date: Thu, 27 Feb 2025 20:28:35 -0500 Subject: [PATCH 08/24] added getter methods to the unexported fields Signed-off-by: bbland1 <104288486+bbland1@users.noreply.github.com> --- providers/multi-provider/pkg/providers.go | 67 +++++++++++++---------- 1 file changed, 37 insertions(+), 30 deletions(-) diff --git a/providers/multi-provider/pkg/providers.go b/providers/multi-provider/pkg/providers.go index 44de41214..8c83ad3eb 100644 --- a/providers/multi-provider/pkg/providers.go +++ b/providers/multi-provider/pkg/providers.go @@ -7,44 +7,44 @@ import ( err "github.com/open-feature/go-sdk-contrib/providers/multi-provider/internal" - of "github.com/open-feature/go-sdk/openfeature" - ofhooks "github.com/open-feature/go-sdk/openfeature/hooks" + "github.com/open-feature/go-sdk/openfeature" + "github.com/open-feature/go-sdk/openfeature/hooks" ) var ( - errUniqueName = errors.New("Provider names must be unique.") + errUniqueName = errors.New("provider names must be unique") ) // UniqueNameProvider allows for a unique name to be assigned to a provider during a multi-provider set up. // The name will be used when reporting errors & results to specify the provider associated. type UniqueNameProvider struct { - Provider of.FeatureProvider - Name string + Provider openfeature.FeatureProvider + UniqueName string } // MultiMetadata defines the return of the MultiProvider metadata with the aggregated data of all the providers. type MultiMetadata struct { Name string - OriginalMetadata map[string]of.Metadata + OriginalMetadata map[string]openfeature.Metadata } // MultiProvider implements openfeature `FeatureProvider` in a way to accept an array of providers. type MultiProvider struct { providersEntries []UniqueNameProvider providersEntriesByName map[string]UniqueNameProvider - AggregatedMetadata map[string]of.Metadata + AggregatedMetadata map[string]openfeature.Metadata EvaluationStrategy string - events chan of.Event - status of.State + events chan openfeature.Event + status openfeature.State mu sync.Mutex } // NewMultiProvider returns the unified interface of multiple providers for interaction. -func NewMultiProvider(passedProviders []UniqueNameProvider, evaluationStrategy string, logger ofhooks.LoggingHook) (*MultiProvider, error) { +func NewMultiProvider(passedProviders []UniqueNameProvider, evaluationStrategy string, logger *hooks.LoggingHook) (*MultiProvider, error) { multiProvider := &MultiProvider{ providersEntries: []UniqueNameProvider{}, providersEntriesByName: map[string]UniqueNameProvider{}, - AggregatedMetadata: map[string]of.Metadata{}, + AggregatedMetadata: map[string]openfeature.Metadata{}, } err := registerProviders(multiProvider, passedProviders) @@ -52,21 +52,26 @@ func NewMultiProvider(passedProviders []UniqueNameProvider, evaluationStrategy s return nil, err } - // err = multiProvider.Init(of.EvaluationContext{}) - // if err != nil { - // return nil, err - // } - return multiProvider, nil } +func (mp *MultiProvider) Providers() []UniqueNameProvider { + return mp.providersEntries +} + +func (mp *MultiProvider) ProvidersByName() []UniqueNameProvider { + return mp.providersEntries +} + +func (mp *MultiProvider) ProviderByName(name string) (UniqueNameProvider, bool) { + provider, exists := mp.providersEntriesByName[name] + return provider, exists +} + // Metadata provides the name `multiprovider` and the names of each provider passed. -func (mp *MultiProvider) Metadata() MultiMetadata { +func (mp *MultiProvider) Metadata() openfeature.Metadata { - return MultiMetadata{ - Name: "multiprovider", - OriginalMetadata: mp.AggregatedMetadata, - } + return openfeature.Metadata{Name: "multiprovider"} } // registerProviders ensures that when setting up an instant of MultiProvider the providers provided either have a unique name or the base `metadata.Name` is made unique by adding an indexed based number to it. @@ -75,7 +80,7 @@ func registerProviders(mp *MultiProvider, providers []UniqueNameProvider) error providersByName := make(map[string][]UniqueNameProvider) for _, provider := range providers { - uniqueName := provider.Name + uniqueName := provider.UniqueName if _, exists := providersByName[uniqueName]; exists { return errUniqueName @@ -90,12 +95,14 @@ func registerProviders(mp *MultiProvider, providers []UniqueNameProvider) error for name, providers := range providersByName { if len(providers) == 1 { + providers[0].UniqueName = name mp.providersEntries = append(mp.providersEntries, providers[0]) mp.providersEntriesByName[name] = providers[0] mp.AggregatedMetadata[name] = providers[0].Provider.Metadata() } else { for i, provider := range providers { uniqueName := fmt.Sprintf("%s-%d", name, i+1) + provider.UniqueName = uniqueName mp.providersEntries = append(mp.providersEntries, provider) mp.providersEntriesByName[uniqueName] = provider mp.AggregatedMetadata[uniqueName] = provider.Provider.Metadata() @@ -106,7 +113,7 @@ func registerProviders(mp *MultiProvider, providers []UniqueNameProvider) error } // Init will run the initialize method for all of provides and aggregate the errors. -func (mp *MultiProvider) Init(evalCtx of.EvaluationContext) error { +func (mp *MultiProvider) Init(evalCtx openfeature.EvaluationContext) error { var wg sync.WaitGroup errChan := make(chan err.StateErr, len(mp.providersEntries)) @@ -114,9 +121,9 @@ func (mp *MultiProvider) Init(evalCtx of.EvaluationContext) error { wg.Add(1) go func(p UniqueNameProvider) { defer wg.Done() - if stateHandle, ok := p.Provider.(of.StateHandler); ok { + if stateHandle, ok := p.Provider.(openfeature.StateHandler); ok { if initErr := stateHandle.Init(evalCtx); initErr != nil { - errChan <- err.StateErr{ProviderName: p.Name, Err: initErr} + errChan <- err.StateErr{ProviderName: p.UniqueName, Err: initErr} } } }(provider) @@ -141,8 +148,8 @@ func (mp *MultiProvider) Init(evalCtx of.EvaluationContext) error { return nil } -func (mp *MultiProvider) Status() of.State { - return of.ReadyState +func (mp *MultiProvider) Status() openfeature.State { + return openfeature.ReadyState } func (mp *MultiProvider) Shutdown() { @@ -152,7 +159,7 @@ func (mp *MultiProvider) Shutdown() { wg.Add(1) go func(p UniqueNameProvider) { defer wg.Done() - if stateHandle, ok := p.Provider.(of.StateHandler); ok { + if stateHandle, ok := p.Provider.(openfeature.StateHandler); ok { stateHandle.Shutdown() } }(provider) @@ -161,7 +168,7 @@ func (mp *MultiProvider) Shutdown() { wg.Wait() } -func (mp *MultiProvider) EventChannel() <-chan of.Event { - ev := make(chan of.Event) +func (mp *MultiProvider) EventChannel() <-chan openfeature.Event { + ev := make(chan openfeature.Event) return ev } From c6aaf74cf1bf8b3f35c8312219164b9d240e37b8 Mon Sep 17 00:00:00 2001 From: bbland1 <104288486+bbland1@users.noreply.github.com> Date: Thu, 27 Feb 2025 20:35:12 -0500 Subject: [PATCH 09/24] added tests to check unique name for providers passed Signed-off-by: bbland1 <104288486+bbland1@users.noreply.github.com> --- .../multi-provider/pkg/providers_test.go | 164 +++++++++++++++++- 1 file changed, 162 insertions(+), 2 deletions(-) diff --git a/providers/multi-provider/pkg/providers_test.go b/providers/multi-provider/pkg/providers_test.go index ab244afd2..ec4380d14 100644 --- a/providers/multi-provider/pkg/providers_test.go +++ b/providers/multi-provider/pkg/providers_test.go @@ -1,5 +1,165 @@ package multiprovider -import "testing" +import ( + "testing" -func TestNewMultiProvider(t *testing.T){} \ No newline at end of file + // "github.com/open-feature/go-sdk/openfeature" + "github.com/open-feature/go-sdk/openfeature/hooks" + "github.com/open-feature/go-sdk/openfeature/memprovider" + oft "github.com/open-feature/go-sdk/openfeature/testing" +) + +func TestNewMultiProvider_ProviderMetadataUniqueNames(t *testing.T) { + testProvider1 := memprovider.NewInMemoryProvider(map[string]memprovider.InMemoryFlag{ + "boolFlag": { + Key: "boolFlag", + State: memprovider.Enabled, + DefaultVariant: "true", + Variants: map[string]interface{}{ + "true": true, + "false": false, + }, + ContextEvaluator: nil, + }, + }) + testProvider2 := oft.NewTestProvider() + + defaultLogger, err := hooks.NewLoggingHook(false) + if err != nil { + t.Errorf("Issue setting up logger,'%s'", err) + } + + multiProvider, err := NewMultiProvider([]UniqueNameProvider{ + { + Provider: testProvider1, + }, { + Provider: testProvider2, + }, + }, "test", defaultLogger) + + if err != nil { + t.Errorf("Expected the multiprovider to successfully make an instance, '%s'", err) + } + + providerEntries := multiProvider.Providers() + + if providerEntries[0].UniqueName != "InMemoryProvider" { + t.Errorf("Expected unique provider name to be: 'InMemoryProvider', got: '%s'", providerEntries[0].UniqueName) + } + if providerEntries[1].UniqueName != "NoopProvider" { + t.Errorf("Expected unique provider name to be: 'NoopProvider', got: '%s'", providerEntries[1].UniqueName) + } + + if len(providerEntries) != 2 { + t.Errorf("Expected there to be 2 provider entries, got: '%d'", len(providerEntries)) + } +} + +func TestNewMultiProvider_DuplicateProviderGenerateUniqueNames(t *testing.T) { + testProvider1 := memprovider.NewInMemoryProvider(map[string]memprovider.InMemoryFlag{ + "boolFlag": { + Key: "boolFlag", + State: memprovider.Enabled, + DefaultVariant: "true", + Variants: map[string]interface{}{ + "true": true, + "false": false, + }, + ContextEvaluator: nil, + }, + }) + testProvider2 := oft.NewTestProvider() + testProvider3 := oft.NewTestProvider() + testProvider4 := oft.NewTestProvider() + + defaultLogger, err := hooks.NewLoggingHook(false) + if err != nil { + t.Errorf("Issue setting up logger,'%s'", err) + } + + multiProvider, err := NewMultiProvider([]UniqueNameProvider{ + { + Provider: testProvider1, + }, { + Provider: testProvider2, + }, { + Provider: testProvider3, + },{ + Provider: testProvider4, + }, + }, "test", defaultLogger) + + if err != nil { + t.Errorf("Expected the multiprovider to successfully make an instance, '%s'", err) + } + + providerEntries := multiProvider.Providers() + + if providerEntries[0].UniqueName != "InMemoryProvider" { + t.Errorf("Expected unique provider name to be: 'InMemoryProvider', got: '%s'", providerEntries[0].UniqueName) + } + if providerEntries[1].UniqueName != "NoopProvider-1" { + t.Errorf("Expected unique provider name to be: 'NoopProvider', got: '%s'", providerEntries[1].UniqueName) + } + if providerEntries[2].UniqueName != "NoopProvider-2" { + t.Errorf("Expected unique provider name to be: 'NoopProvider', got: '%s'", providerEntries[2].UniqueName) + } + if providerEntries[3].UniqueName != "NoopProvider-3" { + t.Errorf("Expected unique provider name to be: 'NoopProvider', got: '%s'", providerEntries[3].UniqueName) + } + + if len(providerEntries) != 4 { + t.Errorf("Expected there to be 4 provider entries, got: '%d'", len(providerEntries)) + } +} +func TestNewMultiProvider_(t *testing.T) { + testProvider1 := memprovider.NewInMemoryProvider(map[string]memprovider.InMemoryFlag{ + "boolFlag": { + Key: "boolFlag", + State: memprovider.Enabled, + DefaultVariant: "true", + Variants: map[string]interface{}{ + "true": true, + "false": false, + }, + ContextEvaluator: nil, + }, + }) + testProvider2 := oft.NewTestProvider() + testProvider3 := oft.NewTestProvider() + testProvider4 := oft.NewTestProvider() + + defaultLogger, err := hooks.NewLoggingHook(false) + if err != nil { + t.Errorf("Issue setting up logger,'%s'", err) + } + + multiProvider, err := NewMultiProvider([]UniqueNameProvider{ + { + Provider: testProvider1, + }, { + Provider: testProvider2, + }, { + Provider: testProvider3, + },{ + Provider: testProvider4, + }, + }, "test", defaultLogger) + + if err != nil { + t.Errorf("Expected the multiprovider to successfully make an instance, '%s'", err) + } + + if multiProvider.providersEntries[0].UniqueName != "InMemoryProvider" { + t.Errorf("Expected unique provider name to be: 'InMemoryProvider', got: '%s'", multiProvider.providersEntries[0].UniqueName) + } + if multiProvider.providersEntries[1].UniqueName != "NoopProvider-1" { + t.Errorf("Expected unique provider name to be: 'NoopProvider', got: '%s'", multiProvider.providersEntries[1].UniqueName) + } + if multiProvider.providersEntries[2].UniqueName != "NoopProvider-2" { + t.Errorf("Expected unique provider name to be: 'NoopProvider', got: '%s'", multiProvider.providersEntries[2].UniqueName) + } + if multiProvider.providersEntries[3].UniqueName != "NoopProvider-3" { + t.Errorf("Expected unique provider name to be: 'NoopProvider', got: '%s'", multiProvider.providersEntries[3].UniqueName) + } +} From 70878e517ecd569a86f75d68c10decd9e9e5e2fe Mon Sep 17 00:00:00 2001 From: bbland1 <104288486+bbland1@users.noreply.github.com> Date: Sat, 1 Mar 2025 00:09:12 -0500 Subject: [PATCH 10/24] added test checking if error thrown for unique name if not unique Signed-off-by: bbland1 <104288486+bbland1@users.noreply.github.com> --- .../multi-provider/pkg/providers_test.go | 75 +++++++++++-------- 1 file changed, 44 insertions(+), 31 deletions(-) diff --git a/providers/multi-provider/pkg/providers_test.go b/providers/multi-provider/pkg/providers_test.go index ec4380d14..16c25b465 100644 --- a/providers/multi-provider/pkg/providers_test.go +++ b/providers/multi-provider/pkg/providers_test.go @@ -31,7 +31,7 @@ func TestNewMultiProvider_ProviderMetadataUniqueNames(t *testing.T) { multiProvider, err := NewMultiProvider([]UniqueNameProvider{ { - Provider: testProvider1, + Provider: testProvider1, }, { Provider: testProvider2, }, @@ -79,12 +79,12 @@ func TestNewMultiProvider_DuplicateProviderGenerateUniqueNames(t *testing.T) { multiProvider, err := NewMultiProvider([]UniqueNameProvider{ { - Provider: testProvider1, + Provider: testProvider1, }, { Provider: testProvider2, }, { Provider: testProvider3, - },{ + }, { Provider: testProvider4, }, }, "test", defaultLogger) @@ -112,22 +112,9 @@ func TestNewMultiProvider_DuplicateProviderGenerateUniqueNames(t *testing.T) { t.Errorf("Expected there to be 4 provider entries, got: '%d'", len(providerEntries)) } } -func TestNewMultiProvider_(t *testing.T) { - testProvider1 := memprovider.NewInMemoryProvider(map[string]memprovider.InMemoryFlag{ - "boolFlag": { - Key: "boolFlag", - State: memprovider.Enabled, - DefaultVariant: "true", - Variants: map[string]interface{}{ - "true": true, - "false": false, - }, - ContextEvaluator: nil, - }, - }) +func TestNewMultiProvider_ProvidersUsePassedNames(t *testing.T) { + testProvider1 := oft.NewTestProvider() testProvider2 := oft.NewTestProvider() - testProvider3 := oft.NewTestProvider() - testProvider4 := oft.NewTestProvider() defaultLogger, err := hooks.NewLoggingHook(false) if err != nil { @@ -137,12 +124,10 @@ func TestNewMultiProvider_(t *testing.T) { multiProvider, err := NewMultiProvider([]UniqueNameProvider{ { Provider: testProvider1, + UniqueName: "theFirst", }, { - Provider: testProvider2, - }, { - Provider: testProvider3, - },{ - Provider: testProvider4, + Provider: testProvider2, + UniqueName: "theSecond", }, }, "test", defaultLogger) @@ -150,16 +135,44 @@ func TestNewMultiProvider_(t *testing.T) { t.Errorf("Expected the multiprovider to successfully make an instance, '%s'", err) } - if multiProvider.providersEntries[0].UniqueName != "InMemoryProvider" { - t.Errorf("Expected unique provider name to be: 'InMemoryProvider', got: '%s'", multiProvider.providersEntries[0].UniqueName) + providerEntries := multiProvider.Providers() + + if providerEntries[0].UniqueName != "theFirst" { + t.Errorf("Expected unique provider name to be: 'theFirst', got: '%s'", providerEntries[0].UniqueName) } - if multiProvider.providersEntries[1].UniqueName != "NoopProvider-1" { - t.Errorf("Expected unique provider name to be: 'NoopProvider', got: '%s'", multiProvider.providersEntries[1].UniqueName) + if providerEntries[1].UniqueName != "theSecond" { + t.Errorf("Expected unique provider name to be: 'theSecond', got: '%s'", providerEntries[1].UniqueName) } - if multiProvider.providersEntries[2].UniqueName != "NoopProvider-2" { - t.Errorf("Expected unique provider name to be: 'NoopProvider', got: '%s'", multiProvider.providersEntries[2].UniqueName) + + if len(providerEntries) != 2 { + t.Errorf("Expected there to be 2 provider entries, got: '%d'", len(providerEntries)) } - if multiProvider.providersEntries[3].UniqueName != "NoopProvider-3" { - t.Errorf("Expected unique provider name to be: 'NoopProvider', got: '%s'", multiProvider.providersEntries[3].UniqueName) +} + +func TestNewMultiProvider_ProvidersErrorNameNotUnique(t *testing.T) { + testProvider1 := oft.NewTestProvider() + testProvider2 := oft.NewTestProvider() + + defaultLogger, err := hooks.NewLoggingHook(false) + if err != nil { + t.Errorf("Issue setting up logger,'%s'", err) + } + + _, err = NewMultiProvider([]UniqueNameProvider{ + { + Provider: testProvider1, + UniqueName: "provider", + }, { + Provider: testProvider2, + UniqueName: "provider", + }, + }, "test", defaultLogger) + + if err == nil { + t.Errorf("Expected the multiprovider to have an error") + } + + if err.Error() != "provider names must be unique" { + t.Errorf("Expected the multiprovider to have an error of: '%s', got: '%s'", errUniqueName, err.Error()) } } From d5f3d6adce327a0423c1ea03b29d00565670e120 Mon Sep 17 00:00:00 2001 From: bbland1 <104288486+bbland1@users.noreply.github.com> Date: Tue, 4 Mar 2025 13:04:43 -0500 Subject: [PATCH 11/24] added test to check for metadata, currently fails Signed-off-by: bbland1 <104288486+bbland1@users.noreply.github.com> --- .../multi-provider/pkg/providers_test.go | 42 ++++++++++++++++++- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/providers/multi-provider/pkg/providers_test.go b/providers/multi-provider/pkg/providers_test.go index 16c25b465..7440bb686 100644 --- a/providers/multi-provider/pkg/providers_test.go +++ b/providers/multi-provider/pkg/providers_test.go @@ -3,13 +3,13 @@ package multiprovider import ( "testing" - // "github.com/open-feature/go-sdk/openfeature" + "github.com/open-feature/go-sdk/openfeature" "github.com/open-feature/go-sdk/openfeature/hooks" "github.com/open-feature/go-sdk/openfeature/memprovider" oft "github.com/open-feature/go-sdk/openfeature/testing" ) -func TestNewMultiProvider_ProviderMetadataUniqueNames(t *testing.T) { +func TestNewMultiProvider_ProviderUniqueNames(t *testing.T) { testProvider1 := memprovider.NewInMemoryProvider(map[string]memprovider.InMemoryFlag{ "boolFlag": { Key: "boolFlag", @@ -176,3 +176,41 @@ func TestNewMultiProvider_ProvidersErrorNameNotUnique(t *testing.T) { t.Errorf("Expected the multiprovider to have an error of: '%s', got: '%s'", errUniqueName, err.Error()) } } + +// todo: currently the `multiProvider.Metadata()` just give the `Name` of the multi provider it doesn't aggregate the passed providers as stated in this specification https://openfeature.dev/specification/appendix-a/#metadata so this test fails +func TestAggregatedMetaData(t *testing.T){ + testProvider1 := oft.NewTestProvider() + testProvider2 := oft.NewTestProvider() + + defaultLogger, err := hooks.NewLoggingHook(false) + if err != nil { + t.Errorf("Issue setting up logger,'%s'", err) + } + + multiProvider, err := NewMultiProvider([]UniqueNameProvider{ + { + Provider: testProvider1, + UniqueName: "provider1", + }, { + Provider: testProvider2, + UniqueName: "provider2", + }, + }, "test", defaultLogger) + + if err != nil { + t.Errorf("Expected the multiprovider to successfully make an instance, '%s'", err) + } + + expectedMetadata := MultiMetadata{ + Name: "multiprovider", + OriginalMetadata: map[string]openfeature.Metadata{ + "provider1": openfeature.Metadata{Name:"NoopProvider"}, + "provider2": openfeature.Metadata{Name:"NoopProvider"}, + + }, + } + + if multiProvider.Metadata().Name != "hi" { + t.Errorf("Expected to see the aggregated metadata of all passed providers: '%s', got: '%s'", expectedMetadata, multiProvider.Metadata().Name) + } +} \ No newline at end of file From a3ba348c11f29b2e860e8baebc21d508f749dcd2 Mon Sep 17 00:00:00 2001 From: bbland1 <104288486+bbland1@users.noreply.github.com> Date: Wed, 5 Mar 2025 14:25:17 -0500 Subject: [PATCH 12/24] added test for getter methods of the struct provider entries Signed-off-by: bbland1 <104288486+bbland1@users.noreply.github.com> --- providers/multi-provider/pkg/providers.go | 4 +- .../multi-provider/pkg/providers_test.go | 244 ++++++++++++++---- 2 files changed, 202 insertions(+), 46 deletions(-) diff --git a/providers/multi-provider/pkg/providers.go b/providers/multi-provider/pkg/providers.go index 8c83ad3eb..51ffa6863 100644 --- a/providers/multi-provider/pkg/providers.go +++ b/providers/multi-provider/pkg/providers.go @@ -59,8 +59,8 @@ func (mp *MultiProvider) Providers() []UniqueNameProvider { return mp.providersEntries } -func (mp *MultiProvider) ProvidersByName() []UniqueNameProvider { - return mp.providersEntries +func (mp *MultiProvider) ProvidersByName() map[string]UniqueNameProvider { + return mp.providersEntriesByName } func (mp *MultiProvider) ProviderByName(name string) (UniqueNameProvider, bool) { diff --git a/providers/multi-provider/pkg/providers_test.go b/providers/multi-provider/pkg/providers_test.go index 7440bb686..ee7d792f4 100644 --- a/providers/multi-provider/pkg/providers_test.go +++ b/providers/multi-provider/pkg/providers_test.go @@ -9,6 +9,200 @@ import ( oft "github.com/open-feature/go-sdk/openfeature/testing" ) +func TestMultiProvider_ProvidersMethod(t *testing.T) { + testProvider1 := oft.NewTestProvider() + testProvider2 := oft.NewTestProvider() + + defaultLogger, err := hooks.NewLoggingHook(false) + if err != nil { + t.Errorf("Issue setting up logger,'%s'", err) + } + + mp, err := NewMultiProvider([]UniqueNameProvider{ + { + Provider: testProvider1, + UniqueName: "provider1", + }, { + Provider: testProvider2, + UniqueName: "provider2", + }, + }, "test", defaultLogger) + + if err != nil { + t.Errorf("Expected the multiprovider to successfully make an instance, '%s'", err) + } + + providers := mp.Providers() + + if len(providers) != 2 { + t.Errorf("Expected there to be '2' providers as passed but got: '%d'", len(providers)) + } + + if providers[0].UniqueName != "provider1" { + t.Errorf("Expected unique provider name to be: 'provider1', got: '%s'", providers[0].UniqueName) + } + if providers[1].UniqueName != "provider2" { + t.Errorf("Expected unique provider name to be: 'provider2', got: '%s'", providers[1].UniqueName) + } +} + +func TestMultiProvider_ProvidersByNamesMethod(t *testing.T) { + testProvider1 := oft.NewTestProvider() + testProvider2 := oft.NewTestProvider() + + defaultLogger, err := hooks.NewLoggingHook(false) + if err != nil { + t.Errorf("Issue setting up logger,'%s'", err) + } + + mp, err := NewMultiProvider([]UniqueNameProvider{ + { + Provider: testProvider1, + UniqueName: "provider1", + }, { + Provider: testProvider2, + UniqueName: "provider2", + }, + }, "test", defaultLogger) + + if err != nil { + t.Errorf("Expected the multiprovider to successfully make an instance, '%s'", err) + } + + providers := mp.ProvidersByName() + + if len(providers) != 2 { + t.Errorf("Expected there to be '2' providers as passed but got: '%d'", len(providers)) + } + + if provider, exists := providers["provider1"]; exists { + if provider.UniqueName != "provider1" { + t.Errorf("Expected unique provider name to be: 'provider1', got: '%s'", provider.UniqueName) + } + if provider.Provider != testProvider1 { + t.Errorf("Expected unique provider name to be: 'provider1', got: '%s'", provider.UniqueName) + } + } else { + t.Errorf("Expected there to be a provider with the key of '%s', but none was found.", "provider1") + } + + if provider, exists := providers["provider2"]; exists { + if provider.UniqueName != "provider2" { + t.Errorf("Expected unique provider name to be: 'provider2', got: '%s'", provider.UniqueName) + } + if provider.Provider != testProvider2 { + t.Errorf("Expected unique provider name to be: 'provider2', got: '%s'", provider.UniqueName) + } + } else { + t.Errorf("Expected there to be a provider with the key of '%s', but none was found.", "provider2") + } + +} + +func TestMultiProvider_ProviderByNameMethod(t *testing.T) { + testProvider1 := oft.NewTestProvider() + testProvider2 := oft.NewTestProvider() + + defaultLogger, err := hooks.NewLoggingHook(false) + if err != nil { + t.Errorf("Issue setting up logger,'%s'", err) + } + + mp, err := NewMultiProvider([]UniqueNameProvider{ + { + Provider: testProvider1, + UniqueName: "provider1", + }, { + Provider: testProvider2, + UniqueName: "provider2", + }, + }, "test", defaultLogger) + + if err != nil { + t.Errorf("Expected the multiprovider to successfully make an instance, '%s'", err) + } + + providers := mp.ProvidersByName() + + if len(providers) != 2 { + t.Errorf("Expected there to be '2' providers as passed but got: '%d'", len(providers)) + } + if provider, exists := mp.ProviderByName("provider2"); exists { + if provider.UniqueName != "provider2" { + t.Errorf("Expected unique provider name to be: 'provider2', got: '%s'", provider.UniqueName) + } + if provider.Provider != testProvider2 { + t.Errorf("Expected unique provider name to be: 'provider2', got: '%s'", provider.UniqueName) + } + } else { + t.Errorf("Expected there to be a provider with the key of '%s', but none was found.", "provider1") + } + +} + +// todo: currently the `multiProvider.Metadata()` just give the `Name` of the multi provider it doesn't aggregate the passed providers as stated in this specification https://openfeature.dev/specification/appendix-a/#metadata so this test fails +func TestMultiProvider_MetaData(t *testing.T) { + testProvider1 := oft.NewTestProvider() + testProvider2 := oft.NewTestProvider() + + defaultLogger, err := hooks.NewLoggingHook(false) + if err != nil { + t.Errorf("Issue setting up logger,'%s'", err) + } + + mp, err := NewMultiProvider([]UniqueNameProvider{ + { + Provider: testProvider1, + UniqueName: "provider1", + }, { + Provider: testProvider2, + UniqueName: "provider2", + }, + }, "test", defaultLogger) + + if err != nil { + t.Errorf("Expected the multiprovider to successfully make an instance, '%s'", err) + } + + expectedMetadata := MultiMetadata{ + Name: "multiprovider", + OriginalMetadata: map[string]openfeature.Metadata{ + "provider1": openfeature.Metadata{Name: "NoopProvider"}, + "provider2": openfeature.Metadata{Name: "NoopProvider"}, + }, + } + + if mp.Metadata().Name != "hi" { + t.Errorf("Expected to see the aggregated metadata of all passed providers: '%s', got: '%s'", expectedMetadata, mp.Metadata().Name) + } +} + +// func TestMultiProvider_Init(t *testing.T) { +// testProvider1 := oft.NewTestProvider() +// testProvider2 := oft.NewTestProvider() + +// defaultLogger, err := hooks.NewLoggingHook(false) +// if err != nil { +// t.Errorf("Issue setting up logger,'%s'", err) +// } + +// mp, err := NewMultiProvider([]UniqueNameProvider{ +// { +// Provider: testProvider1, +// UniqueName: "provider1", +// }, { +// Provider: testProvider2, +// UniqueName: "provider2", +// }, +// }, "test", defaultLogger) + +// if err != nil { +// t.Errorf("Expected the multiprovider to successfully make an instance, '%s'", err) +// } + +// mp.Init() +// } + func TestNewMultiProvider_ProviderUniqueNames(t *testing.T) { testProvider1 := memprovider.NewInMemoryProvider(map[string]memprovider.InMemoryFlag{ "boolFlag": { @@ -29,7 +223,7 @@ func TestNewMultiProvider_ProviderUniqueNames(t *testing.T) { t.Errorf("Issue setting up logger,'%s'", err) } - multiProvider, err := NewMultiProvider([]UniqueNameProvider{ + mp, err := NewMultiProvider([]UniqueNameProvider{ { Provider: testProvider1, }, { @@ -41,7 +235,7 @@ func TestNewMultiProvider_ProviderUniqueNames(t *testing.T) { t.Errorf("Expected the multiprovider to successfully make an instance, '%s'", err) } - providerEntries := multiProvider.Providers() + providerEntries := mp.Providers() if providerEntries[0].UniqueName != "InMemoryProvider" { t.Errorf("Expected unique provider name to be: 'InMemoryProvider', got: '%s'", providerEntries[0].UniqueName) @@ -77,7 +271,7 @@ func TestNewMultiProvider_DuplicateProviderGenerateUniqueNames(t *testing.T) { t.Errorf("Issue setting up logger,'%s'", err) } - multiProvider, err := NewMultiProvider([]UniqueNameProvider{ + mp, err := NewMultiProvider([]UniqueNameProvider{ { Provider: testProvider1, }, { @@ -93,7 +287,7 @@ func TestNewMultiProvider_DuplicateProviderGenerateUniqueNames(t *testing.T) { t.Errorf("Expected the multiprovider to successfully make an instance, '%s'", err) } - providerEntries := multiProvider.Providers() + providerEntries := mp.Providers() if providerEntries[0].UniqueName != "InMemoryProvider" { t.Errorf("Expected unique provider name to be: 'InMemoryProvider', got: '%s'", providerEntries[0].UniqueName) @@ -121,7 +315,7 @@ func TestNewMultiProvider_ProvidersUsePassedNames(t *testing.T) { t.Errorf("Issue setting up logger,'%s'", err) } - multiProvider, err := NewMultiProvider([]UniqueNameProvider{ + mp, err := NewMultiProvider([]UniqueNameProvider{ { Provider: testProvider1, UniqueName: "theFirst", @@ -135,7 +329,7 @@ func TestNewMultiProvider_ProvidersUsePassedNames(t *testing.T) { t.Errorf("Expected the multiprovider to successfully make an instance, '%s'", err) } - providerEntries := multiProvider.Providers() + providerEntries := mp.Providers() if providerEntries[0].UniqueName != "theFirst" { t.Errorf("Expected unique provider name to be: 'theFirst', got: '%s'", providerEntries[0].UniqueName) @@ -176,41 +370,3 @@ func TestNewMultiProvider_ProvidersErrorNameNotUnique(t *testing.T) { t.Errorf("Expected the multiprovider to have an error of: '%s', got: '%s'", errUniqueName, err.Error()) } } - -// todo: currently the `multiProvider.Metadata()` just give the `Name` of the multi provider it doesn't aggregate the passed providers as stated in this specification https://openfeature.dev/specification/appendix-a/#metadata so this test fails -func TestAggregatedMetaData(t *testing.T){ - testProvider1 := oft.NewTestProvider() - testProvider2 := oft.NewTestProvider() - - defaultLogger, err := hooks.NewLoggingHook(false) - if err != nil { - t.Errorf("Issue setting up logger,'%s'", err) - } - - multiProvider, err := NewMultiProvider([]UniqueNameProvider{ - { - Provider: testProvider1, - UniqueName: "provider1", - }, { - Provider: testProvider2, - UniqueName: "provider2", - }, - }, "test", defaultLogger) - - if err != nil { - t.Errorf("Expected the multiprovider to successfully make an instance, '%s'", err) - } - - expectedMetadata := MultiMetadata{ - Name: "multiprovider", - OriginalMetadata: map[string]openfeature.Metadata{ - "provider1": openfeature.Metadata{Name:"NoopProvider"}, - "provider2": openfeature.Metadata{Name:"NoopProvider"}, - - }, - } - - if multiProvider.Metadata().Name != "hi" { - t.Errorf("Expected to see the aggregated metadata of all passed providers: '%s', got: '%s'", expectedMetadata, multiProvider.Metadata().Name) - } -} \ No newline at end of file From efa68b983aa5276104e158725dd1ba4591df7449 Mon Sep 17 00:00:00 2001 From: cupofcat Date: Sat, 22 Feb 2025 14:34:14 +0100 Subject: [PATCH 13/24] chore(flagd): Updates flagd core to v0.11.2 (#636) Signed-off-by: Maks Osowski Signed-off-by: bbland1 <104288486+bbland1@users.noreply.github.com> --- providers/flagd/go.mod | 16 ++++++++-------- providers/flagd/go.sum | 39 +++++++++++++++++++-------------------- 2 files changed, 27 insertions(+), 28 deletions(-) diff --git a/providers/flagd/go.mod b/providers/flagd/go.mod index 30f9d62b2..63a218d00 100644 --- a/providers/flagd/go.mod +++ b/providers/flagd/go.mod @@ -7,21 +7,21 @@ toolchain go1.23.6 require ( buf.build/gen/go/open-feature/flagd/connectrpc/go v1.17.0-20240906125204-0a6a901b42e8.1 buf.build/gen/go/open-feature/flagd/grpc/go v1.5.1-20250127221518-be6d1143b690.2 - buf.build/gen/go/open-feature/flagd/protocolbuffers/go v1.36.4-20250127221518-be6d1143b690.1 + buf.build/gen/go/open-feature/flagd/protocolbuffers/go v1.36.5-20250127221518-be6d1143b690.1 connectrpc.com/connect v1.18.1 connectrpc.com/otelconnect v0.7.1 github.com/cucumber/godog v0.15.0 github.com/go-logr/logr v1.4.2 github.com/google/go-cmp v0.6.0 github.com/hashicorp/golang-lru/v2 v2.0.7 - github.com/open-feature/flagd/core v0.11.1 + github.com/open-feature/flagd/core v0.11.2 github.com/open-feature/go-sdk v1.11.0 github.com/open-feature/go-sdk-contrib/tests/flagd v1.4.1 go.uber.org/mock v0.5.0 - golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c + golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac golang.org/x/net v0.34.0 google.golang.org/grpc v1.70.0 - google.golang.org/protobuf v1.36.4 + google.golang.org/protobuf v1.36.5 sigs.k8s.io/controller-runtime v0.19.0 ) @@ -29,7 +29,7 @@ require ( github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df // indirect github.com/cucumber/gherkin/go/v26 v26.2.0 // indirect github.com/cucumber/messages/go/v21 v21.0.1 // indirect - github.com/diegoholiveira/jsonlogic/v3 v3.7.3 // indirect + github.com/diegoholiveira/jsonlogic/v3 v3.7.4 // indirect github.com/fsnotify/fsnotify v1.8.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect @@ -58,9 +58,9 @@ require ( go.opentelemetry.io/otel/trace v1.34.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/mod v0.22.0 // indirect - golang.org/x/sys v0.29.0 // indirect - golang.org/x/text v0.21.0 // indirect + golang.org/x/mod v0.23.0 // indirect + golang.org/x/sys v0.30.0 // indirect + golang.org/x/text v0.22.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/providers/flagd/go.sum b/providers/flagd/go.sum index c9a3a885a..6450e262f 100644 --- a/providers/flagd/go.sum +++ b/providers/flagd/go.sum @@ -2,8 +2,8 @@ buf.build/gen/go/open-feature/flagd/connectrpc/go v1.17.0-20240906125204-0a6a901 buf.build/gen/go/open-feature/flagd/connectrpc/go v1.17.0-20240906125204-0a6a901b42e8.1/go.mod h1:jKw7gioqYsWaHUKr5Ja6MiadsXcrGJxQ86gucJ0luUA= buf.build/gen/go/open-feature/flagd/grpc/go v1.5.1-20250127221518-be6d1143b690.2 h1:D3HI5RQbqgffyf+Z77+hReDx5kigFVAKGvttULD9/ms= buf.build/gen/go/open-feature/flagd/grpc/go v1.5.1-20250127221518-be6d1143b690.2/go.mod h1:b9rfG6rbGXZAlLwQwedvZ0kI0nUcR+aLaYF70pj920E= -buf.build/gen/go/open-feature/flagd/protocolbuffers/go v1.36.4-20250127221518-be6d1143b690.1 h1:0vXmOkGv8nO5H1W8TkSz+GtZhvD2LNXiQaiucEio6vk= -buf.build/gen/go/open-feature/flagd/protocolbuffers/go v1.36.4-20250127221518-be6d1143b690.1/go.mod h1:wemFLfCpuNfhrBQ7NwzbtYxbg+IihAYqJcNeS+fLpLI= +buf.build/gen/go/open-feature/flagd/protocolbuffers/go v1.36.5-20250127221518-be6d1143b690.1 h1:eZKupK8gUTuc6zifAFQon8Gnt44fR4cd0GnTWjELvEw= +buf.build/gen/go/open-feature/flagd/protocolbuffers/go v1.36.5-20250127221518-be6d1143b690.1/go.mod h1:wJvVIADHM0IaBc5sYf8wgMMgSHi0nAtc6rgr5rfizhA= connectrpc.com/connect v1.18.1 h1:PAg7CjSAGvscaf6YZKUefjoih5Z/qYkyaTrBW8xvYPw= connectrpc.com/connect v1.18.1/go.mod h1:0292hj1rnx8oFrStN7cB4jjVBeqs+Yx5yDIC2prWDO8= connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY= @@ -13,8 +13,7 @@ github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df/go.mod h1:h github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cucumber/gherkin/go/v26 v26.2.0 h1:EgIjePLWiPeslwIWmNQ3XHcypPsWAHoMCz/YEBKP4GI= github.com/cucumber/gherkin/go/v26 v26.2.0/go.mod h1:t2GAPnB8maCT4lkHL99BDCVNzCh1d7dBhCLt150Nr/0= -github.com/cucumber/godog v0.14.1 h1:HGZhcOyyfaKclHjJ+r/q93iaTJZLKYW6Tv3HkmUE6+M= -github.com/cucumber/godog v0.14.1/go.mod h1:FX3rzIDybWABU4kuIXLZ/qtqEe1Ac5RdXmqvACJOces= +github.com/cucumber/godog v0.15.0 h1:51AL8lBXF3f0cyA5CV4TnJFCTHpgiy+1x1Hb3TtZUmo= github.com/cucumber/godog v0.15.0/go.mod h1:FX3rzIDybWABU4kuIXLZ/qtqEe1Ac5RdXmqvACJOces= github.com/cucumber/messages/go/v21 v21.0.1 h1:wzA0LxwjlWQYZd32VTlAVDTkW6inOFmSM+RuOwHZiMI= github.com/cucumber/messages/go/v21 v21.0.1/go.mod h1:zheH/2HS9JLVFukdrsPWoPdmUtmYQAQPLk7w5vWsk5s= @@ -23,8 +22,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/diegoholiveira/jsonlogic/v3 v3.7.3 h1:orvGaTW5Qdcowpr7vgfMNuqYNjQYcqtw9W1Bk4QyI38= -github.com/diegoholiveira/jsonlogic/v3 v3.7.3/go.mod h1:OYRb6FSTVmMM+MNQ7ElmMsczyNSepw+OU4Z8emDSi4w= +github.com/diegoholiveira/jsonlogic/v3 v3.7.4 h1:92HSmB9bwM/o0ZvrCpcvTP2EsPXSkKtAniIr2W/dcIM= +github.com/diegoholiveira/jsonlogic/v3 v3.7.4/go.mod h1:OYRb6FSTVmMM+MNQ7ElmMsczyNSepw+OU4Z8emDSi4w= github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= @@ -95,8 +94,8 @@ github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= github.com/open-feature/flagd-schemas v0.2.9-0.20250127221449-bb763438abc5 h1:0RKCLYeQpvSsKR95kc894tm8GAZmq7bcG48v0KJ0HCs= github.com/open-feature/flagd-schemas v0.2.9-0.20250127221449-bb763438abc5/go.mod h1:WKtwo1eW9/K6D+4HfgTXWBqCDzpvMhDa5eRxW7R5B2U= -github.com/open-feature/flagd/core v0.11.1 h1:0qBVXcRBZOFoZ5lNK/Yba2IyUDdxUHcLsv5OhUJtltA= -github.com/open-feature/flagd/core v0.11.1/go.mod h1:yzPjp7D9wNusvOyKt8wBND5PQGslcu+5e+xmaIBGgLE= +github.com/open-feature/flagd/core v0.11.2 h1:3LAuLR2vXpBF80RwwCAu9JX898JasfPH7ErJEf5C5YA= +github.com/open-feature/flagd/core v0.11.2/go.mod h1:rTdYFyLGP1tGwxo0X26ygIrC31nINCv8hcCq+vhFD0E= github.com/open-feature/go-sdk v1.11.0 h1:4cp9rXl16ZvlMCef7O+I3vQSXae8DzAF0SfV9mvYInw= github.com/open-feature/go-sdk v1.11.0/go.mod h1:+rkJhLBtYsJ5PZNddAgFILhRAAxwrJ32aU7UEUm4zQI= github.com/open-feature/go-sdk-contrib/tests/flagd v1.4.1 h1:kFAeX4qLSdcm//s9fvyBQ9CvfBZMtTkwEN46rjuxx+E= @@ -160,12 +159,12 @@ go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c h1:KL/ZBHXgKGVmuZBZ01Lt57yE5ws8ZPSkkihmEyq7FXc= -golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU= +golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac h1:l5+whBCLH3iH2ZNHYLbAe58bo7yrN4mVcnkHDYz5vvs= +golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac/go.mod h1:hH+7mtFmImwwcMvScyxUhjuVHR3HGaDPMn9rMSUUbxo= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= -golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= +golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -181,18 +180,18 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= -golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE= -golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588= +golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= +golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -201,8 +200,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f h1: google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50= google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= -google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM= -google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= +google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= From 0ac634326b6af0e963912424c9d72a262ef71c51 Mon Sep 17 00:00:00 2001 From: cupofcat Date: Sat, 22 Feb 2025 15:02:34 +0100 Subject: [PATCH 14/24] feat(flagd): Added WithGrpcDialOptionsOverride provider option (#638) Signed-off-by: Maks Osowski Signed-off-by: bbland1 <104288486+bbland1@users.noreply.github.com> --- providers/flagd/README.md | 21 ++++++ providers/flagd/pkg/configuration.go | 2 + providers/flagd/pkg/provider.go | 30 +++++--- providers/flagd/pkg/provider_test.go | 68 ++++++++++++++----- .../flagd/pkg/service/in_process/service.go | 34 ++++++---- 5 files changed, 114 insertions(+), 41 deletions(-) diff --git a/providers/flagd/README.md b/providers/flagd/README.md index d9788ad0b..463d92c0c 100644 --- a/providers/flagd/README.md +++ b/providers/flagd/README.md @@ -144,6 +144,27 @@ openfeature.SetProvider(flagd.NewProvider( )) ``` +### gRPC DialOptions override + +The `GrpcDialOptionsOverride` is meant for connection of the in-process resolver to a Sync API implementation on a host/port, +that might require special credentials or headers. + +```go +creds := customSync.CreateCredentials(...) + +dialOptions := []grpc.DialOption{ + grpc.WithTransportCredentials(creds.TransportCredentials()), + grpc.WithPerRPCCredentials(creds.PerRPCCredentials()), + grpc.WithAuthority(...), + } + +openfeature.SetProvider(flagd.NewProvider( + flagd.WithInProcessResolver(), + flagd.WithHost("example.com/flagdSyncApi"), flagd.WithPort(443), + flagd.WithGrpcDialOptionsOverride(dialOptions), + )) +``` + ## Supported Events The flagd provider emits `PROVIDER_READY`, `PROVIDER_ERROR` and `PROVIDER_CONFIGURATION_CHANGED` events. diff --git a/providers/flagd/pkg/configuration.go b/providers/flagd/pkg/configuration.go index e08536096..61538fb8a 100644 --- a/providers/flagd/pkg/configuration.go +++ b/providers/flagd/pkg/configuration.go @@ -8,6 +8,7 @@ import ( "github.com/go-logr/logr" "github.com/open-feature/flagd/core/pkg/sync" "github.com/open-feature/go-sdk-contrib/providers/flagd/internal/cache" + "google.golang.org/grpc" ) type ResolverType string @@ -58,6 +59,7 @@ type providerConfiguration struct { TLSEnabled bool CustomSyncProvider sync.ISync CustomSyncProviderUri string + GrpcDialOptionsOverride []grpc.DialOption log logr.Logger } diff --git a/providers/flagd/pkg/provider.go b/providers/flagd/pkg/provider.go index c41165e22..d6c413db4 100644 --- a/providers/flagd/pkg/provider.go +++ b/providers/flagd/pkg/provider.go @@ -13,6 +13,7 @@ import ( process "github.com/open-feature/go-sdk-contrib/providers/flagd/pkg/service/in_process" rpcService "github.com/open-feature/go-sdk-contrib/providers/flagd/pkg/service/rpc" of "github.com/open-feature/go-sdk/openfeature" + "google.golang.org/grpc" ) const ( @@ -78,15 +79,16 @@ func NewProvider(opts ...ProviderOption) *Provider { provider.providerConfiguration.EventStreamConnectionMaxAttempts) } else { service = process.NewInProcessService(process.Configuration{ - Host: provider.providerConfiguration.Host, - Port: provider.providerConfiguration.Port, - ProviderID: provider.providerConfiguration.ProviderID, - Selector: provider.providerConfiguration.Selector, - TargetUri: provider.providerConfiguration.TargetUri, - TLSEnabled: provider.providerConfiguration.TLSEnabled, - OfflineFlagSource: provider.providerConfiguration.OfflineFlagSourcePath, - CustomSyncProvider: provider.providerConfiguration.CustomSyncProvider, - CustomSyncProviderUri: provider.providerConfiguration.CustomSyncProviderUri, + Host: provider.providerConfiguration.Host, + Port: provider.providerConfiguration.Port, + ProviderID: provider.providerConfiguration.ProviderID, + Selector: provider.providerConfiguration.Selector, + TargetUri: provider.providerConfiguration.TargetUri, + TLSEnabled: provider.providerConfiguration.TLSEnabled, + OfflineFlagSource: provider.providerConfiguration.OfflineFlagSourcePath, + CustomSyncProvider: provider.providerConfiguration.CustomSyncProvider, + CustomSyncProviderUri: provider.providerConfiguration.CustomSyncProviderUri, + GrpcDialOptionsOverride: provider.providerConfiguration.GrpcDialOptionsOverride, }) } @@ -356,3 +358,13 @@ func WithCustomSyncProviderAndUri(customSyncProvider sync.ISync, customSyncProvi p.providerConfiguration.CustomSyncProviderUri = customSyncProviderUri } } + +// WithGrpcDialOptionsOverride provides a set of custom grps.DialOption that will fully override the gRPC dial options used by +// the InProcess resolver with gRPC syncer. All the other provider options that also set dial options (e.g. WithTLS, or WithCertificatePath) +// will be silently ignored. +// This is only useful with inProcess resolver type +func WithGrpcDialOptionsOverride(grpcDialOptionsOverride []grpc.DialOption) ProviderOption { + return func(p *Provider) { + p.providerConfiguration.GrpcDialOptionsOverride = grpcDialOptionsOverride + } +} diff --git a/providers/flagd/pkg/provider_test.go b/providers/flagd/pkg/provider_test.go index 53a57dcfa..d7b03fbdc 100644 --- a/providers/flagd/pkg/provider_test.go +++ b/providers/flagd/pkg/provider_test.go @@ -1,6 +1,7 @@ package flagd import ( + "reflect" "testing" "github.com/open-feature/flagd/core/pkg/sync" @@ -9,29 +10,36 @@ import ( process "github.com/open-feature/go-sdk-contrib/providers/flagd/pkg/service/in_process" of "github.com/open-feature/go-sdk/openfeature" "go.uber.org/mock/gomock" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" ) func TestNewProvider(t *testing.T) { customSyncProvider := process.NewDoNothingCustomSyncProvider() + gRPCDialOptionOverride := []grpc.DialOption{ + grpc.WithTransportCredentials(insecure.NewCredentials()), + grpc.WithAuthority("test-authority"), + } tests := []struct { - name string - expectedResolver ResolverType - expectPort uint16 - expectHost string - expectTargetUri string - expectCacheType cache.Type - expectCertPath string - expectMaxRetries int - expectCacheSize int - expectOtelIntercept bool - expectSocketPath string - expectTlsEnabled bool - expectProviderID string - expectSelector string - expectCustomSyncProvider sync.ISync - expectCustomSyncProviderUri string - options []ProviderOption + name string + expectedResolver ResolverType + expectPort uint16 + expectHost string + expectTargetUri string + expectCacheType cache.Type + expectCertPath string + expectMaxRetries int + expectCacheSize int + expectOtelIntercept bool + expectSocketPath string + expectTlsEnabled bool + expectProviderID string + expectSelector string + expectCustomSyncProvider sync.ISync + expectCustomSyncProviderUri string + expectGrpcDialOptionsOverride []grpc.DialOption + options []ProviderOption }{ { name: "default construction", @@ -173,6 +181,20 @@ func TestNewProvider(t *testing.T) { WithCustomSyncProvider(customSyncProvider), }, }, + { + name: "with gRPC DialOptions override with in-process resolver", + expectedResolver: inProcess, + expectHost: defaultHost, + expectPort: defaultInProcessPort, + expectCacheType: defaultCache, + expectCacheSize: defaultMaxCacheSize, + expectMaxRetries: defaultMaxEventStreamRetries, + expectGrpcDialOptionsOverride: gRPCDialOptionOverride, + options: []ProviderOption{ + WithInProcessResolver(), + WithGrpcDialOptionsOverride(gRPCDialOptionOverride), + }, + }, { name: "with selector and providerID with in-process resolver", expectedResolver: inProcess, @@ -295,6 +317,18 @@ func TestNewProvider(t *testing.T) { test.expectCustomSyncProviderUri, config.CustomSyncProviderUri) } + if test.expectGrpcDialOptionsOverride != nil { + if config.GrpcDialOptionsOverride == nil { + t.Errorf("incorrent configuration GrpcDialOptionsOverride, expected %v, got nil", config.GrpcDialOptionsOverride) + } else if !reflect.DeepEqual(config.GrpcDialOptionsOverride, test.expectGrpcDialOptionsOverride) { + t.Errorf("incorrent configuration GrpcDialOptionsOverride, expected %v, got %v", test.expectGrpcDialOptionsOverride, config.GrpcDialOptionsOverride) + } + } else { + if config.GrpcDialOptionsOverride != nil { + t.Errorf("incorrent configuration GrpcDialOptionsOverride, expected nil, got %v", config.GrpcDialOptionsOverride) + } + } + // this line will fail linting if this provider is no longer compatible with the openfeature sdk var _ of.FeatureProvider = flagdProvider }) diff --git a/providers/flagd/pkg/service/in_process/service.go b/providers/flagd/pkg/service/in_process/service.go index 4031b5fe7..a73691523 100644 --- a/providers/flagd/pkg/service/in_process/service.go +++ b/providers/flagd/pkg/service/in_process/service.go @@ -7,6 +7,8 @@ import ( "regexp" parallel "sync" + googlegrpc "google.golang.org/grpc" + "github.com/open-feature/flagd/core/pkg/evaluator" "github.com/open-feature/flagd/core/pkg/logger" "github.com/open-feature/flagd/core/pkg/model" @@ -33,15 +35,16 @@ type InProcess struct { } type Configuration struct { - Host any - Port any - TargetUri string - ProviderID string - Selector string - TLSEnabled bool - OfflineFlagSource string - CustomSyncProvider sync.ISync - CustomSyncProviderUri string + Host any + Port any + TargetUri string + ProviderID string + Selector string + TLSEnabled bool + OfflineFlagSource string + CustomSyncProvider sync.ISync + CustomSyncProviderUri string + GrpcDialOptionsOverride []googlegrpc.DialOption } func NewInProcessService(cfg Configuration) *InProcess { @@ -301,12 +304,13 @@ func makeSyncProvider(cfg Configuration, log *logger.Logger) (sync.ISync, string log.Info("operating in in-process mode with flags sourced from " + uri) return &grpc.Sync{ - CredentialBuilder: &credentials.CredentialBuilder{}, - Logger: log, - Secure: cfg.TLSEnabled, - ProviderID: cfg.ProviderID, - Selector: cfg.Selector, - URI: uri, + CredentialBuilder: &credentials.CredentialBuilder{}, + GrpcDialOptionsOverride: cfg.GrpcDialOptionsOverride, + Logger: log, + Secure: cfg.TLSEnabled, + ProviderID: cfg.ProviderID, + Selector: cfg.Selector, + URI: uri, }, uri } From 270f5e55a8ac7e64a69b7671863aaa1c5bc27c5c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 22 Feb 2025 09:19:38 -0500 Subject: [PATCH 15/24] chore(main): release providers/flagd 0.2.6 (#635) Signed-off-by: OpenFeature Bot <109696520+openfeaturebot@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Signed-off-by: bbland1 <104288486+bbland1@users.noreply.github.com> --- .release-please-manifest.json | 2 +- providers/flagd/CHANGELOG.md | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 8f27a29b3..8b5f90cf0 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -2,7 +2,7 @@ "hooks/open-telemetry": "0.3.4", "hooks/validator": "0.1.6", "providers/configcat": "0.2.1", - "providers/flagd": "0.2.5", + "providers/flagd": "0.2.6", "providers/flipt": "0.1.3", "providers/from-env": "0.1.5", "providers/go-feature-flag": "0.2.3", diff --git a/providers/flagd/CHANGELOG.md b/providers/flagd/CHANGELOG.md index 140e95228..2bfcb0fba 100644 --- a/providers/flagd/CHANGELOG.md +++ b/providers/flagd/CHANGELOG.md @@ -1,5 +1,22 @@ # Changelog +## [0.2.6](https://github.com/open-feature/go-sdk-contrib/compare/providers/flagd/v0.2.5...providers/flagd/v0.2.6) (2025-02-22) + + +### 🐛 Bug Fixes + +* **flagd:** Fixed possible nil pointer exception with svcMetadata in service.go ([#634](https://github.com/open-feature/go-sdk-contrib/issues/634)) ([50256e9](https://github.com/open-feature/go-sdk-contrib/commit/50256e9af89201ca09f3989161afd5a069d3a06e)) + + +### ✨ New Features + +* **flagd:** Added WithGrpcDialOptionsOverride provider option ([#638](https://github.com/open-feature/go-sdk-contrib/issues/638)) ([fe904bb](https://github.com/open-feature/go-sdk-contrib/commit/fe904bb054be86ca8e1cafa8577e8ac152dfefc8)) + + +### 🧹 Chore + +* **flagd:** Updates flagd core to v0.11.2 ([#636](https://github.com/open-feature/go-sdk-contrib/issues/636)) ([99d1a0c](https://github.com/open-feature/go-sdk-contrib/commit/99d1a0c9d206102774c8a83b2f40e2a33b29309f)) + ## [0.2.5](https://github.com/open-feature/go-sdk-contrib/compare/providers/flagd/v0.2.4...providers/flagd/v0.2.5) (2025-02-18) From 0067b34873211048f98a640d2b355bd7142619bb Mon Sep 17 00:00:00 2001 From: Todd Baert Date: Fri, 28 Feb 2025 11:36:43 -0500 Subject: [PATCH 16/24] =?UTF-8?q?fix(deps):=20Remove=20dependency=20on=20s?= =?UTF-8?q?igs.k8s.io/controller-runtime/pkg/lo=E2=80=A6=20(#639)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: aimuz Co-authored-by: aimuz Signed-off-by: bbland1 <104288486+bbland1@users.noreply.github.com> --- providers/flagd/go.mod | 18 +---- providers/flagd/go.sum | 79 ------------------- .../flagd/pkg/service/in_process/service.go | 3 +- providers/flagd/pkg/service/in_process/zap.go | 47 +++++++++++ 4 files changed, 49 insertions(+), 98 deletions(-) create mode 100644 providers/flagd/pkg/service/in_process/zap.go diff --git a/providers/flagd/go.mod b/providers/flagd/go.mod index 63a218d00..c4b680ea2 100644 --- a/providers/flagd/go.mod +++ b/providers/flagd/go.mod @@ -18,11 +18,11 @@ require ( github.com/open-feature/go-sdk v1.11.0 github.com/open-feature/go-sdk-contrib/tests/flagd v1.4.1 go.uber.org/mock v0.5.0 + go.uber.org/zap v1.27.0 golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac golang.org/x/net v0.34.0 google.golang.org/grpc v1.70.0 google.golang.org/protobuf v1.36.5 - sigs.k8s.io/controller-runtime v0.19.0 ) require ( @@ -31,23 +31,15 @@ require ( github.com/cucumber/messages/go/v21 v21.0.1 // indirect github.com/diegoholiveira/jsonlogic/v3 v3.7.4 // indirect github.com/fsnotify/fsnotify v1.8.0 // indirect - github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-logr/zapr v1.3.0 // indirect github.com/gofrs/uuid v4.3.1+incompatible // indirect - github.com/gogo/protobuf v1.3.2 // indirect - github.com/google/gofuzz v1.2.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-memdb v1.3.4 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect - github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect github.com/open-feature/flagd-schemas v0.2.9-0.20250127221449-bb763438abc5 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/twmb/murmur3 v1.1.8 // indirect - github.com/x448/float16 v0.8.4 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect @@ -57,17 +49,9 @@ require ( go.opentelemetry.io/otel/metric v1.34.0 // indirect go.opentelemetry.io/otel/trace v1.34.0 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.27.0 // indirect golang.org/x/mod v0.23.0 // indirect golang.org/x/sys v0.30.0 // indirect golang.org/x/text v0.22.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect - gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apimachinery v0.31.4 // indirect - k8s.io/klog/v2 v2.130.1 // indirect - k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect - sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect ) diff --git a/providers/flagd/go.sum b/providers/flagd/go.sum index 6450e262f..edad9c778 100644 --- a/providers/flagd/go.sum +++ b/providers/flagd/go.sum @@ -26,34 +26,20 @@ github.com/diegoholiveira/jsonlogic/v3 v3.7.4 h1:92HSmB9bwM/o0ZvrCpcvTP2EsPXSkKt github.com/diegoholiveira/jsonlogic/v3 v3.7.4/go.mod h1:OYRb6FSTVmMM+MNQ7ElmMsczyNSepw+OU4Z8emDSi4w= github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= -github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= -github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= -github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= -github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= -github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.3.1+incompatible h1:0/KbAdpx3UXAx1kEOWHJeOkpbgRFGHVgv+CFIY7dBJI= github.com/gofrs/uuid v4.3.1+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= -github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af h1:kmjWCqn2qkEml422C2Rrd27c3VGxi6a/6HNq8QmHRKM= -github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-immutable-radix v1.3.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= @@ -70,10 +56,6 @@ github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uG github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -83,15 +65,6 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= -github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= -github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= -github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= github.com/open-feature/flagd-schemas v0.2.9-0.20250127221449-bb763438abc5 h1:0RKCLYeQpvSsKR95kc894tm8GAZmq7bcG48v0KJ0HCs= github.com/open-feature/flagd-schemas v0.2.9-0.20250127221449-bb763438abc5/go.mod h1:WKtwo1eW9/K6D+4HfgTXWBqCDzpvMhDa5eRxW7R5B2U= github.com/open-feature/flagd/core v0.11.2 h1:3LAuLR2vXpBF80RwwCAu9JX898JasfPH7ErJEf5C5YA= @@ -121,8 +94,6 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/twmb/murmur3 v1.1.8 h1:8Yt9taO/WN3l08xErzjeschgZU2QSrwm1kclYq+0aRg= github.com/twmb/murmur3 v1.1.8/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ= -github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= -github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -130,8 +101,6 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHo github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= @@ -156,46 +125,19 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac h1:l5+whBCLH3iH2ZNHYLbAe58bo7yrN4mVcnkHDYz5vvs= golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac/go.mod h1:hH+7mtFmImwwcMvScyxUhjuVHR3HGaDPMn9rMSUUbxo= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= -golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f h1:OxYkA3wjPsZyBylwymxSHa7ViiW1Sml4ToBrncvFehI= google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50= google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= @@ -205,27 +147,6 @@ google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojt gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= -gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.31.4 h1:I2QNzitPVsPeLQvexMEsj945QumYraqv9m74isPDKhM= -k8s.io/api v0.31.4/go.mod h1:d+7vgXLvmcdT1BCo79VEgJxHHryww3V5np2OYTr6jdw= -k8s.io/apimachinery v0.31.4 h1:8xjE2C4CzhYVm9DGf60yohpNUh5AEBnPxCryPBECmlM= -k8s.io/apimachinery v0.31.4/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= -k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= -k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= -k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/controller-runtime v0.19.0 h1:nWVM7aq+Il2ABxwiCizrVDSlmDcshi9llbaFbC0ji/Q= -sigs.k8s.io/controller-runtime v0.19.0/go.mod h1:iRmWllt8IlaLjvTTDLhRBXIEtkCK6hwVBJJsYS9Ajf4= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= -sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= -sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= -sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/providers/flagd/pkg/service/in_process/service.go b/providers/flagd/pkg/service/in_process/service.go index a73691523..8dd75688e 100644 --- a/providers/flagd/pkg/service/in_process/service.go +++ b/providers/flagd/pkg/service/in_process/service.go @@ -19,7 +19,6 @@ import ( "github.com/open-feature/flagd/core/pkg/sync/grpc/credentials" of "github.com/open-feature/go-sdk/openfeature" "golang.org/x/exp/maps" - "sigs.k8s.io/controller-runtime/pkg/log/zap" ) // InProcess service implements flagd flag evaluation in-process. @@ -48,7 +47,7 @@ type Configuration struct { } func NewInProcessService(cfg Configuration) *InProcess { - log := logger.NewLogger(zap.NewRaw(), false) + log := logger.NewLogger(NewRaw(), false) iSync, uri := makeSyncProvider(cfg, log) diff --git a/providers/flagd/pkg/service/in_process/zap.go b/providers/flagd/pkg/service/in_process/zap.go new file mode 100644 index 000000000..2a888f885 --- /dev/null +++ b/providers/flagd/pkg/service/in_process/zap.go @@ -0,0 +1,47 @@ +package process + +import ( + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + "os" + "time" +) + +// EncoderConfigOption is a function that can modify a `zapcore.EncoderConfig`. +type EncoderConfigOption func(*zapcore.EncoderConfig) + +func newJSONEncoder(opts ...EncoderConfigOption) zapcore.Encoder { + encoderConfig := zap.NewProductionEncoderConfig() + for _, opt := range opts { + opt(&encoderConfig) + } + return zapcore.NewJSONEncoder(encoderConfig) +} + +// NewRaw returns a new zap.Logger configured with the passed Opts +// or their defaults. It uses KubeAwareEncoder which adds Type +// information and Namespace/Name to the log. +func NewRaw() *zap.Logger { + level := zap.NewAtomicLevelAt(zap.InfoLevel) + + var zapOpts []zap.Option + if level.Enabled(zapcore.Level(-2)) { + zapOpts = append(zapOpts, + zap.WrapCore(func(core zapcore.Core) zapcore.Core { + return zapcore.NewSamplerWithOptions(core, time.Second, 100, 100) + })) + } + zapOpts = append(zapOpts, zap.AddStacktrace(zap.NewAtomicLevelAt(zap.ErrorLevel))) + + f := func(ecfg *zapcore.EncoderConfig) { + ecfg.EncodeTime = zapcore.RFC3339TimeEncoder + } + encoder := newJSONEncoder(f) + + // this basically mimics NewConfig, but with a custom sink + sink := zapcore.AddSync(os.Stderr) + zapOpts = append(zapOpts, zap.ErrorOutput(sink)) + log := zap.New(zapcore.NewCore(encoder, sink, level)) + log = log.WithOptions(zapOpts...) + return log +} From 4e259c6f3776902410984b08f8134cefa0b3078d Mon Sep 17 00:00:00 2001 From: Thomas Poignant Date: Wed, 5 Mar 2025 14:20:10 +0100 Subject: [PATCH 17/24] chore(go-feature-flag): Support new hook format (#641) Signed-off-by: Thomas Poignant Signed-off-by: bbland1 <104288486+bbland1@users.noreply.github.com> --- .../pkg/hook/data_collector_hook.go | 14 +++----------- .../pkg/hook/evaluation_enrichment_hook.go | 16 +--------------- 2 files changed, 4 insertions(+), 26 deletions(-) diff --git a/providers/go-feature-flag/pkg/hook/data_collector_hook.go b/providers/go-feature-flag/pkg/hook/data_collector_hook.go index 16e99de95..dd7a476a0 100644 --- a/providers/go-feature-flag/pkg/hook/data_collector_hook.go +++ b/providers/go-feature-flag/pkg/hook/data_collector_hook.go @@ -13,10 +13,11 @@ func NewDataCollectorHook(dataCollectorManager *controller.DataCollectorManager) } type dataCollectorHook struct { + openfeature.UnimplementedHook dataCollectorManager *controller.DataCollectorManager } -func (d *dataCollectorHook) After(ctx context.Context, hookCtx openfeature.HookContext, +func (d *dataCollectorHook) After(_ context.Context, hookCtx openfeature.HookContext, evalDetails openfeature.InterfaceEvaluationDetails, hint openfeature.HookHints) error { if evalDetails.Reason != openfeature.CachedReason { // we send it only when cached because the evaluation will be collected directly in the relay-proxy @@ -37,7 +38,7 @@ func (d *dataCollectorHook) After(ctx context.Context, hookCtx openfeature.HookC return nil } -func (d *dataCollectorHook) Error(ctx context.Context, hookCtx openfeature.HookContext, +func (d *dataCollectorHook) Error(_ context.Context, hookCtx openfeature.HookContext, err error, hint openfeature.HookHints) { event := model.FeatureEvent{ Kind: "feature", @@ -52,12 +53,3 @@ func (d *dataCollectorHook) Error(ctx context.Context, hookCtx openfeature.HookC } _ = d.dataCollectorManager.AddEvent(event) } - -func (d *dataCollectorHook) Before(context.Context, openfeature.HookContext, openfeature.HookHints) (*openfeature.EvaluationContext, error) { - // Do nothing, needed to satisfy the interface - return nil, nil -} - -func (d *dataCollectorHook) Finally(context.Context, openfeature.HookContext, openfeature.HookHints) { - // Do nothing, needed to satisfy the interface -} diff --git a/providers/go-feature-flag/pkg/hook/evaluation_enrichment_hook.go b/providers/go-feature-flag/pkg/hook/evaluation_enrichment_hook.go index 71462a8f0..dfdf74c79 100644 --- a/providers/go-feature-flag/pkg/hook/evaluation_enrichment_hook.go +++ b/providers/go-feature-flag/pkg/hook/evaluation_enrichment_hook.go @@ -10,20 +10,10 @@ func NewEvaluationEnrichmentHook(exporterMetadata map[string]interface{}) openfe } type evaluationEnrichmentHook struct { + openfeature.UnimplementedHook exporterMetadata map[string]interface{} } -func (d *evaluationEnrichmentHook) After(_ context.Context, _ openfeature.HookContext, - _ openfeature.InterfaceEvaluationDetails, _ openfeature.HookHints) error { - // Do nothing, needed to satisfy the interface - return nil -} - -func (d *evaluationEnrichmentHook) Error(_ context.Context, _ openfeature.HookContext, - _ error, _ openfeature.HookHints) { - // Do nothing, needed to satisfy the interface -} - func (d *evaluationEnrichmentHook) Before(_ context.Context, hookCtx openfeature.HookContext, _ openfeature.HookHints) (*openfeature.EvaluationContext, error) { attributes := hookCtx.EvaluationContext().Attributes() if goffSpecific, ok := attributes["gofeatureflag"]; ok { @@ -39,7 +29,3 @@ func (d *evaluationEnrichmentHook) Before(_ context.Context, hookCtx openfeature newCtx := openfeature.NewEvaluationContext(hookCtx.EvaluationContext().TargetingKey(), attributes) return &newCtx, nil } - -func (d *evaluationEnrichmentHook) Finally(context.Context, openfeature.HookContext, openfeature.HookHints) { - // Do nothing, needed to satisfy the interface -} From e225fbd1acae6180337f58ab09b575882c67cb91 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 5 Mar 2025 18:45:54 +0100 Subject: [PATCH 18/24] chore(main): release providers/go-feature-flag 0.2.4 (#643) Signed-off-by: OpenFeature Bot <109696520+openfeaturebot@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Signed-off-by: bbland1 <104288486+bbland1@users.noreply.github.com> --- .release-please-manifest.json | 2 +- providers/go-feature-flag/CHANGELOG.md | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 8b5f90cf0..946168cdd 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -5,7 +5,7 @@ "providers/flagd": "0.2.6", "providers/flipt": "0.1.3", "providers/from-env": "0.1.5", - "providers/go-feature-flag": "0.2.3", + "providers/go-feature-flag": "0.2.4", "providers/gcp": "0.0.1", "providers/flagsmith": "0.1.4", "providers/launchdarkly": "0.1.5", diff --git a/providers/go-feature-flag/CHANGELOG.md b/providers/go-feature-flag/CHANGELOG.md index 4562b944b..9d8e1abb8 100644 --- a/providers/go-feature-flag/CHANGELOG.md +++ b/providers/go-feature-flag/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.2.4](https://github.com/open-feature/go-sdk-contrib/compare/providers/go-feature-flag/v0.2.3...providers/go-feature-flag/v0.2.4) (2025-03-05) + + +### 🧹 Chore + +* **go-feature-flag:** Support new hook format ([#641](https://github.com/open-feature/go-sdk-contrib/issues/641)) ([192d45a](https://github.com/open-feature/go-sdk-contrib/commit/192d45ae37a0e10b6831a87ca02729d84171b911)) + ## [0.2.3](https://github.com/open-feature/go-sdk-contrib/compare/providers/go-feature-flag/v0.2.2...providers/go-feature-flag/v0.2.3) (2025-02-10) From ac2f3145eca89af8d5dc0784704d17e6f53dd7a6 Mon Sep 17 00:00:00 2001 From: bbland1 <104288486+bbland1@users.noreply.github.com> Date: Fri, 7 Mar 2025 17:16:38 -0500 Subject: [PATCH 19/24] added test for MP Init method with mock providers that have Init methods Signed-off-by: bbland1 <104288486+bbland1@users.noreply.github.com> --- .release-please-manifest.json | 2 +- .../multi-provider/pkg/providers_test.go | 119 ++++++++++++++---- 2 files changed, 94 insertions(+), 27 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 946168cdd..5b2d4f2db 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -16,5 +16,5 @@ "providers/prefab": "0.0.2", "tests/flagd": "1.4.1", "providers/go-feature-flag-in-process": "0.1.0", - "providers/multi-provider": "0.0.1" + "providers/multi-provider": "0.0.2" } diff --git a/providers/multi-provider/pkg/providers_test.go b/providers/multi-provider/pkg/providers_test.go index ee7d792f4..1d9b08119 100644 --- a/providers/multi-provider/pkg/providers_test.go +++ b/providers/multi-provider/pkg/providers_test.go @@ -2,6 +2,7 @@ package multiprovider import ( "testing" + "time" "github.com/open-feature/go-sdk/openfeature" "github.com/open-feature/go-sdk/openfeature/hooks" @@ -9,6 +10,49 @@ import ( oft "github.com/open-feature/go-sdk/openfeature/testing" ) +// MockProvider utilizes openfeature's TestProvider to add testable Init & Shutdown methods to test the MultiProvider functionality +type MockProvider struct { + oft.TestProvider + InitCount *int +} + +func (m *MockProvider) Init(evalCtx openfeature.EvaluationContext) error { + *m.InitCount += 1 + return nil +} + +func (m *MockProvider) Shutdown() { +} + +func NewMockProvider(initCount *int) *MockProvider { + return &MockProvider{ + TestProvider: oft.NewTestProvider(), + InitCount: initCount, + } +} + +// MockProviderDelay utilizes openfeature's TestProvider to add testable Init & Shutdown methods to test the MultiProvider functionality with a small delay making sure the the go routines properly wait. +type MockProviderDelay struct { + oft.TestProvider + InitCount *int +} + +func (m *MockProviderDelay) Init(evalCtx openfeature.EvaluationContext) error { + time.Sleep(1 * time.Millisecond) + *m.InitCount += 1 + return nil +} + +func (m *MockProviderDelay) Shutdown() { +} + +func NewMockProviderDelay(initCount *int) *MockProviderDelay { + return &MockProviderDelay{ + TestProvider: oft.NewTestProvider(), + InitCount: initCount, + } +} + func TestMultiProvider_ProvidersMethod(t *testing.T) { testProvider1 := oft.NewTestProvider() testProvider2 := oft.NewTestProvider() @@ -123,7 +167,7 @@ func TestMultiProvider_ProviderByNameMethod(t *testing.T) { } providers := mp.ProvidersByName() - + if len(providers) != 2 { t.Errorf("Expected there to be '2' providers as passed but got: '%d'", len(providers)) } @@ -177,31 +221,54 @@ func TestMultiProvider_MetaData(t *testing.T) { } } -// func TestMultiProvider_Init(t *testing.T) { -// testProvider1 := oft.NewTestProvider() -// testProvider2 := oft.NewTestProvider() - -// defaultLogger, err := hooks.NewLoggingHook(false) -// if err != nil { -// t.Errorf("Issue setting up logger,'%s'", err) -// } - -// mp, err := NewMultiProvider([]UniqueNameProvider{ -// { -// Provider: testProvider1, -// UniqueName: "provider1", -// }, { -// Provider: testProvider2, -// UniqueName: "provider2", -// }, -// }, "test", defaultLogger) - -// if err != nil { -// t.Errorf("Expected the multiprovider to successfully make an instance, '%s'", err) -// } - -// mp.Init() -// } +func TestMultiProvider_Init(t *testing.T) { + initializations := 0 + + testProvider1 := NewMockProvider(&initializations) + testProvider2 := oft.NewTestProvider() + testProvider3 := NewMockProviderDelay(&initializations) + + defaultLogger, err := hooks.NewLoggingHook(false) + if err != nil { + t.Errorf("Issue setting up logger,'%s'", err) + } + + mp, err := NewMultiProvider([]UniqueNameProvider{ + { + Provider: testProvider1, + UniqueName: "provider1", + }, { + Provider: testProvider2, + UniqueName: "provider2", + },{ + Provider: testProvider3, + UniqueName: "provider3", + }, + }, "test", defaultLogger) + + if err != nil { + t.Errorf("Expected the multiprovider to successfully make an instance, '%s'", err) + } + + attributes := map[string]interface{}{ + "foo": "bar", + } + evalCtx := openfeature.NewTargetlessEvaluationContext(attributes) + + err = mp.Init(evalCtx) + if err != nil { + t.Errorf("Expected the initialization process to be successful, got error: '%s'", err) + } + + if initializations == 0 { + t.Errorf("Expected there to be initializations, but none were ran.") + } + + if initializations != 2 { + t.Errorf("Expected there to be '2' init steps ran, but got: '%d'.", initializations) + } + +} func TestNewMultiProvider_ProviderUniqueNames(t *testing.T) { testProvider1 := memprovider.NewInMemoryProvider(map[string]memprovider.InMemoryFlag{ From 2d6f44b03f21216554d62cc76a36911e3d9febd9 Mon Sep 17 00:00:00 2001 From: bbland1 <104288486+bbland1@users.noreply.github.com> Date: Fri, 7 Mar 2025 17:57:24 -0500 Subject: [PATCH 20/24] added shutdown test confirming method run in MP when called Signed-off-by: bbland1 <104288486+bbland1@users.noreply.github.com> --- .../multi-provider/pkg/providers_test.go | 63 ++++++++++++++++--- 1 file changed, 56 insertions(+), 7 deletions(-) diff --git a/providers/multi-provider/pkg/providers_test.go b/providers/multi-provider/pkg/providers_test.go index 1d9b08119..12cc2d952 100644 --- a/providers/multi-provider/pkg/providers_test.go +++ b/providers/multi-provider/pkg/providers_test.go @@ -14,6 +14,7 @@ import ( type MockProvider struct { oft.TestProvider InitCount *int + ShutCount *int } func (m *MockProvider) Init(evalCtx openfeature.EvaluationContext) error { @@ -22,12 +23,14 @@ func (m *MockProvider) Init(evalCtx openfeature.EvaluationContext) error { } func (m *MockProvider) Shutdown() { + *m.ShutCount += 1 } -func NewMockProvider(initCount *int) *MockProvider { +func NewMockProvider(initCount *int, shutCount *int) *MockProvider { return &MockProvider{ TestProvider: oft.NewTestProvider(), - InitCount: initCount, + InitCount: initCount, + ShutCount: shutCount, } } @@ -35,6 +38,7 @@ func NewMockProvider(initCount *int) *MockProvider { type MockProviderDelay struct { oft.TestProvider InitCount *int + ShutCount *int } func (m *MockProviderDelay) Init(evalCtx openfeature.EvaluationContext) error { @@ -44,12 +48,15 @@ func (m *MockProviderDelay) Init(evalCtx openfeature.EvaluationContext) error { } func (m *MockProviderDelay) Shutdown() { + time.Sleep(2 * time.Millisecond) + *m.ShutCount += 1 } -func NewMockProviderDelay(initCount *int) *MockProviderDelay { +func NewMockProviderDelay(initCount *int, shutCount *int) *MockProviderDelay { return &MockProviderDelay{ TestProvider: oft.NewTestProvider(), - InitCount: initCount, + InitCount: initCount, + ShutCount: shutCount, } } @@ -223,10 +230,11 @@ func TestMultiProvider_MetaData(t *testing.T) { func TestMultiProvider_Init(t *testing.T) { initializations := 0 + shutdowns := 0 - testProvider1 := NewMockProvider(&initializations) + testProvider1 := NewMockProvider(&initializations, &shutdowns) testProvider2 := oft.NewTestProvider() - testProvider3 := NewMockProviderDelay(&initializations) + testProvider3 := NewMockProviderDelay(&initializations, &shutdowns) defaultLogger, err := hooks.NewLoggingHook(false) if err != nil { @@ -240,7 +248,7 @@ func TestMultiProvider_Init(t *testing.T) { }, { Provider: testProvider2, UniqueName: "provider2", - },{ + }, { Provider: testProvider3, UniqueName: "provider3", }, @@ -270,6 +278,47 @@ func TestMultiProvider_Init(t *testing.T) { } +func TestMultiProvider_Shutdown(t *testing.T) { + initializations := 0 + shutdowns := 0 + + testProvider1 := NewMockProvider(&initializations, &shutdowns) + testProvider2 := oft.NewTestProvider() + testProvider3 := NewMockProviderDelay(&initializations, &shutdowns) + + defaultLogger, err := hooks.NewLoggingHook(false) + if err != nil { + t.Errorf("Issue setting up logger,'%s'", err) + } + + mp, err := NewMultiProvider([]UniqueNameProvider{ + { + Provider: testProvider1, + UniqueName: "provider1", + }, { + Provider: testProvider2, + UniqueName: "provider2", + }, { + Provider: testProvider3, + UniqueName: "provider3", + }, + }, "test", defaultLogger) + + if err != nil { + t.Errorf("Expected the multiprovider to successfully make an instance, '%s'", err) + } + + mp.Shutdown() + + if shutdowns == 0 { + t.Errorf("Expected there to be shutdowns, but none were ran.") + } + + if shutdowns != 2 { + t.Errorf("Expected there to be '2' shutdown steps ran, but got: '%d'.", shutdowns) + } +} + func TestNewMultiProvider_ProviderUniqueNames(t *testing.T) { testProvider1 := memprovider.NewInMemoryProvider(map[string]memprovider.InMemoryFlag{ "boolFlag": { From 11abc28f8c29876fb46fe2fc7dbc9e3c77b1e8a2 Mon Sep 17 00:00:00 2001 From: bbland1 <104288486+bbland1@users.noreply.github.com> Date: Sat, 8 Mar 2025 23:33:14 -0500 Subject: [PATCH 21/24] added the empty bases of the evaluations and hooks methods Signed-off-by: bbland1 <104288486+bbland1@users.noreply.github.com> --- providers/multi-provider/pkg/providers.go | 49 ++++++++++++++++++++--- 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/providers/multi-provider/pkg/providers.go b/providers/multi-provider/pkg/providers.go index 51ffa6863..d35377cf8 100644 --- a/providers/multi-provider/pkg/providers.go +++ b/providers/multi-provider/pkg/providers.go @@ -1,6 +1,7 @@ package multiprovider import ( + "context" "errors" "fmt" "sync" @@ -68,12 +69,6 @@ func (mp *MultiProvider) ProviderByName(name string) (UniqueNameProvider, bool) return provider, exists } -// Metadata provides the name `multiprovider` and the names of each provider passed. -func (mp *MultiProvider) Metadata() openfeature.Metadata { - - return openfeature.Metadata{Name: "multiprovider"} -} - // registerProviders ensures that when setting up an instant of MultiProvider the providers provided either have a unique name or the base `metadata.Name` is made unique by adding an indexed based number to it. // registerProviders also stores the providers by their unique name and in an array for easy usage. func registerProviders(mp *MultiProvider, providers []UniqueNameProvider) error { @@ -112,6 +107,48 @@ func registerProviders(mp *MultiProvider, providers []UniqueNameProvider) error return nil } +// Metadata provides the name `multiprovider` and the names of each provider passed. +func (mp *MultiProvider) Metadata() openfeature.Metadata { + + return openfeature.Metadata{Name: "multiprovider"} +} + +// Hooks returns a collection of openfeature.Hook defined by this provider +func (mp *MultiProvider) Hooks() []openfeature.Hook { + // Hooks that should be included with the provider + return []openfeature.Hook{} +} + +// BooleanEvaluation returns a boolean flag +func (mp *MultiProvider) BooleanEvaluation(ctx context.Context, flag string, defaultValue bool, evalCtx openfeature.FlattenedContext) openfeature.BoolResolutionDetail { + // code to evaluate boolean + return openfeature.BoolResolutionDetail{} +} + +// StringEvaluation returns a string flag +func (mp *MultiProvider) StringEvaluation(ctx context.Context, flag string, defaultValue string, evalCtx openfeature.FlattenedContext) openfeature.StringResolutionDetail { + // code to evaluate string + return openfeature.StringResolutionDetail{} +} + +// FloatEvaluation returns a float flag +func (mp *MultiProvider) FloatEvaluation(ctx context.Context, flag string, defaultValue float64, evalCtx openfeature.FlattenedContext) openfeature.FloatResolutionDetail { + // code to evaluate float + return openfeature.FloatResolutionDetail{} +} + +// IntEvaluation returns an int flag +func (mp *MultiProvider) IntEvaluation(ctx context.Context, flag string, defaultValue int64, evalCtx openfeature.FlattenedContext) openfeature.IntResolutionDetail { + // code to evaluate int + return openfeature.IntResolutionDetail{} +} + +// ObjectEvaluation returns an object flag +func (mp *MultiProvider) ObjectEvaluation(ctx context.Context, flag string, defaultValue interface{}, evalCtx openfeature.FlattenedContext) openfeature.InterfaceResolutionDetail { + // code to evaluate object + return openfeature.InterfaceResolutionDetail{} +} + // Init will run the initialize method for all of provides and aggregate the errors. func (mp *MultiProvider) Init(evalCtx openfeature.EvaluationContext) error { var wg sync.WaitGroup From 1939205b2b7c85c71cb4dd7bf1a1e0c19ff45dbb Mon Sep 17 00:00:00 2001 From: bbland1 <104288486+bbland1@users.noreply.github.com> Date: Sun, 9 Mar 2025 04:33:12 -0400 Subject: [PATCH 22/24] added test for init errors by a provider and reduced the mock provider struct made Signed-off-by: bbland1 <104288486+bbland1@users.noreply.github.com> --- .../internal/aggregate-errors.go | 21 ++- providers/multi-provider/pkg/providers.go | 2 +- .../multi-provider/pkg/providers_test.go | 133 +++++++++++++----- 3 files changed, 114 insertions(+), 42 deletions(-) diff --git a/providers/multi-provider/internal/aggregate-errors.go b/providers/multi-provider/internal/aggregate-errors.go index e974e9c05..4d1808218 100644 --- a/providers/multi-provider/internal/aggregate-errors.go +++ b/providers/multi-provider/internal/aggregate-errors.go @@ -1,11 +1,15 @@ package internal -import "fmt" +import ( + "encoding/json" + "fmt" +) -// StateErr is how the error in the Init of Shutdown stage of a provider is reported. +// StateErr is how the error in the Init stage of a provider is reported. type StateErr struct { - ProviderName string - Err error + ProviderName string `json:"source"` + Err error `json:"-"` + ErrMessage string `json:"error"` } func (e *StateErr) Error() string { @@ -13,12 +17,15 @@ func (e *StateErr) Error() string { } type AggregateError struct { - Message string - Errors []StateErr + Message string `json:"message"` + Errors []StateErr `json:"errors"` } func (ae *AggregateError) Error() string { - return ae.Message + errorsJSON, _ := json.Marshal(ae.Errors) + + return fmt.Sprintf("%s\n%s", ae.Message, string(errorsJSON)) + } func (ae *AggregateError) Construct(providerErrors []StateErr) { diff --git a/providers/multi-provider/pkg/providers.go b/providers/multi-provider/pkg/providers.go index d35377cf8..17673dab0 100644 --- a/providers/multi-provider/pkg/providers.go +++ b/providers/multi-provider/pkg/providers.go @@ -160,7 +160,7 @@ func (mp *MultiProvider) Init(evalCtx openfeature.EvaluationContext) error { defer wg.Done() if stateHandle, ok := p.Provider.(openfeature.StateHandler); ok { if initErr := stateHandle.Init(evalCtx); initErr != nil { - errChan <- err.StateErr{ProviderName: p.UniqueName, Err: initErr} + errChan <- err.StateErr{ProviderName: p.UniqueName, Err: initErr, ErrMessage: initErr.Error()} } } }(provider) diff --git a/providers/multi-provider/pkg/providers_test.go b/providers/multi-provider/pkg/providers_test.go index 12cc2d952..ae879c316 100644 --- a/providers/multi-provider/pkg/providers_test.go +++ b/providers/multi-provider/pkg/providers_test.go @@ -1,9 +1,14 @@ package multiprovider import ( + "encoding/json" + "fmt" + "strings" "testing" "time" + errs "github.com/open-feature/go-sdk-contrib/providers/multi-provider/internal" + "github.com/open-feature/go-sdk/openfeature" "github.com/open-feature/go-sdk/openfeature/hooks" "github.com/open-feature/go-sdk/openfeature/memprovider" @@ -15,48 +20,38 @@ type MockProvider struct { oft.TestProvider InitCount *int ShutCount *int + TestErr string + InitDelay int + ShutDelay int } func (m *MockProvider) Init(evalCtx openfeature.EvaluationContext) error { - *m.InitCount += 1 - return nil -} - -func (m *MockProvider) Shutdown() { - *m.ShutCount += 1 -} - -func NewMockProvider(initCount *int, shutCount *int) *MockProvider { - return &MockProvider{ - TestProvider: oft.NewTestProvider(), - InitCount: initCount, - ShutCount: shutCount, + if m.TestErr != "" { + return fmt.Errorf(m.TestErr) } -} - -// MockProviderDelay utilizes openfeature's TestProvider to add testable Init & Shutdown methods to test the MultiProvider functionality with a small delay making sure the the go routines properly wait. -type MockProviderDelay struct { - oft.TestProvider - InitCount *int - ShutCount *int -} -func (m *MockProviderDelay) Init(evalCtx openfeature.EvaluationContext) error { - time.Sleep(1 * time.Millisecond) + if m.InitDelay != 0 { + time.Sleep(time.Duration(m.InitDelay) * time.Millisecond) + } *m.InitCount += 1 return nil } -func (m *MockProviderDelay) Shutdown() { - time.Sleep(2 * time.Millisecond) +func (m *MockProvider) Shutdown() { + if m.ShutDelay != 0 { + time.Sleep(time.Duration(m.ShutDelay) * time.Millisecond) + } *m.ShutCount += 1 } -func NewMockProviderDelay(initCount *int, shutCount *int) *MockProviderDelay { - return &MockProviderDelay{ +func NewMockProvider(initCount *int, shutCount *int, testErr string, initDelay int, shutDelay int) *MockProvider { + return &MockProvider{ TestProvider: oft.NewTestProvider(), InitCount: initCount, ShutCount: shutCount, + TestErr: testErr, + InitDelay: initDelay, + ShutDelay: shutDelay, } } @@ -232,9 +227,9 @@ func TestMultiProvider_Init(t *testing.T) { initializations := 0 shutdowns := 0 - testProvider1 := NewMockProvider(&initializations, &shutdowns) + testProvider1 := NewMockProvider(&initializations, &shutdowns,"", 0, 0) testProvider2 := oft.NewTestProvider() - testProvider3 := NewMockProviderDelay(&initializations, &shutdowns) + testProvider3 := NewMockProvider(&initializations, &shutdowns, "", 1, 0) defaultLogger, err := hooks.NewLoggingHook(false) if err != nil { @@ -278,13 +273,82 @@ func TestMultiProvider_Init(t *testing.T) { } +func TestMultiProvider_InitErrorWithProvider(t *testing.T) { + initializations := 0 + shutdowns := 0 + + testProvider1 := oft.NewTestProvider() + testProvider2 := NewMockProvider(&initializations, &shutdowns, "test error 1 end", 0, 0) + testProvider3 := NewMockProvider(&initializations, &shutdowns, "test error 2 end", 0, 0) + + defaultLogger, err := hooks.NewLoggingHook(false) + if err != nil { + t.Errorf("Issue setting up logger,'%s'", err) + } + + mp, err := NewMultiProvider([]UniqueNameProvider{ + { + Provider: testProvider1, + UniqueName: "provider1", + }, { + Provider: testProvider2, + UniqueName: "provider2", + }, { + Provider: testProvider3, + UniqueName: "provider3", + }, + }, "test", defaultLogger) + + if err != nil { + t.Errorf("Expected the multiprovider to successfully make an instance, '%s'", err) + } + + attributes := map[string]interface{}{ + "foo": "bar", + } + evalCtx := openfeature.NewTargetlessEvaluationContext(attributes) + + err = mp.Init(evalCtx) + if err == nil { + t.Errorf("Expected the initialization process to throw an error.") + } + + var errors []errs.StateErr + + fullErr := err.Error() + fullErrArr := strings.SplitAfterN(fullErr, "end", 2) + errJSON := fullErrArr[1] + errMsg := fullErrArr[0] + + if !strings.Contains(errMsg, "Provider errors occurred:") { + t.Errorf("Expected the first line of error message to contain: '%s', got: '%s'", "Provider errors occurred:", errMsg) + } + + if err = json.Unmarshal([]byte(errJSON), &errors); err != nil { + t.Errorf("Failed to unmarshal error details: %v", err) + } + + if len(errors) != 2 { + t.Errorf("Expected there to be '2' errors found, got: '%d'", len(errors)) + } + + // if errors[0].ProviderName != "provider2" || errors[0].ErrMessage != "test error 1 end" { + // t.Errorf("Expected the first error to be for 'provider2' with 'test error 1 end', got: '%s' with '%s'", errors[0].ProviderName, errors[0].ErrMessage) + // } + + // if errors[1].ProviderName != "provider3" || errors[1].ErrMessage != "test error 1 end" { + // t.Errorf("Expected the second error to be for 'provider3' with 'test error 2 end', got: '%s' with '%s'", errors[1].ProviderName, errors[1].ErrMessage) + // } + +} + func TestMultiProvider_Shutdown(t *testing.T) { initializations := 0 shutdowns := 0 - testProvider1 := NewMockProvider(&initializations, &shutdowns) + testProvider1 := NewMockProvider(&initializations, &shutdowns, "", 0, 0) testProvider2 := oft.NewTestProvider() - testProvider3 := NewMockProviderDelay(&initializations, &shutdowns) + testProvider3 := NewMockProvider(&initializations, &shutdowns, "", 0, 2) defaultLogger, err := hooks.NewLoggingHook(false) if err != nil { @@ -405,6 +469,10 @@ func TestNewMultiProvider_DuplicateProviderGenerateUniqueNames(t *testing.T) { providerEntries := mp.Providers() + if len(providerEntries) != 4 { + t.Errorf("Expected there to be 4 provider entries, got: '%d'", len(providerEntries)) + } + if providerEntries[0].UniqueName != "InMemoryProvider" { t.Errorf("Expected unique provider name to be: 'InMemoryProvider', got: '%s'", providerEntries[0].UniqueName) } @@ -418,9 +486,6 @@ func TestNewMultiProvider_DuplicateProviderGenerateUniqueNames(t *testing.T) { t.Errorf("Expected unique provider name to be: 'NoopProvider', got: '%s'", providerEntries[3].UniqueName) } - if len(providerEntries) != 4 { - t.Errorf("Expected there to be 4 provider entries, got: '%d'", len(providerEntries)) - } } func TestNewMultiProvider_ProvidersUsePassedNames(t *testing.T) { testProvider1 := oft.NewTestProvider() From fede2c694fcb1f56cbf16fa5c1505617ea57a699 Mon Sep 17 00:00:00 2001 From: bbland1 <104288486+bbland1@users.noreply.github.com> Date: Sun, 9 Mar 2025 04:57:04 -0400 Subject: [PATCH 23/24] removed memprovider since NewTestProvider uses it Signed-off-by: bbland1 <104288486+bbland1@users.noreply.github.com> --- .../multi-provider/pkg/providers_test.go | 84 ++++++++----------- 1 file changed, 37 insertions(+), 47 deletions(-) diff --git a/providers/multi-provider/pkg/providers_test.go b/providers/multi-provider/pkg/providers_test.go index ae879c316..c9794128e 100644 --- a/providers/multi-provider/pkg/providers_test.go +++ b/providers/multi-provider/pkg/providers_test.go @@ -11,7 +11,6 @@ import ( "github.com/open-feature/go-sdk/openfeature" "github.com/open-feature/go-sdk/openfeature/hooks" - "github.com/open-feature/go-sdk/openfeature/memprovider" oft "github.com/open-feature/go-sdk/openfeature/testing" ) @@ -23,6 +22,7 @@ type MockProvider struct { TestErr string InitDelay int ShutDelay int + MockMeta string } func (m *MockProvider) Init(evalCtx openfeature.EvaluationContext) error { @@ -44,7 +44,11 @@ func (m *MockProvider) Shutdown() { *m.ShutCount += 1 } -func NewMockProvider(initCount *int, shutCount *int, testErr string, initDelay int, shutDelay int) *MockProvider { +func (m *MockProvider) Metadata() openfeature.Metadata { + return openfeature.Metadata{Name: m.MockMeta} +} + +func NewMockProvider(initCount *int, shutCount *int, testErr string, initDelay int, shutDelay int, meta string) *MockProvider { return &MockProvider{ TestProvider: oft.NewTestProvider(), InitCount: initCount, @@ -52,6 +56,7 @@ func NewMockProvider(initCount *int, shutCount *int, testErr string, initDelay i TestErr: testErr, InitDelay: initDelay, ShutDelay: shutDelay, + MockMeta: meta, } } @@ -188,8 +193,11 @@ func TestMultiProvider_ProviderByNameMethod(t *testing.T) { // todo: currently the `multiProvider.Metadata()` just give the `Name` of the multi provider it doesn't aggregate the passed providers as stated in this specification https://openfeature.dev/specification/appendix-a/#metadata so this test fails func TestMultiProvider_MetaData(t *testing.T) { + initializations := 0 + shutdowns := 0 + testProvider1 := oft.NewTestProvider() - testProvider2 := oft.NewTestProvider() + testProvider2 := NewMockProvider(&initializations, &shutdowns, "", 0, 0, "test2") defaultLogger, err := hooks.NewLoggingHook(false) if err != nil { @@ -214,7 +222,7 @@ func TestMultiProvider_MetaData(t *testing.T) { Name: "multiprovider", OriginalMetadata: map[string]openfeature.Metadata{ "provider1": openfeature.Metadata{Name: "NoopProvider"}, - "provider2": openfeature.Metadata{Name: "NoopProvider"}, + "provider2": openfeature.Metadata{Name: "test2"}, }, } @@ -227,9 +235,9 @@ func TestMultiProvider_Init(t *testing.T) { initializations := 0 shutdowns := 0 - testProvider1 := NewMockProvider(&initializations, &shutdowns,"", 0, 0) + testProvider1 := NewMockProvider(&initializations, &shutdowns, "", 0, 0, "test1") testProvider2 := oft.NewTestProvider() - testProvider3 := NewMockProvider(&initializations, &shutdowns, "", 1, 0) + testProvider3 := NewMockProvider(&initializations, &shutdowns, "", 1, 0, "test3") defaultLogger, err := hooks.NewLoggingHook(false) if err != nil { @@ -278,8 +286,8 @@ func TestMultiProvider_InitErrorWithProvider(t *testing.T) { shutdowns := 0 testProvider1 := oft.NewTestProvider() - testProvider2 := NewMockProvider(&initializations, &shutdowns, "test error 1 end", 0, 0) - testProvider3 := NewMockProvider(&initializations, &shutdowns, "test error 2 end", 0, 0) + testProvider2 := NewMockProvider(&initializations, &shutdowns, "test error 1 end", 0, 0, "test2") + testProvider3 := NewMockProvider(&initializations, &shutdowns, "test error 2 end", 0, 0, "test3") defaultLogger, err := hooks.NewLoggingHook(false) if err != nil { @@ -346,9 +354,9 @@ func TestMultiProvider_Shutdown(t *testing.T) { initializations := 0 shutdowns := 0 - testProvider1 := NewMockProvider(&initializations, &shutdowns, "", 0, 0) + testProvider1 := NewMockProvider(&initializations, &shutdowns, "", 0, 0, "test1") testProvider2 := oft.NewTestProvider() - testProvider3 := NewMockProvider(&initializations, &shutdowns, "", 0, 2) + testProvider3 := NewMockProvider(&initializations, &shutdowns, "", 0, 2, "test3") defaultLogger, err := hooks.NewLoggingHook(false) if err != nil { @@ -384,19 +392,11 @@ func TestMultiProvider_Shutdown(t *testing.T) { } func TestNewMultiProvider_ProviderUniqueNames(t *testing.T) { - testProvider1 := memprovider.NewInMemoryProvider(map[string]memprovider.InMemoryFlag{ - "boolFlag": { - Key: "boolFlag", - State: memprovider.Enabled, - DefaultVariant: "true", - Variants: map[string]interface{}{ - "true": true, - "false": false, - }, - ContextEvaluator: nil, - }, - }) - testProvider2 := oft.NewTestProvider() + initializations := 0 + shutdowns := 0 + + testProvider1 := oft.NewTestProvider() + testProvider2 := NewMockProvider(&initializations, &shutdowns, "", 0, 0, "test2") defaultLogger, err := hooks.NewLoggingHook(false) if err != nil { @@ -417,11 +417,12 @@ func TestNewMultiProvider_ProviderUniqueNames(t *testing.T) { providerEntries := mp.Providers() - if providerEntries[0].UniqueName != "InMemoryProvider" { - t.Errorf("Expected unique provider name to be: 'InMemoryProvider', got: '%s'", providerEntries[0].UniqueName) + if providerEntries[0].UniqueName != "NoopProvider" { + t.Errorf("Expected unique provider name to be: 'NoopProvider', got: '%s'", providerEntries[0].UniqueName) } - if providerEntries[1].UniqueName != "NoopProvider" { - t.Errorf("Expected unique provider name to be: 'NoopProvider', got: '%s'", providerEntries[1].UniqueName) + + if providerEntries[1].UniqueName != "test2" { + t.Errorf("Expected unique provider name to be: 'test2', got: '%s'", providerEntries[1].UniqueName) } if len(providerEntries) != 2 { @@ -430,18 +431,7 @@ func TestNewMultiProvider_ProviderUniqueNames(t *testing.T) { } func TestNewMultiProvider_DuplicateProviderGenerateUniqueNames(t *testing.T) { - testProvider1 := memprovider.NewInMemoryProvider(map[string]memprovider.InMemoryFlag{ - "boolFlag": { - Key: "boolFlag", - State: memprovider.Enabled, - DefaultVariant: "true", - Variants: map[string]interface{}{ - "true": true, - "false": false, - }, - ContextEvaluator: nil, - }, - }) + testProvider1 := oft.NewTestProvider() testProvider2 := oft.NewTestProvider() testProvider3 := oft.NewTestProvider() testProvider4 := oft.NewTestProvider() @@ -473,17 +463,17 @@ func TestNewMultiProvider_DuplicateProviderGenerateUniqueNames(t *testing.T) { t.Errorf("Expected there to be 4 provider entries, got: '%d'", len(providerEntries)) } - if providerEntries[0].UniqueName != "InMemoryProvider" { - t.Errorf("Expected unique provider name to be: 'InMemoryProvider', got: '%s'", providerEntries[0].UniqueName) + if providerEntries[0].UniqueName != "NoopProvider-1" { + t.Errorf("Expected unique provider name to be: 'NoopProvider-1', got: '%s'", providerEntries[0].UniqueName) } - if providerEntries[1].UniqueName != "NoopProvider-1" { - t.Errorf("Expected unique provider name to be: 'NoopProvider', got: '%s'", providerEntries[1].UniqueName) + if providerEntries[1].UniqueName != "NoopProvider-2" { + t.Errorf("Expected unique provider name to be: 'NoopProvider-2', got: '%s'", providerEntries[1].UniqueName) } - if providerEntries[2].UniqueName != "NoopProvider-2" { - t.Errorf("Expected unique provider name to be: 'NoopProvider', got: '%s'", providerEntries[2].UniqueName) + if providerEntries[2].UniqueName != "NoopProvider-3" { + t.Errorf("Expected unique provider name to be: 'NoopProvider-3', got: '%s'", providerEntries[2].UniqueName) } - if providerEntries[3].UniqueName != "NoopProvider-3" { - t.Errorf("Expected unique provider name to be: 'NoopProvider', got: '%s'", providerEntries[3].UniqueName) + if providerEntries[3].UniqueName != "NoopProvider-4" { + t.Errorf("Expected unique provider name to be: 'NoopProvider-4', got: '%s'", providerEntries[3].UniqueName) } } From 9a96d942e9fdcb3e908655aa311c728d6677da98 Mon Sep 17 00:00:00 2001 From: bbland1 <104288486+bbland1@users.noreply.github.com> Date: Sun, 9 Mar 2025 05:52:00 -0400 Subject: [PATCH 24/24] added metadata aggregate to the method and updated test to properly use Signed-off-by: bbland1 <104288486+bbland1@users.noreply.github.com> --- .../internal/aggregate-errors.go | 5 ++++- providers/multi-provider/pkg/providers.go | 19 ++++++++++++------- .../multi-provider/pkg/providers_test.go | 19 ++++++++----------- 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/providers/multi-provider/internal/aggregate-errors.go b/providers/multi-provider/internal/aggregate-errors.go index 4d1808218..5b7ccbcf0 100644 --- a/providers/multi-provider/internal/aggregate-errors.go +++ b/providers/multi-provider/internal/aggregate-errors.go @@ -22,7 +22,10 @@ type AggregateError struct { } func (ae *AggregateError) Error() string { - errorsJSON, _ := json.Marshal(ae.Errors) + errorsJSON, err := json.Marshal(ae.Errors) + if err != nil { + return fmt.Sprintf("Error in json marshal of errors, %s", err) + } return fmt.Sprintf("%s\n%s", ae.Message, string(errorsJSON)) diff --git a/providers/multi-provider/pkg/providers.go b/providers/multi-provider/pkg/providers.go index 17673dab0..5b8b3363f 100644 --- a/providers/multi-provider/pkg/providers.go +++ b/providers/multi-provider/pkg/providers.go @@ -2,6 +2,7 @@ package multiprovider import ( "context" + "encoding/json" "errors" "fmt" "sync" @@ -25,15 +26,15 @@ type UniqueNameProvider struct { // MultiMetadata defines the return of the MultiProvider metadata with the aggregated data of all the providers. type MultiMetadata struct { - Name string - OriginalMetadata map[string]openfeature.Metadata + Name string `json:"name"` + OriginalMetadata map[string]openfeature.Metadata `json:"originalMetadata"` } // MultiProvider implements openfeature `FeatureProvider` in a way to accept an array of providers. type MultiProvider struct { providersEntries []UniqueNameProvider providersEntriesByName map[string]UniqueNameProvider - AggregatedMetadata map[string]openfeature.Metadata + AggregatedMetadata MultiMetadata EvaluationStrategy string events chan openfeature.Event status openfeature.State @@ -45,7 +46,10 @@ func NewMultiProvider(passedProviders []UniqueNameProvider, evaluationStrategy s multiProvider := &MultiProvider{ providersEntries: []UniqueNameProvider{}, providersEntriesByName: map[string]UniqueNameProvider{}, - AggregatedMetadata: map[string]openfeature.Metadata{}, + AggregatedMetadata: MultiMetadata{ + Name: "multiprovider", + OriginalMetadata: map[string]openfeature.Metadata{}, + }, } err := registerProviders(multiProvider, passedProviders) @@ -93,14 +97,14 @@ func registerProviders(mp *MultiProvider, providers []UniqueNameProvider) error providers[0].UniqueName = name mp.providersEntries = append(mp.providersEntries, providers[0]) mp.providersEntriesByName[name] = providers[0] - mp.AggregatedMetadata[name] = providers[0].Provider.Metadata() + mp.AggregatedMetadata.OriginalMetadata[name] = providers[0].Provider.Metadata() } else { for i, provider := range providers { uniqueName := fmt.Sprintf("%s-%d", name, i+1) provider.UniqueName = uniqueName mp.providersEntries = append(mp.providersEntries, provider) mp.providersEntriesByName[uniqueName] = provider - mp.AggregatedMetadata[uniqueName] = provider.Provider.Metadata() + mp.AggregatedMetadata.OriginalMetadata[uniqueName] = provider.Provider.Metadata() } } } @@ -109,8 +113,9 @@ func registerProviders(mp *MultiProvider, providers []UniqueNameProvider) error // Metadata provides the name `multiprovider` and the names of each provider passed. func (mp *MultiProvider) Metadata() openfeature.Metadata { + metaJSON, _ := json.Marshal(mp.AggregatedMetadata) - return openfeature.Metadata{Name: "multiprovider"} + return openfeature.Metadata{Name: string(metaJSON)} } // Hooks returns a collection of openfeature.Hook defined by this provider diff --git a/providers/multi-provider/pkg/providers_test.go b/providers/multi-provider/pkg/providers_test.go index c9794128e..16d7117e7 100644 --- a/providers/multi-provider/pkg/providers_test.go +++ b/providers/multi-provider/pkg/providers_test.go @@ -218,16 +218,21 @@ func TestMultiProvider_MetaData(t *testing.T) { t.Errorf("Expected the multiprovider to successfully make an instance, '%s'", err) } - expectedMetadata := MultiMetadata{ + expectedJSON, err := json.Marshal(MultiMetadata{ Name: "multiprovider", OriginalMetadata: map[string]openfeature.Metadata{ "provider1": openfeature.Metadata{Name: "NoopProvider"}, "provider2": openfeature.Metadata{Name: "test2"}, }, + }) + if err != nil { + t.Errorf("Error in JSON marshal of the expected answer, '%s'", err) } - if mp.Metadata().Name != "hi" { - t.Errorf("Expected to see the aggregated metadata of all passed providers: '%s', got: '%s'", expectedMetadata, mp.Metadata().Name) + expectedMetadata := openfeature.Metadata{Name: string(expectedJSON)} + + if mp.Metadata() != expectedMetadata { + t.Errorf("Expected to see the aggregated metadata of all passed providers: '%s', got: '%s'", expectedMetadata, mp.Metadata()) } } @@ -340,14 +345,6 @@ func TestMultiProvider_InitErrorWithProvider(t *testing.T) { t.Errorf("Expected there to be '2' errors found, got: '%d'", len(errors)) } - // if errors[0].ProviderName != "provider2" || errors[0].ErrMessage != "test error 1 end" { - // t.Errorf("Expected the first error to be for 'provider2' with 'test error 1 end', got: '%s' with '%s'", errors[0].ProviderName, errors[0].ErrMessage) - // } - - // if errors[1].ProviderName != "provider3" || errors[1].ErrMessage != "test error 1 end" { - // t.Errorf("Expected the second error to be for 'provider3' with 'test error 2 end', got: '%s' with '%s'", errors[1].ProviderName, errors[1].ErrMessage) - // } - } func TestMultiProvider_Shutdown(t *testing.T) {