diff --git a/README.md b/README.md index cab3fa2..912766c 100644 --- a/README.md +++ b/README.md @@ -405,6 +405,20 @@ For more information about option **2** and **3**, see [Credentials](#credential #### Built-in credentials +The built-in credential handling for managed identities have been tested on: + +- Azure Functions +- Azure Container Apps +- Azure Container Instances + +In addition to this it should work on: + +- Azure Virtual Machines (since it makes use of the IMDS endpoint like Azure Container Instances) +- Azure App Services (since it makes us of the same endpoint as Azure Functions) + +For more advanced scenarios like Azure Stack or Service Fabric see the section about using [`authopts`](./authopts/) +together with [`azidentity`](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity). + ##### Authentication with environment variables For all authentication scenarios the following environment variables are used: diff --git a/azcfg_test.go b/azcfg_test.go index 5d6c602..59c6553 100644 --- a/azcfg_test.go +++ b/azcfg_test.go @@ -191,8 +191,8 @@ func TestParse(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - secretClient := mockSecretClient{err: test.wantErr} - settingClient := mockSettingClient{err: test.wantErr} + secretClient := newMockSecretClient(responseSecrets, test.wantErr) + settingClient := newMockSettingClient(responseSettings, test.wantErr) gotErr := parse(context.Background(), &test.input, parseOptions{secretClient: secretClient, settingClient: settingClient}) if diff := cmp.Diff(test.want, test.input, cmp.AllowUnexported(Struct{})); diff != "" { @@ -217,8 +217,8 @@ func TestParseRequired(t *testing.T) { input: StructWithRequired{}, wantErr: &RequiredFieldsError{ errors: []error{ - requiredSecretsError{message: requiredErrorMessage(map[string]secret.Secret{"empty": {}, "empty-float64": {}}, []string{"empty", "empty-float64"}, "secret")}, - requiredSettingsError{message: requiredErrorMessage(map[string]setting.Setting{"empty-setting": {}}, []string{"empty-setting"}, "setting")}, + requiredSecretsError{message: requiredErrorMessage(map[string]Secret{"empty": {}, "empty-float64": {}}, []string{"empty", "empty-float64"}, "secret")}, + requiredSettingsError{message: requiredErrorMessage(map[string]Setting{"empty-setting": {}}, []string{"empty-setting"}, "setting")}, }, }, }, @@ -226,8 +226,8 @@ func TestParseRequired(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - secretClient := mockSecretClient{} - settingClient := mockSettingClient{} + secretClient := mockSecretClient{secrets: responseSecrets} + settingClient := mockSettingClient{settings: responseSettings} gotErr := parse(context.Background(), &test.input, parseOptions{secretClient: secretClient, settingClient: settingClient}) if test.wantErr != nil && gotErr == nil { @@ -375,18 +375,29 @@ type NestedStructWithRequired struct { } type mockSecretClient struct { - err error + secrets map[string]Secret + err error } -func (c mockSecretClient) GetSecrets(ctx context.Context, names []string, options ...secret.Option) (map[string]secret.Secret, error) { +func newMockSecretClient(secrets map[string]Secret, err error) mockSecretClient { + if secrets == nil { + secrets = make(map[string]Secret) + } + return mockSecretClient{ + secrets: secrets, + err: err, + } +} + +func (c mockSecretClient) GetSecrets(ctx context.Context, names []string, options ...secret.Option) (map[string]Secret, error) { if c.err != nil { return nil, errors.New("could not get secrets") } - return responseSecrets, nil + return c.secrets, nil } var ( - responseSecrets = map[string]secret.Secret{ + responseSecrets = map[string]Secret{ "string": {Value: "new string"}, "string-ptr": {Value: "new string ptr"}, "empty": {Value: ""}, @@ -413,15 +424,26 @@ var ( ) type mockSettingClient struct { - err error + settings map[string]Setting + err error +} + +func newMockSettingClient(settings map[string]Setting, err error) mockSettingClient { + if settings == nil { + settings = make(map[string]Setting) + } + return mockSettingClient{ + settings: settings, + err: err, + } } -func (c mockSettingClient) GetSettings(ctx context.Context, keys []string, options ...setting.Option) (map[string]setting.Setting, error) { +func (c mockSettingClient) GetSettings(ctx context.Context, keys []string, options ...setting.Option) (map[string]Setting, error) { time.Sleep(time.Millisecond * 10) if c.err != nil { return nil, errors.New("could not get settings") } - return responseSettings, nil + return c.settings, nil } func toPtr[V any](v V) *V { @@ -429,7 +451,7 @@ func toPtr[V any](v V) *V { } var ( - responseSettings = map[string]setting.Setting{ + responseSettings = map[string]Setting{ "string-setting": {Value: "new string setting"}, "string-setting-ptr": {Value: "new string setting ptr"}, "bool-setting": {Value: "true"}, diff --git a/errors_test.go b/errors_test.go index 5203a14..215f6ba 100644 --- a/errors_test.go +++ b/errors_test.go @@ -3,8 +3,6 @@ package azcfg import ( "testing" - "github.com/KarlGW/azcfg/internal/secret" - "github.com/KarlGW/azcfg/internal/setting" "github.com/google/go-cmp/cmp" ) @@ -12,7 +10,7 @@ func TestRequiredErrorMessage_Secret(t *testing.T) { var tests = []struct { name string input struct { - secrets map[string]secret.Secret + secrets map[string]Secret required []string } want string @@ -20,10 +18,10 @@ func TestRequiredErrorMessage_Secret(t *testing.T) { { name: "no required", input: struct { - secrets map[string]secret.Secret + secrets map[string]Secret required []string }{ - secrets: map[string]secret.Secret{}, + secrets: map[string]Secret{}, required: []string{}, }, want: "", @@ -31,10 +29,10 @@ func TestRequiredErrorMessage_Secret(t *testing.T) { { name: "1 required", input: struct { - secrets map[string]secret.Secret + secrets map[string]Secret required []string }{ - secrets: map[string]secret.Secret{ + secrets: map[string]Secret{ "secret1": {Value: ""}, }, required: []string{ @@ -46,10 +44,10 @@ func TestRequiredErrorMessage_Secret(t *testing.T) { { name: "2 required", input: struct { - secrets map[string]secret.Secret + secrets map[string]Secret required []string }{ - secrets: map[string]secret.Secret{ + secrets: map[string]Secret{ "secret1": {Value: ""}, "secret2": {Value: ""}, }, @@ -63,10 +61,10 @@ func TestRequiredErrorMessage_Secret(t *testing.T) { { name: "3 required", input: struct { - secrets map[string]secret.Secret + secrets map[string]Secret required []string }{ - secrets: map[string]secret.Secret{ + secrets: map[string]Secret{ "secret1": {Value: ""}, "secret2": {Value: ""}, "secret3": {Value: ""}, @@ -96,7 +94,7 @@ func TestRequiredErrorMessage_Setting(t *testing.T) { var tests = []struct { name string input struct { - settings map[string]setting.Setting + settings map[string]Setting required []string } want string @@ -104,10 +102,10 @@ func TestRequiredErrorMessage_Setting(t *testing.T) { { name: "no required", input: struct { - settings map[string]setting.Setting + settings map[string]Setting required []string }{ - settings: map[string]setting.Setting{}, + settings: map[string]Setting{}, required: []string{}, }, want: "", @@ -115,10 +113,10 @@ func TestRequiredErrorMessage_Setting(t *testing.T) { { name: "1 required", input: struct { - settings map[string]setting.Setting + settings map[string]Setting required []string }{ - settings: map[string]setting.Setting{ + settings: map[string]Setting{ "setting1": {Value: ""}, }, required: []string{ @@ -130,10 +128,10 @@ func TestRequiredErrorMessage_Setting(t *testing.T) { { name: "2 required", input: struct { - settings map[string]setting.Setting + settings map[string]Setting required []string }{ - settings: map[string]setting.Setting{ + settings: map[string]Setting{ "setting1": {Value: ""}, "setting2": {Value: ""}, }, @@ -147,10 +145,10 @@ func TestRequiredErrorMessage_Setting(t *testing.T) { { name: "3 required", input: struct { - settings map[string]setting.Setting + settings map[string]Setting required []string }{ - settings: map[string]setting.Setting{ + settings: map[string]Setting{ "setting1": {Value: ""}, "setting2": {Value: ""}, "setting3": {Value: ""}, diff --git a/internal/httpr/policy.go b/internal/httpr/policy.go index 63bada0..aa604ed 100644 --- a/internal/httpr/policy.go +++ b/internal/httpr/policy.go @@ -33,7 +33,11 @@ func defaultRetry(r *http.Response, err error) bool { return true } switch r.StatusCode { - case 0, http.StatusInternalServerError, http.StatusBadGateway, http.StatusServiceUnavailable, http.StatusGatewayTimeout: + case 0: + return true + case http.StatusTooManyRequests: + return true + case http.StatusInternalServerError, http.StatusBadGateway, http.StatusServiceUnavailable, http.StatusGatewayTimeout: return true } return false diff --git a/internal/setting/setting.go b/internal/setting/setting.go index e058175..de89433 100644 --- a/internal/setting/setting.go +++ b/internal/setting/setting.go @@ -52,10 +52,13 @@ type AccessKey struct { Secret string } +// Secret represents a secret as returned from the Key Vault REST API. +type Secret = secret.Secret + // secretClient is the interface that wraps around method Get, Vault and // SetVault. type secretClient interface { - Get(ctx context.Context, name string, options ...secret.Option) (secret.Secret, error) + Get(ctx context.Context, name string, options ...secret.Option) (Secret, error) Vault() string SetVault(vault string) } @@ -266,13 +269,13 @@ func (c *Client) Get(ctx context.Context, key string, options ...Option) (Settin } // getSecret gets a secret from the provided URI. -func (c *Client) getSecret(ctx context.Context, uri string) (secret.Secret, error) { +func (c *Client) getSecret(ctx context.Context, uri string) (Secret, error) { c.mu.Lock() defer c.mu.Unlock() v, s, err := vaultAndSecret(uri) if err != nil { - return secret.Secret{}, err + return Secret{}, err } if c.sc == nil { c.sc, err = newSecretClient(v, c.cred, @@ -281,7 +284,7 @@ func (c *Client) getSecret(ctx context.Context, uri string) (secret.Secret, erro secret.WithRetryPolicy(c.retryPolicy), ) if err != nil { - return secret.Secret{}, err + return Secret{}, err } } else { if c.sc.Vault() != v { @@ -290,7 +293,7 @@ func (c *Client) getSecret(ctx context.Context, uri string) (secret.Secret, erro } sec, err := c.sc.Get(ctx, s) if err != nil { - return secret.Secret{}, err + return Secret{}, err } return sec, nil } diff --git a/internal/setting/setting_test.go b/internal/setting/setting_test.go index edaa98d..85bc29a 100644 --- a/internal/setting/setting_test.go +++ b/internal/setting/setting_test.go @@ -176,7 +176,7 @@ func TestClient_GetSettings(t *testing.T) { bodies map[string][]byte label string labels map[string]string - secrets map[string]secret.Secret + secrets map[string]Secret err error } want map[string]Setting @@ -191,7 +191,7 @@ func TestClient_GetSettings(t *testing.T) { bodies map[string][]byte label string labels map[string]string - secrets map[string]secret.Secret + secrets map[string]Secret err error }{ keys: []string{"setting-a", "setting-b", "setting-c"}, @@ -217,7 +217,7 @@ func TestClient_GetSettings(t *testing.T) { bodies map[string][]byte label string labels map[string]string - secrets map[string]secret.Secret + secrets map[string]Secret err error }{ withAccessKey: true, @@ -244,7 +244,7 @@ func TestClient_GetSettings(t *testing.T) { bodies map[string][]byte label string labels map[string]string - secrets map[string]secret.Secret + secrets map[string]Secret err error }{ keys: []string{"setting-a", "setting-b", "setting-c"}, @@ -274,7 +274,7 @@ func TestClient_GetSettings(t *testing.T) { bodies map[string][]byte label string labels map[string]string - secrets map[string]secret.Secret + secrets map[string]Secret err error }{ keys: []string{"setting-a", "setting-b", "setting-c"}, @@ -310,7 +310,7 @@ func TestClient_GetSettings(t *testing.T) { bodies map[string][]byte label string labels map[string]string - secrets map[string]secret.Secret + secrets map[string]Secret err error }{ keys: []string{"setting-a", "setting-b", "setting-c"}, @@ -319,7 +319,7 @@ func TestClient_GetSettings(t *testing.T) { "setting-b": []byte(`{"value":"b"}`), "setting-c": []byte(`{"value":"c"}`), }, - secrets: map[string]secret.Secret{ + secrets: map[string]Secret{ "secret-1": {Value: "1"}, }, }, @@ -339,7 +339,7 @@ func TestClient_GetSettings(t *testing.T) { bodies map[string][]byte label string labels map[string]string - secrets map[string]secret.Secret + secrets map[string]Secret err error }{ keys: []string{"setting-a", "setting-b", "setting-c"}, @@ -364,7 +364,7 @@ func TestClient_GetSettings(t *testing.T) { bodies map[string][]byte label string labels map[string]string - secrets map[string]secret.Secret + secrets map[string]Secret err error }{ keys: []string{"setting-a"}, @@ -384,7 +384,7 @@ func TestClient_GetSettings(t *testing.T) { bodies map[string][]byte label string labels map[string]string - secrets map[string]secret.Secret + secrets map[string]Secret err error }{ keys: []string{"setting-a", "setting-b", "setting-c"}, @@ -410,7 +410,7 @@ func TestClient_GetSettings(t *testing.T) { bodies map[string][]byte label string labels map[string]string - secrets map[string]secret.Secret + secrets map[string]Secret err error }{ keys: []string{"setting-a"}, @@ -432,7 +432,7 @@ func TestClient_GetSettings(t *testing.T) { bodies map[string][]byte label string labels map[string]string - secrets map[string]secret.Secret + secrets map[string]Secret err error }{ keys: []string{"setting-a"}, @@ -450,14 +450,14 @@ func TestClient_GetSettings(t *testing.T) { bodies map[string][]byte label string labels map[string]string - secrets map[string]secret.Secret + secrets map[string]Secret err error }{ keys: []string{"setting-a", "setting-b", "setting-c"}, bodies: map[string][]byte{ "setting-a": []byte(`{"content_type":"` + keyVaultReferenceContentType + `","value":"{\"uri\":\"https://testvault.vault.azure.net/secrets/secret-1\"}"}`), }, - secrets: map[string]secret.Secret{ + secrets: map[string]Secret{ "secret-1": {Value: "1"}, }, err: errGetSecret, @@ -508,69 +508,69 @@ func TestClient_getSecret(t *testing.T) { name string input struct { secretClient secretClient - secrets map[string]secret.Secret + secrets map[string]Secret uri string err error } - want secret.Secret + want Secret wantErr error }{ { name: "get secret from uri", input: struct { secretClient secretClient - secrets map[string]secret.Secret + secrets map[string]Secret uri string err error }{ - secrets: map[string]secret.Secret{ + secrets: map[string]Secret{ "secretname": {Value: "secret"}, }, uri: "https://testvault.vault.azure.net/secrets/secretname", }, - want: secret.Secret{Value: "secret"}, + want: Secret{Value: "secret"}, }, { name: "get secret from uri (existing client)", input: struct { secretClient secretClient - secrets map[string]secret.Secret + secrets map[string]Secret uri string err error }{ secretClient: func() *mockSecretClient { return &mockSecretClient{ - secrets: map[string]secret.Secret{ + secrets: map[string]Secret{ "secretname": {Value: "secret"}, }, } }(), uri: "https://testvault.vault.azure.net/secrets/secretname", }, - want: secret.Secret{Value: "secret"}, + want: Secret{Value: "secret"}, }, { name: "get secret - not found", input: struct { secretClient secretClient - secrets map[string]secret.Secret + secrets map[string]Secret uri string err error }{ - secrets: map[string]secret.Secret{}, + secrets: map[string]Secret{}, uri: "https://testvault.vault.azure.net/secrets/secretname", }, - want: secret.Secret{Value: ""}, + want: Secret{Value: ""}, }, { name: "get secret from uri - error", input: struct { secretClient secretClient - secrets map[string]secret.Secret + secrets map[string]Secret uri string err error }{ - secrets: map[string]secret.Secret{ + secrets: map[string]Secret{ "secretname": {Value: "secret"}, }, uri: "https://testvault.vault.azure.net/secrets/secretname", @@ -928,7 +928,7 @@ func (c mockHttpClient) Do(req *http.Request) (*http.Response, error) { type mockSecretClient struct { err error - secrets map[string]secret.Secret + secrets map[string]Secret vault string } @@ -940,13 +940,13 @@ func (c *mockSecretClient) SetVault(vault string) { c.vault = vault } -func (c mockSecretClient) Get(ctx context.Context, name string, options ...secret.Option) (secret.Secret, error) { +func (c mockSecretClient) Get(ctx context.Context, name string, options ...secret.Option) (Secret, error) { if c.err != nil && errors.Is(c.err, errGetSecret) { - return secret.Secret{}, c.err + return Secret{}, c.err } s, ok := c.secrets[name] if !ok { - return secret.Secret{}, nil + return Secret{}, nil } return s, nil } diff --git a/options_test.go b/options_test.go index 1e300b8..2b2cc2d 100644 --- a/options_test.go +++ b/options_test.go @@ -7,7 +7,6 @@ import ( "time" "github.com/KarlGW/azcfg/azure/cloud" - "github.com/KarlGW/azcfg/stub" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" ) @@ -164,16 +163,20 @@ func TestOptions(t *testing.T) { }, { name: "WithSecretClient", - input: WithSecretClient(stub.NewSecretClient(nil, nil)), + input: WithSecretClient(newMockSecretClient(nil, nil)), want: Options{ - SecretClient: stub.SecretClient{}, + SecretClient: mockSecretClient{ + secrets: map[string]Secret{}, + }, }, }, { name: "WithSettingClient", - input: WithSettingClient(stub.NewSettingClient(nil, nil)), + input: WithSettingClient(newMockSettingClient(nil, nil)), want: Options{ - SettingClient: stub.SettingClient{}, + SettingClient: mockSettingClient{ + settings: map[string]Setting{}, + }, }, }, { @@ -223,7 +226,7 @@ func TestOptions(t *testing.T) { got := Options{} test.input(&got) - if diff := cmp.Diff(test.want, got, cmp.AllowUnexported(Options{}, mockCredential{}, Entra{}), cmpopts.IgnoreUnexported(stub.SecretClient{}, stub.SettingClient{}), cmpopts.IgnoreFields(Entra{}, "PrivateKey"), cmp.Comparer(compareAssertionFunc)); diff != "" { + if diff := cmp.Diff(test.want, got, cmp.AllowUnexported(Options{}, Entra{}, mockCredential{}, mockSecretClient{}, mockSettingClient{}), cmpopts.IgnoreFields(Entra{}, "PrivateKey"), cmp.Comparer(compareAssertionFunc)); diff != "" { t.Errorf("%s() = unexpected result (-want +got)\n%s\n", test.name, diff) } } diff --git a/parser.go b/parser.go index ab99fb7..966c55f 100644 --- a/parser.go +++ b/parser.go @@ -18,14 +18,20 @@ import ( "github.com/KarlGW/azcfg/internal/setting" ) +// Secret represents a secret as returned from the Key Vault REST API. +type Secret = secret.Secret + // secretClient is the interface that wraps around method GetSecrets. type secretClient interface { - GetSecrets(ctx context.Context, names []string, options ...secret.Option) (map[string]secret.Secret, error) + GetSecrets(ctx context.Context, names []string, options ...secret.Option) (map[string]Secret, error) } +// Setting represents a setting as returned from the App Config REST API. +type Setting = setting.Setting + // settingClient is the interface that wraps around method GetSettings. type settingClient interface { - GetSettings(ctx context.Context, keys []string, options ...setting.Option) (map[string]setting.Setting, error) + GetSettings(ctx context.Context, keys []string, options ...setting.Option) (map[string]Setting, error) } // RetryPolicy contains rules for retries. diff --git a/parser_test.go b/parser_test.go index c496575..54a26dd 100644 --- a/parser_test.go +++ b/parser_test.go @@ -17,7 +17,6 @@ import ( "github.com/KarlGW/azcfg/internal/setting" "github.com/KarlGW/azcfg/internal/testutils" "github.com/KarlGW/azcfg/internal/uuid" - "github.com/KarlGW/azcfg/stub" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" ) @@ -219,11 +218,11 @@ func TestNewParser(t *testing.T) { envs map[string]string }{ options: []Option{ - WithSecretClient(stub.NewSecretClient(nil, nil)), + WithSecretClient(newMockSecretClient(nil, nil)), }, }, want: &parser{ - secretClient: stub.SecretClient{}, + secretClient: mockSecretClient{}, settingClient: nil, timeout: time.Second * 10, }, @@ -235,12 +234,12 @@ func TestNewParser(t *testing.T) { envs map[string]string }{ options: []Option{ - WithSettingClient(stub.NewSettingClient(nil, nil)), + WithSettingClient(newMockSettingClient(nil, nil)), }, }, want: &parser{ secretClient: nil, - settingClient: stub.SettingClient{}, + settingClient: mockSettingClient{}, timeout: time.Second * 10, }, }, @@ -251,13 +250,13 @@ func TestNewParser(t *testing.T) { envs map[string]string }{ options: []Option{ - WithSecretClient(stub.NewSecretClient(nil, nil)), - WithSettingClient(stub.NewSettingClient(nil, nil)), + WithSecretClient(newMockSecretClient(nil, nil)), + WithSettingClient(newMockSettingClient(nil, nil)), }, }, want: &parser{ - secretClient: stub.SecretClient{}, - settingClient: stub.SettingClient{}, + secretClient: mockSecretClient{}, + settingClient: mockSettingClient{}, timeout: time.Second * 10, }, }, @@ -273,7 +272,7 @@ func TestNewParser(t *testing.T) { got, gotErr := NewParser(test.input.options...) - if diff := cmp.Diff(test.want, got, cmp.AllowUnexported(parser{}, mockCredential{}), cmpopts.IgnoreUnexported(secret.Client{}, stub.SecretClient{}, setting.Client{}, stub.SettingClient{}, identity.ClientCredential{}, identity.ManagedIdentityCredential{})); diff != "" { + if diff := cmp.Diff(test.want, got, cmp.AllowUnexported(parser{}, mockCredential{}), cmpopts.IgnoreUnexported(secret.Client{}, setting.Client{}, identity.ClientCredential{}, identity.ManagedIdentityCredential{}, mockSecretClient{}, mockSettingClient{})); diff != "" { t.Errorf("NewParser() = unexpected result (-want +got)\n%s\n", diff) } @@ -290,9 +289,9 @@ func TestParser_Parse(t *testing.T) { input struct { s Struct options []Option - secrets map[string]string + secrets map[string]Secret secretErr error - settings map[string]string + settings map[string]Setting settingErr error } want Struct @@ -303,17 +302,17 @@ func TestParser_Parse(t *testing.T) { input: struct { s Struct options []Option - secrets map[string]string + secrets map[string]Secret secretErr error - settings map[string]string + settings map[string]Setting settingErr error }{ s: Struct{}, - secrets: map[string]string{ - "string": "new string", + secrets: map[string]Secret{ + "string": {Value: "new string"}, }, - settings: map[string]string{ - "string-setting": "new string setting", + settings: map[string]Setting{ + "string-setting": {Value: "new string setting"}, }, }, want: Struct{ @@ -326,17 +325,17 @@ func TestParser_Parse(t *testing.T) { input: struct { s Struct options []Option - secrets map[string]string + secrets map[string]Secret secretErr error - settings map[string]string + settings map[string]Setting settingErr error }{ s: Struct{}, - secrets: map[string]string{ - "string": "new string", + secrets: map[string]Secret{ + "string": {Value: "new string"}, }, - settings: map[string]string{ - "string-setting": "new string setting", + settings: map[string]Setting{ + "string-setting": {Value: "new string setting"}, }, options: []Option{ WithContext(context.Background()), @@ -352,8 +351,8 @@ func TestParser_Parse(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { p := &parser{ - secretClient: stub.NewSecretClient(test.input.secrets, test.input.secretErr), - settingClient: stub.NewSettingClient(test.input.settings, test.input.settingErr), + secretClient: newMockSecretClient(test.input.secrets, test.input.secretErr), + settingClient: newMockSettingClient(test.input.settings, test.input.settingErr), } gotErr := p.Parse(&test.input.s, test.input.options...) diff --git a/stub/stub.go b/stub/stub.go deleted file mode 100644 index 04929e5..0000000 --- a/stub/stub.go +++ /dev/null @@ -1,70 +0,0 @@ -package stub - -import ( - "context" - - "github.com/KarlGW/azcfg/internal/secret" - "github.com/KarlGW/azcfg/internal/setting" -) - -// SecretClient satisfies the secretClient interface in package azcfg. Purpose is -// to be used as a stub for secret retrieval. -type SecretClient struct { - secrets map[string]secret.Secret - err error -} - -// NewSecretClient creates a new SecretClient. Argument the map[string]string secrets -// should be key-value pairs of secret names and values. Argument -// error is to set if method calls should return an error. -func NewSecretClient(secrets map[string]string, err error) SecretClient { - s := make(map[string]secret.Secret, len(secrets)) - for k, v := range secrets { - s[k] = secret.Secret{ - Value: v, - } - } - return SecretClient{ - secrets: s, - err: err, - } -} - -// Get secrets set to the stub client. -func (c SecretClient) GetSecrets(ctx context.Context, names []string, options ...secret.Option) (map[string]secret.Secret, error) { - if c.err != nil { - return nil, c.err - } - return c.secrets, nil -} - -// SettingClient satisfies the settingClient interface in package azcfg. Purpose is -// to be used as a stub for setting retrieval. -type SettingClient struct { - settings map[string]setting.Setting - err error -} - -// NewSettingClient creates a new SettingClient. Argument the map[string]string settings -// should be key-value pairs of setting keys and values. Argument -// error is to set if method calls should return an error. -func NewSettingClient(settings map[string]string, err error) SettingClient { - s := make(map[string]setting.Setting, len(settings)) - for k, v := range settings { - s[k] = setting.Setting{ - Value: v, - } - } - return SettingClient{ - settings: s, - err: err, - } -} - -// Get settings set to the stub client. -func (c SettingClient) GetSettings(ctx context.Context, keys []string, options ...setting.Option) (map[string]setting.Setting, error) { - if c.err != nil { - return nil, c.err - } - return c.settings, nil -} diff --git a/stub/stub_test.go b/stub/stub_test.go deleted file mode 100644 index 227070b..0000000 --- a/stub/stub_test.go +++ /dev/null @@ -1,181 +0,0 @@ -package stub - -import ( - "context" - "errors" - "testing" - - "github.com/KarlGW/azcfg/internal/secret" - "github.com/KarlGW/azcfg/internal/setting" - "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" -) - -func TestNewSecretClient(t *testing.T) { - t.Run("NewSecretClient", func(t *testing.T) { - want := SecretClient{ - secrets: map[string]secret.Secret{}, - err: errors.New("test"), - } - - got := NewSecretClient(map[string]string{ - "secret": "value", - }, errors.New("test")) - - if diff := cmp.Diff(want, got, cmp.AllowUnexported(SecretClient{}), cmpopts.IgnoreUnexported(SecretClient{})); diff != "" { - t.Errorf("NewSecretClient() = unexpected result (-want +got)\n%s\n", diff) - } - }) -} - -func TestSecretClient_GetSecrets(t *testing.T) { - var tests = []struct { - name string - input struct { - names []string - secrets map[string]string - err error - } - want map[string]secret.Secret - wantErr error - }{ - { - name: "Get secrets", - input: struct { - names []string - secrets map[string]string - err error - }{ - names: []string{"secret"}, - secrets: map[string]string{ - "secret": "value", - }, - err: nil, - }, - want: map[string]secret.Secret{ - "secret": { - Value: "value", - }, - }, - wantErr: nil, - }, - { - name: "Get error", - input: struct { - names []string - secrets map[string]string - err error - }{ - names: []string{"secret"}, - secrets: map[string]string{ - "secret": "value", - }, - err: errGetSecrets, - }, - want: nil, - wantErr: errGetSecrets, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - cl := NewSecretClient(test.input.secrets, test.input.err) - got, gotErr := cl.GetSecrets(context.Background(), test.input.names) - - if diff := cmp.Diff(test.want, got); diff != "" { - t.Errorf("GetSecrets() = unexpected result (-want +got)\n%s\n", diff) - } - - if diff := cmp.Diff(test.wantErr, gotErr, cmpopts.EquateErrors()); diff != "" { - t.Errorf("GetSecrets() = unexpected error (-want +got)\n%s\b", diff) - } - }) - } -} - -func TestNewSettingClient(t *testing.T) { - t.Run("NewSettingClient", func(t *testing.T) { - want := SettingClient{ - settings: map[string]setting.Setting{}, - err: errors.New("test"), - } - - got := NewSettingClient(map[string]string{ - "setting": "value", - }, errors.New("test")) - - if diff := cmp.Diff(want, got, cmp.AllowUnexported(SettingClient{}), cmpopts.IgnoreUnexported(SettingClient{})); diff != "" { - t.Errorf("NewSettingCLient() = unexpected result (-want +got)\n%s\n", diff) - } - }) -} - -func TestSettingClient_GetSettings(t *testing.T) { - var tests = []struct { - name string - input struct { - keys []string - settings map[string]string - err error - } - want map[string]setting.Setting - wantErr error - }{ - { - name: "Get settings", - input: struct { - keys []string - settings map[string]string - err error - }{ - keys: []string{"setting"}, - settings: map[string]string{ - "setting": "value", - }, - err: nil, - }, - want: map[string]setting.Setting{ - "setting": { - Value: "value", - }, - }, - wantErr: nil, - }, - { - name: "Get error", - input: struct { - keys []string - settings map[string]string - err error - }{ - keys: []string{"setting"}, - settings: map[string]string{ - "setting": "value", - }, - err: errGetSettings, - }, - want: nil, - wantErr: errGetSettings, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - cl := NewSettingClient(test.input.settings, test.input.err) - got, gotErr := cl.GetSettings(context.Background(), test.input.keys) - - if diff := cmp.Diff(test.want, got); diff != "" { - t.Errorf("GetSettings() = unexpected result (-want +got)\n%s\n", diff) - } - - if diff := cmp.Diff(test.wantErr, gotErr, cmpopts.EquateErrors()); diff != "" { - t.Errorf("GetSettings() = unexpected result (-want +got)\n%s\n", diff) - } - }) - } -} - -var ( - errGetSecrets = errors.New("err") - errGetSettings = errors.New("err") -)