Procházet zdrojové kódy

test: refactor fake implementation design

Signed-off-by: Jordan Sauvain <jordan.sauvain@ovhcloud.com>
Jordan Sauvain před 4 měsíci
rodič
revize
03f91e88a3

+ 112 - 95
providers/v1/ovh/client_get_all_secrets_test.go

@@ -17,8 +17,9 @@ limitations under the License.
 package ovh
 
 import (
-	"bytes"
 	"context"
+	"fmt"
+	"reflect"
 	"testing"
 
 	kclient "sigs.k8s.io/controller-runtime/pkg/client"
@@ -30,125 +31,134 @@ import (
 func TestGetAllSecrets(t *testing.T) {
 	path1 := "pattern1"
 	path2 := "pattern2/test"
-	path3 := "nil resp"
-	path4 := "nil data struct"
-	path5 := "nil secrets list"
-	path6 := "empty secrets list"
-	path7 := "error response"
+	nonExistentPath := "non-existent-path"
+	emptyPath := ""
+
+	noMatchRegexp := "^noMatch.*$"
+	invalidRegexp := "\\wa\\w([a]"
+
 	testCases := map[string]struct {
-		shouldmap map[string][]byte
-		errshould string
-		kube      kclient.Client
-		refFind   esv1.ExternalSecretFind
+		should     map[string][]byte
+		errshould  string
+		kube       kclient.Client
+		refFind    esv1.ExternalSecretFind
+		okmsClient fake.FakeOkmsClient
 	}{
-		"No secrets found (nil response)": {
-			errshould: "no secrets found in the secret manager",
-			refFind: esv1.ExternalSecretFind{
-				Path: &path3,
-			},
-		},
-		"No secrets found (nil Data struct)": {
-			errshould: "no secrets found in the secret manager",
-			refFind: esv1.ExternalSecretFind{
-				Path: &path4,
-			},
-		},
-		"No secrets found (nil secrets list)": {
-			errshould: "no secrets found in the secret manager",
-			refFind: esv1.ExternalSecretFind{
-				Path: &path5,
-			},
-		},
-		"No secrets found (empty secrets list)": {
-			errshould: "no secrets found in the secret manager",
+		"No secrets found under provided path": {
+			errshould: fmt.Sprintf("failed to retrieve multiple secrets: no secrets under path %q were found in the secret manager", nonExistentPath),
 			refFind: esv1.ExternalSecretFind{
-				Path: &path6,
+				Path: &nonExistentPath,
 			},
-		},
-		"Error response": {
-			errshould: "error response",
-			refFind: esv1.ExternalSecretFind{
-				Path: &path7,
+			okmsClient: fake.FakeOkmsClient{
+				GetSecretsMetadataFn: fake.NewGetSecretsMetadataFn(nonExistentPath, nil),
 			},
 		},
 		"Invalid Regex": {
-			errshould: "failed to parse regexp",
+			errshould: fmt.Sprintf("failed to retrieve multiple secrets: could not parse regex: error parsing regexp: missing closing ): `%s`", invalidRegexp),
 			refFind: esv1.ExternalSecretFind{
 				Name: &esv1.FindName{
-					RegExp: "\\wa\\w([a]",
+					RegExp: invalidRegexp,
 				},
 			},
+			okmsClient: fake.FakeOkmsClient{
+				GetSecretsMetadataFn: fake.NewGetSecretsMetadataFn(emptyPath, nil),
+			},
 		},
 		"Empty Regex": {
-			shouldmap: map[string][]byte{
+			should: map[string][]byte{
+				"mysecret":                  []byte(`{"key1":"value1","key2":"value2"}`),
+				"mysecret2":                 []byte(`{"keys":{"key1":"value1","key2":"value2"},"token":"value"}`),
+				"nested-secret":             []byte(`{"users":{"alice":{"age":"23"},"baptist":{"age":"27"}}}`),
 				"pattern1/path1":            []byte("{\"projects\":{\"project1\":\"Name\",\"project2\":\"Name\"}}"),
 				"pattern1/path2":            []byte("{\"key\":\"value\"}"),
 				"pattern1/path3":            []byte("{\"root\":{\"sub1\":{\"value\":\"string\"},\"sub2\":\"Name\"},\"test\":\"value\",\"test1\":\"value1\"}"),
-				"pattern2/test/test-secret": []byte("{\"test4\":\"value4\"}"),
-				"pattern2/test/test.secret": []byte("{\"test5\":\"value5\"}"),
-				"pattern2/secret":           []byte("{\"test6\":\"value6\"}"),
-				"1secret":                   []byte("{\"test7\":\"value7\"}"),
-				"pattern2/test/test;secret": []byte("{\"test8\":\"value8\"}"),
+				"pattern2/test/test-secret": []byte("{\"key4\":\"value4\"}"),
+				"pattern2/test/test.secret": []byte("{\"key5\":\"value5\"}"),
+				"pattern2/secret":           []byte("{\"key6\":\"value6\"}"),
+				"1secret":                   []byte("{\"key7\":\"value7\"}"),
+				"pattern2/test/test;secret": []byte("{\"key8\":\"value8\"}"),
 			},
 			refFind: esv1.ExternalSecretFind{
 				Name: &esv1.FindName{
 					RegExp: "",
 				},
 			},
+			okmsClient: fake.FakeOkmsClient{
+				GetSecretsMetadataFn: fake.NewGetSecretsMetadataFn(emptyPath, nil),
+			},
 		},
 		"No Regexp Match": {
-			errshould: "no secrets matched the regexp",
+			errshould: fmt.Sprintf("failed to retrieve multiple secrets: regex expression %q did not match any secret at path %q", noMatchRegexp, emptyPath),
 			refFind: esv1.ExternalSecretFind{
 				Name: &esv1.FindName{
-					RegExp: "^noMatch.*$",
+					RegExp: noMatchRegexp,
 				},
 			},
+			okmsClient: fake.FakeOkmsClient{
+				GetSecretsMetadataFn: fake.NewGetSecretsMetadataFn(emptyPath, nil),
+			},
 		},
 		"Regex pattern containing '.' or '-' only": {
-			shouldmap: map[string][]byte{
-				"pattern2/test/test-secret": []byte("{\"test4\":\"value4\"}"),
-				"pattern2/test/test.secret": []byte("{\"test5\":\"value5\"}"),
+			should: map[string][]byte{
+				"nested-secret":             []byte(`{"users":{"alice":{"age":"23"},"baptist":{"age":"27"}}}`),
+				"pattern2/test/test-secret": []byte("{\"key4\":\"value4\"}"),
+				"pattern2/test/test.secret": []byte("{\"key5\":\"value5\"}"),
 			},
 			refFind: esv1.ExternalSecretFind{
 				Name: &esv1.FindName{
 					RegExp: ".*[.|-].*",
 				},
 			},
+			okmsClient: fake.FakeOkmsClient{
+				GetSecretsMetadataFn: fake.NewGetSecretsMetadataFn(emptyPath, nil),
+			},
 		},
 		"Regex pattern starting with alphanumeric character": {
-			shouldmap: map[string][]byte{
+			should: map[string][]byte{
+				"mysecret":                  []byte(`{"key1":"value1","key2":"value2"}`),
+				"mysecret2":                 []byte(`{"keys":{"key1":"value1","key2":"value2"},"token":"value"}`),
+				"nested-secret":             []byte(`{"users":{"alice":{"age":"23"},"baptist":{"age":"27"}}}`),
 				"pattern1/path1":            []byte("{\"projects\":{\"project1\":\"Name\",\"project2\":\"Name\"}}"),
 				"pattern1/path2":            []byte("{\"key\":\"value\"}"),
 				"pattern1/path3":            []byte("{\"root\":{\"sub1\":{\"value\":\"string\"},\"sub2\":\"Name\"},\"test\":\"value\",\"test1\":\"value1\"}"),
-				"pattern2/test/test-secret": []byte("{\"test4\":\"value4\"}"),
-				"pattern2/test/test.secret": []byte("{\"test5\":\"value5\"}"),
-				"pattern2/secret":           []byte("{\"test6\":\"value6\"}"),
-				"pattern2/test/test;secret": []byte("{\"test8\":\"value8\"}"),
+				"pattern2/test/test-secret": []byte("{\"key4\":\"value4\"}"),
+				"pattern2/test/test.secret": []byte("{\"key5\":\"value5\"}"),
+				"pattern2/secret":           []byte("{\"key6\":\"value6\"}"),
+				"pattern2/test/test;secret": []byte("{\"key8\":\"value8\"}"),
 			},
 			refFind: esv1.ExternalSecretFind{
 				Name: &esv1.FindName{
 					RegExp: "^[A-Za-z].*$",
 				},
 			},
+			okmsClient: fake.FakeOkmsClient{
+				GetSecretsMetadataFn: fake.NewGetSecretsMetadataFn(emptyPath, nil),
+			},
 		},
 		"Regex pattern without ';' character": {
-			shouldmap: map[string][]byte{
+			should: map[string][]byte{
+				"mysecret":                  []byte(`{"key1":"value1","key2":"value2"}`),
+				"mysecret2":                 []byte(`{"keys":{"key1":"value1","key2":"value2"},"token":"value"}`),
+				"nested-secret":             []byte(`{"users":{"alice":{"age":"23"},"baptist":{"age":"27"}}}`),
 				"pattern1/path1":            []byte("{\"projects\":{\"project1\":\"Name\",\"project2\":\"Name\"}}"),
 				"pattern1/path2":            []byte("{\"key\":\"value\"}"),
 				"pattern1/path3":            []byte("{\"root\":{\"sub1\":{\"value\":\"string\"},\"sub2\":\"Name\"},\"test\":\"value\",\"test1\":\"value1\"}"),
-				"pattern2/test/test-secret": []byte("{\"test4\":\"value4\"}"),
-				"pattern2/test/test.secret": []byte("{\"test5\":\"value5\"}"),
-				"pattern2/secret":           []byte("{\"test6\":\"value6\"}"),
-				"1secret":                   []byte("{\"test7\":\"value7\"}"),
+				"pattern2/test/test-secret": []byte("{\"key4\":\"value4\"}"),
+				"pattern2/test/test.secret": []byte("{\"key5\":\"value5\"}"),
+				"pattern2/secret":           []byte("{\"key6\":\"value6\"}"),
+				"1secret":                   []byte("{\"key7\":\"value7\"}"),
 			},
 			refFind: esv1.ExternalSecretFind{
 				Name: &esv1.FindName{
 					RegExp: "^[^;]+$",
 				},
 			},
+			okmsClient: fake.FakeOkmsClient{
+				GetSecretsMetadataFn: fake.NewGetSecretsMetadataFn(emptyPath, nil),
+			},
 		},
 		"Path pattern1": {
-			shouldmap: map[string][]byte{
+			should: map[string][]byte{
 				"pattern1/path1": []byte("{\"projects\":{\"project1\":\"Name\",\"project2\":\"Name\"}}"),
 				"pattern1/path2": []byte("{\"key\":\"value\"}"),
 				"pattern1/path3": []byte("{\"root\":{\"sub1\":{\"value\":\"string\"},\"sub2\":\"Name\"},\"test\":\"value\",\"test1\":\"value1\"}"),
@@ -156,27 +166,42 @@ func TestGetAllSecrets(t *testing.T) {
 			refFind: esv1.ExternalSecretFind{
 				Path: &path1,
 			},
+			okmsClient: fake.FakeOkmsClient{
+				GetSecretsMetadataFn: fake.NewGetSecretsMetadataFn(path1, nil),
+			},
 		},
 		"Path pattern2/test": {
-			shouldmap: map[string][]byte{
-				"pattern2/test/test-secret": []byte("{\"test4\":\"value4\"}"),
-				"pattern2/test/test.secret": []byte("{\"test5\":\"value5\"}"),
-				"pattern2/test/test;secret": []byte("{\"test8\":\"value8\"}"),
+			should: map[string][]byte{
+				"pattern2/test/test-secret": []byte("{\"key4\":\"value4\"}"),
+				"pattern2/test/test.secret": []byte("{\"key5\":\"value5\"}"),
+				"pattern2/test/test;secret": []byte("{\"key8\":\"value8\"}"),
 			},
 			refFind: esv1.ExternalSecretFind{
 				Path: &path2,
 			},
+			okmsClient: fake.FakeOkmsClient{
+				GetSecretsMetadataFn: fake.NewGetSecretsMetadataFn(path2, nil),
+			},
 		},
 		"Secrets found without path": {
-			shouldmap: map[string][]byte{
+			should: map[string][]byte{
+				"mysecret":                  []byte(`{"key1":"value1","key2":"value2"}`),
+				"mysecret2":                 []byte(`{"keys":{"key1":"value1","key2":"value2"},"token":"value"}`),
+				"nested-secret":             []byte(`{"users":{"alice":{"age":"23"},"baptist":{"age":"27"}}}`),
 				"pattern1/path1":            []byte("{\"projects\":{\"project1\":\"Name\",\"project2\":\"Name\"}}"),
 				"pattern1/path2":            []byte("{\"key\":\"value\"}"),
 				"pattern1/path3":            []byte("{\"root\":{\"sub1\":{\"value\":\"string\"},\"sub2\":\"Name\"},\"test\":\"value\",\"test1\":\"value1\"}"),
-				"pattern2/test/test-secret": []byte("{\"test4\":\"value4\"}"),
-				"pattern2/test/test.secret": []byte("{\"test5\":\"value5\"}"),
-				"pattern2/secret":           []byte("{\"test6\":\"value6\"}"),
-				"1secret":                   []byte("{\"test7\":\"value7\"}"),
-				"pattern2/test/test;secret": []byte("{\"test8\":\"value8\"}"),
+				"pattern2/test/test-secret": []byte("{\"key4\":\"value4\"}"),
+				"pattern2/test/test.secret": []byte("{\"key5\":\"value5\"}"),
+				"pattern2/secret":           []byte("{\"key6\":\"value6\"}"),
+				"1secret":                   []byte("{\"key7\":\"value7\"}"),
+				"pattern2/test/test;secret": []byte("{\"key8\":\"value8\"}"),
+			},
+			refFind: esv1.ExternalSecretFind{
+				Path: nil,
+			},
+			okmsClient: fake.FakeOkmsClient{
+				GetSecretsMetadataFn: fake.NewGetSecretsMetadataFn(emptyPath, nil),
 			},
 		},
 	}
@@ -185,40 +210,32 @@ func TestGetAllSecrets(t *testing.T) {
 	for name, testCase := range testCases {
 		t.Run(name, func(t *testing.T) {
 			cl := &ovhClient{
-				okmsClient: fake.FakeOkmsClient{
-					TestCase: name,
-				},
-				kube: testCase.kube,
+				okmsClient: testCase.okmsClient,
+				kube:       testCase.kube,
 			}
 			secrets, err := cl.GetAllSecrets(ctx, testCase.refFind)
 
-			if err != nil && (err.Error() == "unknown case" || err.Error() == "unknown path") {
-				t.Fatalf("unexpected fake client case: %v", err)
-			}
 			if testCase.errshould != "" {
 				if err == nil {
-					t.Error()
-				}
-				if err.Error() != testCase.errshould {
-					t.Error()
+					t.Errorf("\nexpected value: %s\nactual value:   <nil>\n\n", testCase.errshould)
+				} else if err.Error() != testCase.errshould {
+					t.Errorf("\nexpected value: %s\nactual value:   %v\n\n", testCase.errshould, err)
 				}
 				return
 			}
-			if err != nil {
-				t.Fatalf("unexpected error: %v", err)
-			}
-			if len(testCase.shouldmap) != 0 {
-				if len(testCase.shouldmap) != len(secrets) {
-					t.Error()
-				}
-				for key, value := range secrets {
-					if _, ok := testCase.shouldmap[key]; !ok {
-						t.Error()
-					} else if !bytes.Equal(testCase.shouldmap[key], value) {
-						t.Error()
-					}
-				}
+			if !reflect.DeepEqual(testCase.should, secrets) {
+				t.Errorf("\nexpected value: %v\nactual value:   %v\n\n", convertByteMapToStringMap(testCase.should), convertByteMapToStringMap(secrets))
 			}
 		})
 	}
 }
+
+func convertByteMapToStringMap(m map[string][]byte) map[string]string {
+	newMap := make(map[string]string)
+
+	for key, value := range m {
+		newMap[key] = string(value)
+	}
+
+	return newMap
+}

+ 72 - 52
providers/v1/ovh/client_get_secret_map_test.go

@@ -18,6 +18,8 @@ package ovh
 
 import (
 	"context"
+	"errors"
+	"fmt"
 	"reflect"
 	"testing"
 
@@ -28,77 +30,100 @@ import (
 )
 
 func TestGetSecretMap(t *testing.T) {
+	mySecretRemoteKey := "mysecret"
+	mySecret2RemoteKey := "mysecret2"
+	myNestedSecretRemoteKey := "nested-secret"
+	nonExistentSecretRemoteKey := "non-existent-secret"
+	emptySecretRemoteKey := "empty-secret"
+	nilSecretRemoteKey := "nil-secret"
+
+	property := "keys"
+	nestedProperty := "users.alice"
+	scalarValueProperty := "users.alice.age"
+	invalidProperty := "invalid-property"
+
 	testCases := map[string]struct {
-		shouldmap map[string][]byte
-		errshould string
-		kube      kclient.Client
-		ref       esv1.ExternalSecretDataRemoteRef
+		should     map[string][]byte
+		errshould  string
+		kube       kclient.Client
+		okmsClient fake.FakeOkmsClient
+		ref        esv1.ExternalSecretDataRemoteRef
 	}{
 		"Valid Secret": {
-			shouldmap: map[string][]byte{
-				"key": []byte("value"),
+			should: map[string][]byte{
+				"key1": []byte("value1"),
+				"key2": []byte("value2"),
 			},
 			ref: esv1.ExternalSecretDataRemoteRef{
-				Key: "key",
+				Key: mySecretRemoteKey,
 			},
 		},
 		"Non-existent Secret": {
-			errshould: "Secret does not exist",
+			errshould: "failed to parse the following okms error: Secret does not exist",
 			ref: esv1.ExternalSecretDataRemoteRef{
-				Key: "key",
+				Key: nonExistentSecretRemoteKey,
 			},
 		},
-		"Secret without data": {
-			errshould: "secret version data is missing",
+		"Secret with nil data": {
+			errshould: fmt.Sprintf("failed to retrieve secret at path %q: secret version data is missing", nilSecretRemoteKey),
 			ref: esv1.ExternalSecretDataRemoteRef{
-				Key: "key",
+				Key: nilSecretRemoteKey,
 			},
 		},
-		"MetaDataPolicy: Fetch": {
-			errshould: "fetch metadata policy not supported",
+		"Secret without empty data": {
+			errshould: fmt.Sprintf("failed to retrieve secret at path %q: secret version data is missing", emptySecretRemoteKey),
 			ref: esv1.ExternalSecretDataRemoteRef{
-				MetadataPolicy: "Fetch",
-				Key:            "key",
+				Key: emptySecretRemoteKey,
 			},
 		},
-		"Valid property that gets Nested Json": {
-			shouldmap: map[string][]byte{
-				"project1": []byte("Name"),
-				"project2": []byte("Name"),
-			},
+		"Fetch MetaDataPolicy": {
+			errshould: fmt.Sprintf("failed to retrieve secret at path %q: fetch metadata policy not supported", mySecretRemoteKey),
 			ref: esv1.ExternalSecretDataRemoteRef{
-				Property: "projects",
-				Key:      "key",
+				Key:            mySecretRemoteKey,
+				MetadataPolicy: "Fetch",
 			},
 		},
-		"Invalid property": {
-			errshould: "secret property \"Invalid Property\" not found",
+		"Property": {
+			should: map[string][]byte{
+				"key1": []byte("value1"),
+				"key2": []byte("value2"),
+			},
 			ref: esv1.ExternalSecretDataRemoteRef{
-				Property: "Invalid Property",
-				Key:      "key",
+				Key:      mySecret2RemoteKey,
+				Property: property,
 			},
 		},
-		"Empty property": {
-			shouldmap: map[string][]byte{
-				"key": []byte("value"),
+		"Nested Property": {
+			should: map[string][]byte{
+				"age": []byte("23"),
 			},
 			ref: esv1.ExternalSecretDataRemoteRef{
-				Property: "",
-				Key:      "key",
+				Key:      myNestedSecretRemoteKey,
+				Property: nestedProperty,
 			},
 		},
-		"Secret Version": {
-			shouldmap: map[string][]byte{
-				"key": []byte("value"),
+		"Scalar Value Property": {
+			errshould: fmt.Sprintf("failed to retrieve secret at path %q: json: cannot unmarshal number into Go value of type map[string]interface {}", myNestedSecretRemoteKey),
+			ref: esv1.ExternalSecretDataRemoteRef{
+				Key:      myNestedSecretRemoteKey,
+				Property: scalarValueProperty,
 			},
+		},
+		"Invalid Property": {
+			errshould: fmt.Sprintf("failed to retrieve secret at path %q: secret property %q not found", mySecretRemoteKey, invalidProperty),
 			ref: esv1.ExternalSecretDataRemoteRef{
-				Key: "key",
+				Key:      mySecretRemoteKey,
+				Property: invalidProperty,
 			},
 		},
-		"Invalid Secret Version": {
-			errshould: "ID=\"\", Request-ID:\"\", Code=17125378, System=CCM, Component=Secret Manager, Category=Not Found",
+		"Error case": {
+			errshould: fmt.Sprintf("failed to retrieve secret at path %q: failed to parse the following okms error: custom error", mySecretRemoteKey),
 			ref: esv1.ExternalSecretDataRemoteRef{
-				Key: "key",
+				Key:      mySecretRemoteKey,
+				Property: invalidProperty,
+			},
+			okmsClient: fake.FakeOkmsClient{
+				GetSecretV2Fn: fake.NewGetSecretV2Fn(mySecretRemoteKey, errors.New("custom error")),
 			},
 		},
 	}
@@ -107,25 +132,20 @@ func TestGetSecretMap(t *testing.T) {
 		t.Run(name, func(t *testing.T) {
 			ctx := context.Background()
 			cl := &ovhClient{
-				okmsClient: &fake.FakeOkmsClient{
-					TestCase: name,
-				},
-				kube: testCase.kube,
+				okmsClient: testCase.okmsClient,
+				kube:       testCase.kube,
 			}
 			secret, err := cl.GetSecretMap(ctx, testCase.ref)
 			if testCase.errshould != "" {
 				if err == nil {
-					t.Error()
+					t.Errorf("\nexpected value: %s\nactual value:   <nil>\n\n", testCase.errshould)
 				} else if err.Error() != testCase.errshould {
-					t.Error()
-				}
-			} else {
-				if err != nil {
-					t.Error()
-				}
-				if !reflect.DeepEqual(secret, testCase.shouldmap) {
-					t.Error()
+					t.Errorf("\nexpected value: %s\nactual value:   %v\n\n", testCase.errshould, err)
 				}
+				return
+			}
+			if !reflect.DeepEqual(testCase.should, secret) {
+				t.Errorf("\nexpected value: %v\nactual value:   %v\n\n", convertByteMapToStringMap(testCase.should), convertByteMapToStringMap(secret))
 			}
 		})
 	}

+ 61 - 47
providers/v1/ovh/client_get_secret_test.go

@@ -18,6 +18,8 @@ package ovh
 
 import (
 	"context"
+	"errors"
+	"fmt"
 	"testing"
 
 	kclient "sigs.k8s.io/controller-runtime/pkg/client"
@@ -27,75 +29,83 @@ import (
 )
 
 func TestGetSecret(t *testing.T) {
+	mySecretRemoteKey := "mysecret"
+	myNestedSecretRemoteKey := "nested-secret"
+	nonExistentSecretRemoteKey := "non-existent-secret"
+	emptySecretRemoteKey := "empty-secret"
+	nilSecretRemoteKey := "nil-secret"
+
+	property := "key1"
+	nestedProperty := "users.alice.age"
+	invalidProperty := "invalid-property"
+
 	testCases := map[string]struct {
-		should    string
-		errshould string
-		kube      kclient.Client
-		ref       esv1.ExternalSecretDataRemoteRef
+		should     string
+		errshould  string
+		kube       kclient.Client
+		ref        esv1.ExternalSecretDataRemoteRef
+		okmsClient fake.FakeOkmsClient
 	}{
 		"Valid Secret": {
-			should: "{\"key\":\"value\"}",
+			should: "{\"key1\":\"value1\",\"key2\":\"value2\"}",
 			ref: esv1.ExternalSecretDataRemoteRef{
-				Key: "key",
+				Key: mySecretRemoteKey,
 			},
 		},
 		"Non-existent Secret": {
-			errshould: "Secret does not exist",
+			errshould: "failed to parse the following okms error: Secret does not exist",
 			ref: esv1.ExternalSecretDataRemoteRef{
-				Key: "key",
+				Key: nonExistentSecretRemoteKey,
 			},
 		},
-		"Secret without data": {
-			errshould: "secret version data is missing",
+		"Secret with nil data": {
+			errshould: fmt.Sprintf("failed to retrieve secret at path %q: secret version data is missing", nilSecretRemoteKey),
 			ref: esv1.ExternalSecretDataRemoteRef{
-				Key: "key",
+				Key: nilSecretRemoteKey,
 			},
 		},
-		"MetaDataPolicy: Fetch": {
-			errshould: "fetch metadata policy not supported",
+		"Secret without empty data": {
+			errshould: fmt.Sprintf("failed to retrieve secret at path %q: secret version data is missing", emptySecretRemoteKey),
 			ref: esv1.ExternalSecretDataRemoteRef{
-				Key:            "key",
-				MetadataPolicy: "Fetch",
+				Key: emptySecretRemoteKey,
 			},
 		},
-		"Valid property that gets Nested Json": {
-			should: "{\"project1\":\"Name\",\"project2\":\"Name\"}",
+		"Fetch MetaDataPolicy": {
+			errshould: fmt.Sprintf("failed to retrieve secret at path %q: fetch metadata policy not supported", mySecretRemoteKey),
 			ref: esv1.ExternalSecretDataRemoteRef{
-				Key:      "key",
-				Property: "projects",
+				Key:            mySecretRemoteKey,
+				MetadataPolicy: "Fetch",
 			},
 		},
-		"Valid property that gets non_Nested Json": {
-			should: "Name",
+		"Property": {
+			should: "value1",
 			ref: esv1.ExternalSecretDataRemoteRef{
-				Key:      "key",
-				Property: "projects.project1",
+				Key:      mySecretRemoteKey,
+				Property: property,
 			},
 		},
-		"Invalid property": {
-			errshould: "secret property \"Invalid Property\" not found",
+		"Nested Property": {
+			should: "23",
 			ref: esv1.ExternalSecretDataRemoteRef{
-				Key:      "key",
-				Property: "Invalid Property",
+				Key:      myNestedSecretRemoteKey,
+				Property: nestedProperty,
 			},
 		},
-		"Empty property": {
-			should: "{\"key\":\"value\"}",
+		"Invalid Property": {
+			errshould: fmt.Sprintf("failed to retrieve secret at path %q: secret property %q not found", mySecretRemoteKey, invalidProperty),
 			ref: esv1.ExternalSecretDataRemoteRef{
-				Key:      "key",
-				Property: "",
+				Key:      mySecretRemoteKey,
+				Property: invalidProperty,
 			},
 		},
-		"Secret Version": {
-			should: "{\"key\":\"value\"}",
+		"Error case": {
+			errshould: fmt.Sprintf("failed to retrieve secret at path %q: failed to parse the following okms error: custom error", mySecretRemoteKey),
 			ref: esv1.ExternalSecretDataRemoteRef{
-				Key: "key",
+				Key:      mySecretRemoteKey,
+				Property: invalidProperty,
 			},
-		},
-		"Invalid Secret Version": {
-			errshould: "ID=\"\", Request-ID:\"\", Code=17125378, System=CCM, Component=Secret Manager, Category=Not Found",
-			ref: esv1.ExternalSecretDataRemoteRef{
-				Key: "key",
+			okmsClient: fake.FakeOkmsClient{
+				GetSecretV2Fn: fake.NewGetSecretV2Fn(mySecretRemoteKey, errors.New("custom error")),
 			},
 		},
 	}
@@ -103,16 +113,20 @@ func TestGetSecret(t *testing.T) {
 		t.Run(name, func(t *testing.T) {
 			ctx := context.Background()
 			cl := &ovhClient{
-				okmsClient: &fake.FakeOkmsClient{
-					TestCase: name,
-				},
-				kube: testCase.kube,
+				okmsClient: testCase.okmsClient,
+				kube:       testCase.kube,
 			}
 			secret, err := cl.GetSecret(ctx, testCase.ref)
-			if testCase.errshould != "" && err != nil && err.Error() != testCase.errshould {
-				t.Error()
-			} else if testCase.should != "" && string(secret) != testCase.should {
-				t.Error()
+			if testCase.errshould != "" {
+				if err == nil {
+					t.Errorf("\nexpected error: %s\nactual error:   <nil>\n\n", testCase.errshould)
+				} else if err.Error() != testCase.errshould {
+					t.Errorf("\nexpected error: %s\nactual error:   %v\n\n", testCase.errshould, err)
+				}
+				return
+			}
+			if testCase.should != "" && string(secret) != testCase.should {
+				t.Errorf("\nexpected value: %q\nactual value:   %q\n\n", testCase.should, string(secret))
 			}
 		})
 	}

+ 105 - 154
providers/v1/ovh/client_push_secret_test.go

@@ -18,6 +18,8 @@ package ovh
 
 import (
 	"context"
+	"errors"
+	"fmt"
 	"testing"
 
 	v1 "k8s.io/api/core/v1"
@@ -27,193 +29,142 @@ import (
 )
 
 func TestPushSecret(t *testing.T) {
+	secretData := &v1.Secret{
+		Data: map[string][]byte{
+			"key1": []byte("value1"),
+			"key2": []byte("value2"),
+		},
+	}
+	mySecretRemoteKey := "mysecret"
+	mySecret2RemoteKey := "mysecret2"
+	nonExistentSecretRemoteKey := "non-existent-secret"
+	emptyRemoteKey := ""
+	emptySecretRemoteKey := "empty-secret"
+	nilSecretRemoteKey := "nil-secret"
+
 	testCases := map[string]struct {
-		should string
-		secret *v1.Secret
-		data   testingfake.PushSecretData
+		errshould  string
+		secret     *v1.Secret
+		data       testingfake.PushSecretData
+		okmsClient fake.FakeOkmsClient
 	}{
 		"Nil Secret": {
-			should: "nil secret",
-			secret: nil,
+			errshould: fmt.Sprintf("failed to push secret at path %q: provided secret is nil", nilSecretRemoteKey),
+			secret:    nil,
 			data: testingfake.PushSecretData{
-				SecretKey: "secretKey",
-				RemoteKey: "remoteKey",
-				Property:  "property",
+				RemoteKey: nilSecretRemoteKey,
 			},
-		},
-		"Nil Secret Data": {
-			should: "cannot push empty secret",
-			secret: &v1.Secret{
-				Data: nil,
-			},
-			data: testingfake.PushSecretData{
-				SecretKey: "secretKey",
-				RemoteKey: "remoteKey",
-				Property:  "property",
+			okmsClient: fake.FakeOkmsClient{
+				PostSecretV2Fn: fake.NewPostSecretV2Fn(nil),
+				PutSecretV2Fn:  fake.NewPutSecretV2Fn(nil),
 			},
 		},
 		"Empty Secret Data": {
-			should: "cannot push empty secret",
+			errshould: fmt.Sprintf("failed to push secret at path %q: provided secret is empty", emptySecretRemoteKey),
 			secret: &v1.Secret{
-				Data: map[string][]byte{},
+				Data: nil,
 			},
 			data: testingfake.PushSecretData{
-				SecretKey: "secretKey",
-				RemoteKey: "remoteKey",
-				Property:  "property",
+				RemoteKey: emptySecretRemoteKey,
+			},
+			okmsClient: fake.FakeOkmsClient{
+				PostSecretV2Fn: fake.NewPostSecretV2Fn(nil),
+				PutSecretV2Fn:  fake.NewPutSecretV2Fn(nil),
 			},
 		},
 		"Empty Remote Key": {
-			should: "spec.data.remoteRef.key cannot be empty",
-			secret: &v1.Secret{
-				Data: map[string][]byte{
-					"key": []byte("value"),
-				},
-			},
+			errshould: fmt.Sprintf("failed to push secret at path %q: remote key cannot be empty (spec.data.remoteRef.key)", emptyRemoteKey),
+			secret:    secretData,
 			data: testingfake.PushSecretData{
-				RemoteKey: "",
-			},
-		},
-		"Empty Secret Key / Empty Property / Existing Remote Key (Equal Data)": {
-			should: "",
-			secret: &v1.Secret{
-				Data: map[string][]byte{
-					"test4": []byte(`"value4"`),
-				},
+				RemoteKey: emptyRemoteKey,
 			},
-			data: testingfake.PushSecretData{
-				SecretKey: "",
-				RemoteKey: "pattern2/test/test-secret",
-				Property:  "",
+			okmsClient: fake.FakeOkmsClient{
+				PostSecretV2Fn: fake.NewPostSecretV2Fn(nil),
+				PutSecretV2Fn:  fake.NewPutSecretV2Fn(nil),
 			},
 		},
-		"Empty Secret Key / Property / Existing Remote Key (Equal Data)": {
-			should: `{"property":{"test4":"value4"}}`,
-			secret: &v1.Secret{
-				Data: map[string][]byte{
-					"test4": []byte(`"value4"`),
-				},
-			},
+		"Non-Existent Remote Key": {
+			errshould: "",
+			secret:    secretData,
 			data: testingfake.PushSecretData{
-				SecretKey: "",
-				RemoteKey: "pattern2/test/test-secret",
-				Property:  "property",
-			},
-		},
-		"Empty Secret Key / Empty Property / Existing Remote Key (Non-Equal Data)": {
-			should: `{"new-test4":"new-value4"}`,
-			secret: &v1.Secret{
-				Data: map[string][]byte{
-					"new-test4": []byte(`"new-value4"`),
-				},
+				RemoteKey: nonExistentSecretRemoteKey,
 			},
-			data: testingfake.PushSecretData{
-				SecretKey: "",
-				RemoteKey: "pattern2/test/test-secret",
-				Property:  "",
+			okmsClient: fake.FakeOkmsClient{
+				PostSecretV2Fn: fake.NewPostSecretV2Fn(nil),
+				PutSecretV2Fn:  fake.NewPutSecretV2Fn(nil),
 			},
 		},
-		"Empty Secret Key / Property / Existing Remote Key (Non-Equal Data)": {
-			should: `{"property":{"new-test4":"new-value4"}}`,
-			secret: &v1.Secret{
-				Data: map[string][]byte{
-					"new-test4": []byte(`"new-value4"`),
-				},
-			},
+		"Existing Remote Key": {
+			errshould: "",
+			secret:    secretData,
 			data: testingfake.PushSecretData{
-				SecretKey: "",
-				RemoteKey: "pattern2/test/test-secret",
-				Property:  "property",
+				RemoteKey: mySecretRemoteKey,
 			},
-		},
-		"Empty Secret Key / Empty Property / Non-Existent Remote Key": {
-			should: `{"root":{"sub1":{"value":"string"},"sub2":"Name"},"test":"value","test1":"value1"}`,
-			secret: &v1.Secret{
-				Data: map[string][]byte{
-					"root":  []byte(`{"sub1":{"value":"string"},"sub2":"Name"}`),
-					"test":  []byte(`"value"`),
-					"test1": []byte(`"value1"`),
-				},
+			okmsClient: fake.FakeOkmsClient{
+				PostSecretV2Fn: fake.NewPostSecretV2Fn(nil),
+				PutSecretV2Fn:  fake.NewPutSecretV2Fn(nil),
 			},
+		},
+		"Secret Key": {
+			errshould: "",
+			secret:    secretData,
 			data: testingfake.PushSecretData{
-				SecretKey: "",
-				RemoteKey: "non-existent",
-				Property:  "",
+				RemoteKey: mySecretRemoteKey,
+				SecretKey: "key1",
 			},
-		},
-		"Empty Secret Key / Property / Non-Existent Remote Key": {
-			should: `{"property":{"root":{"sub1":{"value":"string"},"sub2":"Name"},"test":"value","test1":"value1"}}`,
-			secret: &v1.Secret{
-				Data: map[string][]byte{
-					"root":  []byte(`{"sub1":{"value":"string"},"sub2":"Name"}`),
-					"test":  []byte(`"value"`),
-					"test1": []byte(`"value1"`),
-				},
+			okmsClient: fake.FakeOkmsClient{
+				PostSecretV2Fn: fake.NewPostSecretV2Fn(nil),
+				PutSecretV2Fn:  fake.NewPutSecretV2Fn(nil),
 			},
+		},
+		"Property": {
+			errshould: "",
+			secret:    secretData,
 			data: testingfake.PushSecretData{
-				SecretKey: "",
-				RemoteKey: "non-existent",
+				RemoteKey: mySecretRemoteKey,
 				Property:  "property",
 			},
-		},
-		"Secret Key / Empty Property / Existing Remote Key": {
-			should: `{"test":"value"}`,
-			secret: &v1.Secret{
-				Data: map[string][]byte{
-					"root":  []byte(`{"sub1":{"value":"string"},"sub2":"Name"}`),
-					"test":  []byte(`"value"`),
-					"test1": []byte(`"value1"`),
-				},
-			},
-			data: testingfake.PushSecretData{
-				SecretKey: "test",
-				RemoteKey: "pattern1/path3",
-				Property:  "",
+			okmsClient: fake.FakeOkmsClient{
+				PostSecretV2Fn: fake.NewPostSecretV2Fn(nil),
+				PutSecretV2Fn:  fake.NewPutSecretV2Fn(nil),
 			},
 		},
-		"Secret Key / Property / Existing Remote Key": {
-			should: `{"property":{"test":"value"}}`,
-			secret: &v1.Secret{
-				Data: map[string][]byte{
-					"root":  []byte(`{"sub1":{"value":"string"},"sub2":"Name"}`),
-					"test":  []byte(`"value"`),
-					"test1": []byte(`"value1"`),
-				},
-			},
+		"Custom PostSecretV2 Error": {
+			errshould: fmt.Sprintf("failed to push secret at path %q: could not create remote secret \"mysecret\": custom error", mySecretRemoteKey),
+			secret:    secretData,
 			data: testingfake.PushSecretData{
-				SecretKey: "test",
-				RemoteKey: "pattern1/path3",
-				Property:  "property",
+				RemoteKey: mySecretRemoteKey,
 			},
-		},
-		"Secret Key / Property / Non-Existent Remote Key": {
-			should: `{"property":{"test":"value"}}`,
-			secret: &v1.Secret{
-				Data: map[string][]byte{
-					"root":  []byte(`{"sub1":{"value":"string"},"sub2":"Name"}`),
-					"test":  []byte(`"value"`),
-					"test1": []byte(`"value1"`),
-				},
+			okmsClient: fake.FakeOkmsClient{
+				// A non-existent secret is referenced to trigger Post instead of Put
+				GetSecretV2Fn:  fake.NewGetSecretV2Fn(nonExistentSecretRemoteKey, nil),
+				PostSecretV2Fn: fake.NewPostSecretV2Fn(errors.New("custom error")),
+				PutSecretV2Fn:  fake.NewPutSecretV2Fn(nil),
 			},
+		},
+		"Custom PutSecretV2 Error": {
+			errshould: fmt.Sprintf("failed to push secret at path %q: could not update remote secret \"mysecret\": custom error", mySecretRemoteKey),
+			secret:    secretData,
 			data: testingfake.PushSecretData{
-				SecretKey: "test",
-				RemoteKey: "non-existent",
-				Property:  "property",
+				RemoteKey: mySecretRemoteKey,
 			},
-		},
-		"Secret Key / Empty Property / Non-Existent Remote Key": {
-			should: `{"test":"value"}`,
-			secret: &v1.Secret{
-				Data: map[string][]byte{
-					"root":  []byte(`{"sub1":{"value":"string"},"sub2":"Name"}`),
-					"test":  []byte(`"value"`),
-					"test1": []byte(`"value1"`),
-				},
+			okmsClient: fake.FakeOkmsClient{
+				// An existing secret is referenced to trigger Put instead of Post
+				GetSecretV2Fn:  fake.NewGetSecretV2Fn(mySecret2RemoteKey, nil),
+				PostSecretV2Fn: fake.NewPostSecretV2Fn(nil),
+				PutSecretV2Fn:  fake.NewPutSecretV2Fn(errors.New("custom error")),
 			},
+		},
+		"Custom GetSecretV2 Error": {
+			errshould: fmt.Sprintf("failed to push secret at path %q: failed to parse the following okms error: custom error", mySecretRemoteKey),
+			secret:    secretData,
 			data: testingfake.PushSecretData{
-				SecretKey: "test",
-				RemoteKey: "non-existent",
-				Property:  "",
+				RemoteKey: mySecretRemoteKey,
+			},
+			okmsClient: fake.FakeOkmsClient{
+				GetSecretV2Fn:  fake.NewGetSecretV2Fn(mySecretRemoteKey, errors.New("custom error")),
+				PostSecretV2Fn: fake.NewPostSecretV2Fn(nil),
+				PutSecretV2Fn:  fake.NewPutSecretV2Fn(nil),
 			},
 		},
 	}
@@ -222,15 +173,15 @@ func TestPushSecret(t *testing.T) {
 	for name, testCase := range testCases {
 		t.Run(name, func(t *testing.T) {
 			cl := ovhClient{
-				okmsClient: &fake.FakeOkmsClient{
-					TestCase: name,
-				},
+				okmsClient: testCase.okmsClient,
 			}
 			err := cl.PushSecret(ctx, testCase.secret, testCase.data)
-			if err != nil && testCase.should != err.Error() {
-				t.Error()
-			} else if err == nil && testCase.should != "" {
-				t.Error()
+			if testCase.errshould != "" {
+				if err == nil {
+					t.Errorf("\nexpected error: %s\nactual error:   <nil>\n\n", testCase.errshould)
+				} else if err.Error() != testCase.errshould {
+					t.Errorf("\nexpected error: %s\nactual error:   %v\n\n", testCase.errshould, err)
+				}
 			}
 		})
 	}

+ 27 - 20
providers/v1/ovh/client_secret_exists_test.go

@@ -18,6 +18,8 @@ package ovh
 
 import (
 	"context"
+	"errors"
+	"fmt"
 	"testing"
 
 	kclient "sigs.k8s.io/controller-runtime/pkg/client"
@@ -27,49 +29,54 @@ import (
 )
 
 func TestSecretExists(t *testing.T) {
+	mysecretRef := testingfake.PushSecretData{
+		RemoteKey: "mysecret",
+	}
+	nonExistentSecretRef := testingfake.PushSecretData{
+		RemoteKey: "non-existent-secret",
+	}
+
 	testCases := map[string]struct {
-		should    bool
-		errshould string
-		kube      kclient.Client
-		remoteRef testingfake.PushSecretData
+		should     bool
+		errshould  string
+		remoteRef  testingfake.PushSecretData
+		okmsClient fake.FakeOkmsClient
+		kube       kclient.Client
 	}{
 		"Valid Secret": {
 			should:    true,
-			remoteRef: testingfake.PushSecretData{},
+			remoteRef: mysecretRef,
 		},
 		"Non-existent Secret": {
 			should:    false,
-			remoteRef: testingfake.PushSecretData{},
+			remoteRef: nonExistentSecretRef,
 		},
 		"Error case": {
-			errshould: "failed to parse okms error: SecretExists error",
-			remoteRef: testingfake.PushSecretData{},
+			errshould: fmt.Sprintf("failed to check existence of secret %q: failed to parse the following okms error: custom error", mysecretRef.RemoteKey),
+			remoteRef: mysecretRef,
+			okmsClient: fake.FakeOkmsClient{
+				GetSecretV2Fn: fake.NewGetSecretV2Fn(mysecretRef.RemoteKey, errors.New("custom error")),
+			},
 		},
 	}
 	for name, testCase := range testCases {
 		t.Run(name, func(t *testing.T) {
 			cl := &ovhClient{
-				kube: testCase.kube,
-				okmsClient: &fake.FakeOkmsClient{
-					TestCase: name,
-				},
+				kube:       testCase.kube,
+				okmsClient: testCase.okmsClient,
 			}
 			ctx := context.Background()
 			exists, err := cl.SecretExists(ctx, testCase.remoteRef)
 			if testCase.errshould != "" {
 				if err == nil {
-					t.Error()
-				}
-				if err.Error() != testCase.errshould {
-					t.Error()
+					t.Errorf("\nexpected error: %s\nactual error:   <nil>\n\n", testCase.errshould)
+				} else if err.Error() != testCase.errshould {
+					t.Errorf("\nexpected error: %s\nactual error:   %v\n\n", testCase.errshould, err)
 				}
 				return
 			}
-			if err != nil {
-				t.Fatalf("unexpected error: %v", err)
-			}
 			if exists != testCase.should {
-				t.Error()
+				t.Errorf("\nexpected value: %t\nactual value:   %t\n\n", testCase.should, exists)
 			}
 		})
 	}

+ 2 - 2
providers/v1/ovh/client_utils.go

@@ -57,7 +57,7 @@ func getSecretWithOvhSDK(ctx context.Context, kmsClient OkmsClient, okmsID uuid.
 	if secret == nil {
 		return []byte{}, nil, esv1.NoSecretErr
 	}
-	if secret.Version == nil || secret.Version.Data == nil {
+	if secret.Version == nil || secret.Version.Data == nil || len(*secret.Version.Data) == 0 {
 		return []byte{}, nil, errors.New("secret version data is missing")
 	}
 
@@ -122,7 +122,7 @@ func handleOkmsError(err error) error {
 	okmsError := okms.AsKmsError(err)
 
 	if okmsError == nil {
-		return fmt.Errorf("failed to parse okms error: %w", err)
+		return fmt.Errorf("failed to parse the following okms error: %w", err)
 	} else if okmsError.ErrorCode == 17125377 { // 17125377: returned by OKMS when secret was not found
 		return esv1.NoSecretErr
 	}

+ 160 - 358
providers/v1/ovh/fake/fake_okms_client.go

@@ -18,411 +18,213 @@ package fake
 
 import (
 	"context"
-	"encoding/json"
 	"errors"
-	"fmt"
+	"maps"
 	"strings"
 
+	esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
 	"github.com/google/uuid"
 	"github.com/ovh/okms-sdk-go"
 	"github.com/ovh/okms-sdk-go/types"
 )
 
-const str = "string"
+type GetSecretV2Fn func() (*types.GetSecretV2Response, error)
+type ListSecretV2Fn func() (*types.ListSecretV2ResponseWithPagination, error)
+type PostSecretV2Fn func() (*types.PostSecretV2Response, error)
+type PutSecretV2Fn func() (*types.PutSecretV2Response, error)
+type DeleteSecretV2Fn func() error
+type WithCustomHeaderFn func() *okms.Client
+type GetSecretsMetadataFn func() (*types.GetMetadataResponse, error)
 
 type FakeOkmsClient struct {
-	TestCase string
+	GetSecretV2Fn        GetSecretV2Fn
+	ListSecretV2Fn       ListSecretV2Fn
+	PostSecretV2Fn       PostSecretV2Fn
+	PutSecretV2Fn        PutSecretV2Fn
+	DeleteSecretV2Fn     DeleteSecretV2Fn
+	GetSecretsMetadataFn GetSecretsMetadataFn
 }
 
-func (kmsClient FakeOkmsClient) GetSecretV2(_ context.Context, _ uuid.UUID, path string, _ *uint32, _ *bool) (*types.GetSecretV2Response, error) {
-	// Called by GetSecret() & GetSecretMap()
-
-	// Metadata
-	CasRequired := true
-	CreatedAt := str
-	DeactivateVersionAfter := str
-	MaxVersions := uint32(10)
-	UpdatedAt := str
-	var State types.SecretV2State = str
-
-	// Version
-	Data := map[string]any{
-		"key": "value",
-	}
-	NestedData := map[string]any{
-		"projects": map[string]any{
-			"project1": "Name",
-			"project2": "Name",
-		},
-		"test": "value",
-	}
-	DeactivatedAt := "string"
-	Warnings := []string{}
-	dataSecretV2Response := &types.GetSecretV2Response{
-		Metadata: &types.SecretV2Metadata{
-			CasRequired:            &CasRequired,
-			CreatedAt:              &CreatedAt,
-			DeactivateVersionAfter: &DeactivateVersionAfter,
-			MaxVersions:            &MaxVersions,
-			UpdatedAt:              &UpdatedAt,
-		},
-		Path: &kmsClient.TestCase,
-		Version: &types.SecretV2Version{
-			CreatedAt:     CreatedAt,
-			Data:          &Data,
-			DeactivatedAt: &DeactivatedAt,
-			Id:            1,
-			State:         State,
-			Warnings:      &Warnings,
-		},
-	}
-	nestedDataSecretV2Response := &types.GetSecretV2Response{
-		Metadata: &types.SecretV2Metadata{
-			CasRequired:            &CasRequired,
-			CreatedAt:              &CreatedAt,
-			DeactivateVersionAfter: &DeactivateVersionAfter,
-			MaxVersions:            &MaxVersions,
-			UpdatedAt:              &UpdatedAt,
+var fakeSecretStorage = map[string]map[string]any{
+	"mysecret": {
+		"key1": "value1",
+		"key2": "value2",
+	},
+	"mysecret2": {
+		"keys": map[string]string{
+			"key1": "value1",
+			"key2": "value2",
 		},
-		Path: &kmsClient.TestCase,
-		Version: &types.SecretV2Version{
-			CreatedAt:     CreatedAt,
-			Data:          &NestedData,
-			DeactivatedAt: &DeactivatedAt,
-			Id:            1,
-			State:         State,
-			Warnings:      &Warnings,
-		},
-	}
-
-	// Test Cases
-	switch kmsClient.TestCase {
-	case "Valid Secret":
-		return dataSecretV2Response, nil
-	case "MetaDataPolicy: Fetch":
-		return dataSecretV2Response, nil
-	case "Non-existent Secret":
-		kmsError := okms.NewKmsErrorFromBytes([]byte("{\"error_code\":17125377}"))
-		return nil, kmsError
-	case "Secret without data":
-		return &types.GetSecretV2Response{
-			Metadata: &types.SecretV2Metadata{
-				CasRequired:            &CasRequired,
-				CreatedAt:              &CreatedAt,
-				DeactivateVersionAfter: &DeactivateVersionAfter,
-				MaxVersions:            &MaxVersions,
-				UpdatedAt:              &UpdatedAt,
+		"token": "value",
+	},
+	"nested-secret": {
+		"users": map[string]any{
+			"alice": map[string]string{
+				"age": "23",
 			},
-			Path: &kmsClient.TestCase,
-			Version: &types.SecretV2Version{
-				CreatedAt:     CreatedAt,
-				Data:          nil,
-				DeactivatedAt: &DeactivatedAt,
-				Id:            1,
-				State:         State,
-				Warnings:      &Warnings,
+			"baptist": map[string]string{
+				"age": "27",
 			},
-		}, nil
-	case "Valid property that gets Nested Json":
-		return nestedDataSecretV2Response, nil
-	case "Valid property that gets non_Nested Json":
-		return nestedDataSecretV2Response, nil
-	case "Invalid property":
-		return dataSecretV2Response, nil
-	case "Empty property":
-		return dataSecretV2Response, nil
-	case "Secret Version":
-		return dataSecretV2Response, nil
-	case "Invalid Secret Version":
-		kmsError := okms.NewKmsErrorFromBytes([]byte("{\"error_code\":17125378}"))
-		return nil, kmsError
-	case "Error case":
-		return &types.GetSecretV2Response{}, errors.New("SecretExists error")
-	}
-
-	if path == "" {
-		return &types.GetSecretV2Response{}, errors.New("unknown case")
-	}
-
-	// Called by GetAllSecrets()
-	data1 := map[string]any{
-		"projects": map[string]any{
+		},
+	},
+	"pattern1/path1": {
+		"projects": map[string]string{
 			"project1": "Name",
 			"project2": "Name",
 		},
-	}
-	data2 := map[string]any{
+	},
+	"pattern1/path2": {
 		"key": "value",
-	}
-	data3 := map[string]any{
+	},
+	"pattern1/path3": {
 		"root": map[string]any{
-			"sub1": map[string]any{
+			"sub1": map[string]string{
 				"value": "string",
 			},
 			"sub2": "Name",
 		},
-		"test":  "value",
-		"test1": "value1",
-	}
-	data4 := map[string]any{
-		"test4": "value4",
-	}
-	data5 := map[string]any{
-		"test5": "value5",
-	}
-	data6 := map[string]any{
-		"test6": "value6",
-	}
-	data7 := map[string]any{
-		"test7": "value7",
-	}
-	data8 := map[string]any{
-		"test8": "value8",
+		"test": "value", "test1": "value1",
+	},
+	"pattern2/test/test-secret": {
+		"key4": "value4",
+	},
+	"pattern2/test/test.secret": {
+		"key5": "value5",
+	},
+	"pattern2/secret": {
+		"key6": "value6",
+	},
+	"1secret": {
+		"key7": "value7",
+	},
+	"pattern2/test/test;secret": {
+		"key8": "value8",
+	},
+	"nil-secret":   nil,
+	"empty-secret": {},
+}
+
+func (f FakeOkmsClient) GetSecretV2(ctx context.Context, okmsID uuid.UUID, path string, version *uint32, includeData *bool) (*types.GetSecretV2Response, error) {
+	if f.GetSecretV2Fn != nil {
+		return f.GetSecretV2Fn()
 	}
-	switch path {
-	case "pattern1/path1":
-		return &types.GetSecretV2Response{
-			Metadata: &types.SecretV2Metadata{
-				CasRequired:            &CasRequired,
-				CreatedAt:              &CreatedAt,
-				DeactivateVersionAfter: &DeactivateVersionAfter,
-				MaxVersions:            &MaxVersions,
-				UpdatedAt:              &UpdatedAt,
-			},
-			Path: &kmsClient.TestCase,
-			Version: &types.SecretV2Version{
-				CreatedAt:     CreatedAt,
-				Data:          &data1,
-				DeactivatedAt: &DeactivatedAt,
-				Id:            1,
-				State:         State,
-				Warnings:      &Warnings,
-			},
-		}, nil
-	case "pattern1/path2":
-		return &types.GetSecretV2Response{
-			Metadata: &types.SecretV2Metadata{
-				CasRequired:            &CasRequired,
-				CreatedAt:              &CreatedAt,
-				DeactivateVersionAfter: &DeactivateVersionAfter,
-				MaxVersions:            &MaxVersions,
-				UpdatedAt:              &UpdatedAt,
-			},
-			Path: &kmsClient.TestCase,
-			Version: &types.SecretV2Version{
-				CreatedAt:     CreatedAt,
-				Data:          &data2,
-				DeactivatedAt: &DeactivatedAt,
-				Id:            1,
-				State:         State,
-				Warnings:      &Warnings,
-			},
-		}, nil
-	case "pattern1/path3":
-		return &types.GetSecretV2Response{
-			Metadata: &types.SecretV2Metadata{
-				CasRequired:            &CasRequired,
-				CreatedAt:              &CreatedAt,
-				DeactivateVersionAfter: &DeactivateVersionAfter,
-				MaxVersions:            &MaxVersions,
-				UpdatedAt:              &UpdatedAt,
-			},
-			Path: &kmsClient.TestCase,
-			Version: &types.SecretV2Version{
-				CreatedAt:     CreatedAt,
-				Data:          &data3,
-				DeactivatedAt: &DeactivatedAt,
-				Id:            1,
-				State:         State,
-				Warnings:      &Warnings,
-			},
-		}, nil
-	case "pattern2/test/test-secret":
-		return &types.GetSecretV2Response{
-			Metadata: &types.SecretV2Metadata{
-				CasRequired:            &CasRequired,
-				CreatedAt:              &CreatedAt,
-				DeactivateVersionAfter: &DeactivateVersionAfter,
-				MaxVersions:            &MaxVersions,
-				UpdatedAt:              &UpdatedAt,
-			},
-			Path: &kmsClient.TestCase,
-			Version: &types.SecretV2Version{
-				CreatedAt:     CreatedAt,
-				Data:          &data4,
-				DeactivatedAt: &DeactivatedAt,
-				Id:            1,
-				State:         State,
-				Warnings:      &Warnings,
-			},
-		}, nil
-	case "pattern2/test/test.secret":
-		return &types.GetSecretV2Response{
-			Metadata: &types.SecretV2Metadata{
-				CasRequired:            &CasRequired,
-				CreatedAt:              &CreatedAt,
-				DeactivateVersionAfter: &DeactivateVersionAfter,
-				MaxVersions:            &MaxVersions,
-				UpdatedAt:              &UpdatedAt,
-			},
-			Path: &kmsClient.TestCase,
-			Version: &types.SecretV2Version{
-				CreatedAt:     CreatedAt,
-				Data:          &data5,
-				DeactivatedAt: &DeactivatedAt,
-				Id:            1,
-				State:         State,
-				Warnings:      &Warnings,
-			},
-		}, nil
-	case "pattern2/secret":
-		return &types.GetSecretV2Response{
-			Metadata: &types.SecretV2Metadata{
-				CasRequired:            &CasRequired,
-				CreatedAt:              &CreatedAt,
-				DeactivateVersionAfter: &DeactivateVersionAfter,
-				MaxVersions:            &MaxVersions,
-				UpdatedAt:              &UpdatedAt,
-			},
-			Path: &kmsClient.TestCase,
-			Version: &types.SecretV2Version{
-				CreatedAt:     CreatedAt,
-				Data:          &data6,
-				DeactivatedAt: &DeactivatedAt,
-				Id:            1,
-				State:         State,
-				Warnings:      &Warnings,
-			},
-		}, nil
-	case "1secret":
-		return &types.GetSecretV2Response{
-			Metadata: &types.SecretV2Metadata{
-				CasRequired:            &CasRequired,
-				CreatedAt:              &CreatedAt,
-				DeactivateVersionAfter: &DeactivateVersionAfter,
-				MaxVersions:            &MaxVersions,
-				UpdatedAt:              &UpdatedAt,
-			},
-			Path: &kmsClient.TestCase,
-			Version: &types.SecretV2Version{
-				CreatedAt:     CreatedAt,
-				Data:          &data7,
-				DeactivatedAt: &DeactivatedAt,
-				Id:            1,
-				State:         State,
-				Warnings:      &Warnings,
-			},
-		}, nil
-	case "pattern2/test/test;secret":
+	return NewGetSecretV2Fn(path, nil)()
+}
+func NewGetSecretV2Fn(path string, err error) GetSecretV2Fn {
+	return func() (*types.GetSecretV2Response, error) {
+		if err != nil {
+			return nil, err
+		}
+
+		secret, ok := fakeSecretStorage[path]
+		if !ok {
+			return nil, esv1.NoSecretErr
+		}
+		data := maps.Clone(secret)
+
 		return &types.GetSecretV2Response{
-			Metadata: &types.SecretV2Metadata{
-				CasRequired:            &CasRequired,
-				CreatedAt:              &CreatedAt,
-				DeactivateVersionAfter: &DeactivateVersionAfter,
-				MaxVersions:            &MaxVersions,
-				UpdatedAt:              &UpdatedAt,
-			},
-			Path: &kmsClient.TestCase,
 			Version: &types.SecretV2Version{
-				CreatedAt:     CreatedAt,
-				Data:          &data8,
-				DeactivatedAt: &DeactivatedAt,
-				Id:            1,
-				State:         State,
-				Warnings:      &Warnings,
+				Data: &data,
 			},
 		}, nil
-	case "non-existent":
-		kmsError := okms.NewKmsErrorFromBytes([]byte("{\"error_code\":17125377}"))
-		return &types.GetSecretV2Response{}, kmsError
 	}
-	return &types.GetSecretV2Response{}, errors.New("unknown path")
 }
 
-func (kmsClient FakeOkmsClient) GetSecretsMetadata(_ context.Context, _ uuid.UUID, path string, _ bool) (*types.GetMetadataResponse, error) {
-	switch path {
-	case "nil resp":
-		return nil, nil
-	case "nil data struct":
-		return &types.GetMetadataResponse{}, nil
-	case "nil secrets list":
-		return &types.GetMetadataResponse{
-			Data: &types.SecretMetadata{},
-		}, nil
-	case "empty secrets list":
-		return &types.GetMetadataResponse{
-			Data: &types.SecretMetadata{
-				Keys: &[]string{},
-			},
-		}, nil
-	case "error response":
-		return nil, errors.New("error response")
-	}
-
-	paths := []string{
-		"pattern1/path1",
-		"pattern1/path2",
-		"pattern1/path3",
-		"pattern2/test/test-secret",
-		"pattern2/test/test.secret",
-		"pattern2/secret",
-		"1secret",
-		"pattern2/test/test;secret",
-	}
-	resp := &types.GetMetadataResponse{
-		Data: &types.SecretMetadata{
-			Keys: &[]string{},
-		},
-	}
-	if path == "" {
-		resp.Data.Keys = &paths
-		return resp, nil
-	}
+func (f FakeOkmsClient) ListSecretV2(ctx context.Context, okmsID uuid.UUID, pageSize *uint32, pageCursor *string) (*types.ListSecretV2ResponseWithPagination, error) {
+	return f.ListSecretV2Fn()
+}
+func NewListSecretV2Fn(err error) ListSecretV2Fn {
+	return func() (*types.ListSecretV2ResponseWithPagination, error) {
+		if err != nil {
+			return nil, err
+		}
 
-	for _, path_elem := range paths {
-		posStart := strings.Index(path_elem, path)
-		if posStart == 0 {
-			if len(path) == len(path_elem) {
-				*resp.Data.Keys = append(*resp.Data.Keys, path_elem)
-			} else if len(path) < len(path_elem) && path_elem[len(path)] == '/' {
-				path_elem = path_elem[len(path)+1:]
-				posSlash := strings.Index(path_elem, "/")
-				if posSlash >= 0 {
-					*resp.Data.Keys = append(*resp.Data.Keys, path_elem[:posSlash])
-				} else {
-					*resp.Data.Keys = append(*resp.Data.Keys, path_elem)
-				}
+		secretList := &types.ListSecretV2ResponseWithPagination{}
+		for k := range fakeSecretStorage {
+			newPath := types.GetSecretV2Response{
+				Path: &k,
 			}
+			secretList.ListSecretV2Response = append(secretList.ListSecretV2Response, newPath)
 		}
-	}
 
-	return resp, nil
+		return secretList, nil
+	}
 }
 
-func (kmsClient FakeOkmsClient) ListSecretV2(_ context.Context, _ uuid.UUID, _ *uint32, _ *string) (*types.ListSecretV2ResponseWithPagination, error) {
-	return nil, nil
+func (f FakeOkmsClient) PostSecretV2(ctx context.Context, okmsID uuid.UUID, body types.PostSecretV2Request) (*types.PostSecretV2Response, error) {
+	return f.PostSecretV2Fn()
 }
-
-func (client FakeOkmsClient) WithCustomHeader(_, _ string) *okms.Client {
-	return &okms.Client{}
+func NewPostSecretV2Fn(err error) PostSecretV2Fn {
+	return func() (*types.PostSecretV2Response, error) {
+		return nil, err
+	}
 }
 
-func (client FakeOkmsClient) PostSecretV2(_ context.Context, _ uuid.UUID, body types.PostSecretV2Request) (*types.PostSecretV2Response, error) {
-	secretDataByte, err := json.Marshal(body.Version.Data)
-	if err != nil {
+func (f FakeOkmsClient) PutSecretV2(ctx context.Context, okmsID uuid.UUID, path string, cas *uint32, body types.PutSecretV2Request) (*types.PutSecretV2Response, error) {
+	return f.PutSecretV2Fn()
+}
+func NewPutSecretV2Fn(err error) PutSecretV2Fn {
+	return func() (*types.PutSecretV2Response, error) {
 		return nil, err
 	}
-	return nil, fmt.Errorf("%s", string(secretDataByte))
 }
 
-func (client FakeOkmsClient) PutSecretV2(_ context.Context, _ uuid.UUID, _ string, _ *uint32, body types.PutSecretV2Request) (*types.PutSecretV2Response, error) {
-	secretDataByte, err := json.Marshal(body.Version.Data)
-	if err != nil {
-		return nil, err
+func (f FakeOkmsClient) DeleteSecretV2(ctx context.Context, okmsID uuid.UUID, path string) error {
+	return f.DeleteSecretV2Fn()
+}
+func NewDeleteSecretV2Fn(err error) DeleteSecretV2Fn {
+	return func() error {
+		return err
+	}
+}
+
+// GetSecretsMetadata is a mock implementation of the OVH SDK GetSecretsMetadata method.
+// It returns metadata for all secrets under the given path.
+//
+// Keys ending with a '/' indicate subpaths, meaning the key represents a folder rather
+// than a final secret value.
+//
+// This implementation returns a list of secrets from fakeSecretStorage variable.
+func (f FakeOkmsClient) GetSecretsMetadata(ctx context.Context, okmsID uuid.UUID, path string, list bool) (*types.GetMetadataResponse, error) {
+	return f.GetSecretsMetadataFn()
+}
+func NewGetSecretsMetadataFn(path string, err error) GetSecretsMetadataFn {
+	return func() (*types.GetMetadataResponse, error) {
+		if err != nil {
+			return nil, errors.New("error response")
+		}
+
+		resp := &types.GetMetadataResponse{
+			Data: &types.SecretMetadata{
+				Keys: &[]string{},
+			},
+		}
+
+		for key := range fakeSecretStorage {
+			if path == "" && key != "nil-secret" && key != "empty-secret" {
+				*resp.Data.Keys = append(*resp.Data.Keys, key)
+				continue
+			}
+			posStart := strings.Index(key, path)
+			if posStart == 0 {
+				if len(path) == len(key) {
+					*resp.Data.Keys = append(*resp.Data.Keys, key)
+				} else if len(path) < len(key) && key[len(path)] == '/' {
+					key = key[len(path)+1:]
+					before, _, ok := strings.Cut(key, "/")
+					if ok {
+						*resp.Data.Keys = append(*resp.Data.Keys, before+"/")
+					} else {
+						*resp.Data.Keys = append(*resp.Data.Keys, key)
+					}
+				}
+			}
+		}
+
+		return resp, nil
 	}
-	return nil, fmt.Errorf("%s", string(secretDataByte))
 }
 
-func (client FakeOkmsClient) DeleteSecretV2(_ context.Context, _ uuid.UUID, _ string) error {
+func (f FakeOkmsClient) WithCustomHeader(key, value string) *okms.Client {
 	return nil
 }

+ 80 - 0
providers/v1/ovh/fake/fake_resolver.go

@@ -0,0 +1,80 @@
+/*
+Copyright © 2025 ESO Maintainer Team
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package fake
+
+import (
+	"context"
+	"crypto/rand"
+	"crypto/rsa"
+	"crypto/x509"
+	"encoding/pem"
+	"sync"
+
+	esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
+	kclient "sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+type FakeResolver struct {
+	Once    sync.Once
+	keyPEM  string
+	certPEM string
+}
+
+type FakeSecretKeyResolver struct {
+	fakeResolver FakeResolver
+}
+
+func (fr *FakeSecretKeyResolver) Resolve(_ context.Context, _ kclient.Client, _, _ string, ref *esmeta.SecretKeySelector) (string, error) {
+	if ref.Name == "Valid token auth" {
+		return "Valid", nil
+	}
+	if ref.Name == "Valid mtls client certificate" || ref.Name == "Valid mtls client key" {
+		var err error
+		fr.fakeResolver.Once.Do(func() {
+			var privKey *rsa.PrivateKey
+			privKey, err = rsa.GenerateKey(rand.Reader, 2048)
+			if err != nil {
+				return
+			}
+			fr.fakeResolver.keyPEM = string(pem.EncodeToMemory(&pem.Block{
+				Type:  "RSA PRIVATE KEY",
+				Bytes: x509.MarshalPKCS1PrivateKey(privKey),
+			}))
+
+			template := x509.Certificate{}
+			var cert []byte
+			cert, err = x509.CreateCertificate(rand.Reader, &template, &template, &privKey.PublicKey, privKey)
+			if err != nil {
+				return
+			}
+			fr.fakeResolver.certPEM = string(pem.EncodeToMemory(&pem.Block{
+				Type:  "CERTIFICATE",
+				Bytes: cert,
+			}))
+		})
+
+		if err != nil {
+			return "", err
+		}
+
+		if ref.Name == "Valid mtls client certificate" {
+			return fr.fakeResolver.certPEM, nil
+		}
+		return fr.fakeResolver.keyPEM, nil
+	}
+	return "", nil
+}

+ 21 - 7
providers/v1/ovh/provider.go

@@ -33,13 +33,13 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
 
 	esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
-	esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
+	v1 "github.com/external-secrets/external-secrets/apis/meta/v1"
 	"github.com/external-secrets/external-secrets/runtime/esutils/resolvers"
 )
 
 // Provider implements the ESO Provider interface for OVHcloud.
 type Provider struct {
-	SecretKeyRef func(ctx context.Context, c kclient.Client, storeKind string, esNamespace string, ref *esmeta.SecretKeySelector) (string, error)
+	secretKeyResolver SecretKeyResolver
 }
 
 // OkmsClient defines an interface for interacting with the OVH OKMS service.
@@ -54,6 +54,15 @@ type OkmsClient interface {
 	GetSecretsMetadata(ctx context.Context, okmsID uuid.UUID, path string, list bool) (*types.GetMetadataResponse, error)
 }
 
+// SecretKeyResolver resolves the value of a key from a Kubernetes Secret.
+// It is defined as an interface to allow different implementations, including mocks for testing.
+type SecretKeyResolver interface {
+	Resolve(ctx context.Context, kube kclient.Client, ovhStoreKind string, ovhStoreNameSpace string, secretRef *v1.SecretKeySelector) (string, error)
+}
+
+// DefaultSecretKeyResolver is the default implementation for resolving keys from Kubernetes Secrets.
+type DefaultSecretKeyResolver struct{}
+
 type ovhClient struct {
 	ovhStoreNameSpace string
 	ovhStoreKind      string
@@ -66,6 +75,11 @@ type ovhClient struct {
 
 var _ esv1.SecretsClient = &ovhClient{}
 
+// Resolve returns the value of the referenced key from a Kubernetes Secret.
+func (r DefaultSecretKeyResolver) Resolve(ctx context.Context, kube kclient.Client, ovhStoreKind string, ovhStoreNameSpace string, secretRef *v1.SecretKeySelector) (string, error) {
+	return resolvers.SecretKeyRef(ctx, kube, ovhStoreKind, ovhStoreNameSpace, secretRef)
+}
+
 // NewClient creates a new Provider client.
 func (p *Provider) NewClient(ctx context.Context, store esv1.GenericStore, kube kclient.Client, namespace string) (esv1.SecretsClient, error) {
 	// Validate Store before creating a client from it.
@@ -104,8 +118,8 @@ func (p *Provider) NewClient(ctx context.Context, store esv1.GenericStore, kube
 	}
 
 	// Authentication configuration: token or mTLS.
-	if p.SecretKeyRef == nil {
-		p.SecretKeyRef = resolvers.SecretKeyRef
+	if p.secretKeyResolver == nil {
+		p.secretKeyResolver = DefaultSecretKeyResolver{}
 	}
 	if ovhStore.Auth.ClientToken != nil {
 		err = configureHTTPTokenClient(ctx, p, cl,
@@ -186,7 +200,7 @@ func getToken(ctx context.Context, p *Provider, cl *ovhClient, clientToken *esv1
 	}
 
 	// Retrieve the token value.
-	token, err := p.SecretKeyRef(ctx, cl.kube,
+	token, err := p.secretKeyResolver.Resolve(ctx, cl.kube,
 		cl.ovhStoreKind, cl.ovhStoreNameSpace, tokenSecretRef)
 	if err != nil {
 		return "", err
@@ -211,7 +225,7 @@ func getMTLS(ctx context.Context, p *Provider, cl *ovhClient, clientMTLS *esv1.O
 		return tls.Certificate{}, errors.New(emptyKeySecretRef)
 	}
 	// Retrieve the value of keySecretRef from the Kubernetes secret.
-	clientKey, err := p.SecretKeyRef(ctx, cl.kube,
+	clientKey, err := p.secretKeyResolver.Resolve(ctx, cl.kube,
 		cl.ovhStoreKind, cl.ovhStoreNameSpace, keyRef)
 	if err != nil {
 		return tls.Certificate{}, err
@@ -227,7 +241,7 @@ func getMTLS(ctx context.Context, p *Provider, cl *ovhClient, clientMTLS *esv1.O
 		return tls.Certificate{}, errors.New(emptyCertSecretRef)
 	}
 	// Retrieve the value of certSecretRef from the Kubernetes secret.
-	clientCert, err := p.SecretKeyRef(ctx, cl.kube,
+	clientCert, err := p.secretKeyResolver.Resolve(ctx, cl.kube,
 		cl.ovhStoreKind, cl.ovhStoreNameSpace, certRef)
 	if err != nil {
 		return tls.Certificate{}, err

+ 124 - 196
providers/v1/ovh/provider_test.go

@@ -18,11 +18,6 @@ package ovh
 
 import (
 	"context"
-	"crypto/rand"
-	"crypto/rsa"
-	"crypto/x509"
-	"encoding/pem"
-	"sync"
 	"testing"
 
 	corev1 "k8s.io/api/core/v1"
@@ -33,20 +28,14 @@ import (
 
 	esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
 	esmeta "github.com/external-secrets/external-secrets/apis/meta/v1"
+	"github.com/external-secrets/external-secrets/providers/v1/ovh/fake"
 )
 
-type EphemeralMTLS struct {
-	Once    sync.Once
-	keyPEM  string
-	certPEM string
-}
-
 var (
-	ephemeralMTLS = EphemeralMTLS{}
-	namespace     = "namespace"
-	scheme        = runtime.NewScheme()
-	_             = corev1.AddToScheme(scheme)
-	kube          = fakeBuilder.NewClientBuilder().
+	namespace = "namespace"
+	scheme    = runtime.NewScheme()
+	_         = corev1.AddToScheme(scheme)
+	kube      = fakeBuilder.NewClientBuilder().
 			WithScheme(scheme).
 			WithObjects(&corev1.Secret{
 			ObjectMeta: v1.ObjectMeta{
@@ -57,65 +46,26 @@ var (
 				"key": []byte("value"),
 			},
 		}).Build()
+	okmsId          = "11111111-1111-1111-1111-111111111111"
+	validTokenAuth  = "Valid token auth"
+	validClientCert = "Valid mtls client certificate"
+	validClientKey  = "Valid mtls client key"
+	fillingStr      = "string"
 )
 
-func (eph *EphemeralMTLS) SecretKeyRef(_ context.Context, _ kclient.Client, _, _ string, ref *esmeta.SecretKeySelector) (string, error) {
-	if ref.Name == "Valid token auth" {
-		return "Valid", nil
-	}
-	if ref.Name == "Valid mtls client certificate" || ref.Name == "Valid mtls client key" {
-		var err error
-		eph.Once.Do(func() {
-			var privKey *rsa.PrivateKey
-			privKey, err = rsa.GenerateKey(rand.Reader, 2048)
-			if err != nil {
-				return
-			}
-			eph.keyPEM = string(pem.EncodeToMemory(&pem.Block{
-				Type:  "RSA PRIVATE KEY",
-				Bytes: x509.MarshalPKCS1PrivateKey(privKey),
-			}))
-
-			template := x509.Certificate{}
-			var cert []byte
-			cert, err = x509.CreateCertificate(rand.Reader, &template, &template, &privKey.PublicKey, privKey)
-			if err != nil {
-				return
-			}
-			eph.certPEM = string(pem.EncodeToMemory(&pem.Block{
-				Type:  "CERTIFICATE",
-				Bytes: cert,
-			}))
-		})
-
-		if err != nil {
-			return "", err
-		}
-
-		if ref.Name == "Valid mtls client certificate" {
-			return eph.certPEM, nil
-		}
-		return eph.keyPEM, nil
-	}
-	return "", nil
-}
-
 func TestNewClient(t *testing.T) {
 	tests := map[string]struct {
-		should string
-		kube   kclient.Client
-		err    bool
-		store  *esv1.SecretStore
+		errshould string
+		kube      kclient.Client
+		store     *esv1.SecretStore
 	}{
 		"Nil store": {
-			should: "store is nil",
-			err:    true,
-			kube:   kube,
+			errshould: "store is nil",
+			kube:      kube,
 		},
 		"Nil provider": {
-			should: "store provider is nil",
-			err:    true,
-			kube:   kube,
+			errshould: "store provider is nil",
+			kube:      kube,
 			store: &esv1.SecretStore{
 				Spec: esv1.SecretStoreSpec{
 					Provider: nil,
@@ -123,9 +73,8 @@ func TestNewClient(t *testing.T) {
 			},
 		},
 		"Nil ovh provider": {
-			should: "ovh store provider is nil",
-			err:    true,
-			kube:   kube,
+			errshould: "ovh store provider is nil",
+			kube:      kube,
 			store: &esv1.SecretStore{
 				Spec: esv1.SecretStoreSpec{
 					Provider: &esv1.SecretStoreProvider{
@@ -135,8 +84,7 @@ func TestNewClient(t *testing.T) {
 			},
 		},
 		"Nil controller-runtime client": {
-			should: "controller-runtime client is nil",
-			err:    true,
+			errshould: "failed to create new ovh provider client: controller-runtime client is nil",
 			store: &esv1.SecretStore{
 				Spec: esv1.SecretStoreSpec{
 					Provider: &esv1.SecretStoreProvider{
@@ -144,47 +92,46 @@ func TestNewClient(t *testing.T) {
 							Auth: esv1.OvhAuth{
 								ClientToken: &esv1.OvhClientToken{
 									ClientTokenSecret: &esmeta.SecretKeySelector{
-										Name:      "Valid token auth",
+										Name:      validTokenAuth,
 										Namespace: &namespace,
-										Key:       "string",
+										Key:       fillingStr,
 									},
 								},
 							},
-							Server: "server",
-							OkmsID: "okmsID",
+							Server: fillingStr,
+							OkmsID: okmsId,
 						},
 					},
 				},
 			},
 		},
 		"Authentication method conflict": {
-			should: "only one authentication method allowed (mtls | token)",
-			err:    true,
-			kube:   kube,
+			errshould: "only one authentication method allowed (mtls | token)",
+			kube:      kube,
 			store: &esv1.SecretStore{
 				Spec: esv1.SecretStoreSpec{
 					Provider: &esv1.SecretStoreProvider{
 						Ovh: &esv1.OvhProvider{
-							Server: "string",
-							OkmsID: "11111111-1111-1111-1111-111111111111",
+							Server: fillingStr,
+							OkmsID: okmsId,
 							Auth: esv1.OvhAuth{
 								ClientMTLS: &esv1.OvhClientMTLS{
 									ClientCertificate: &esmeta.SecretKeySelector{
-										Name:      "string",
+										Name:      fillingStr,
 										Namespace: &namespace,
-										Key:       "string",
+										Key:       fillingStr,
 									},
 									ClientKey: &esmeta.SecretKeySelector{
-										Name:      "string",
+										Name:      fillingStr,
 										Namespace: &namespace,
-										Key:       "string",
+										Key:       fillingStr,
 									},
 								},
 								ClientToken: &esv1.OvhClientToken{
 									ClientTokenSecret: &esmeta.SecretKeySelector{
-										Name:      "string",
+										Name:      fillingStr,
 										Namespace: &namespace,
-										Key:       "string",
+										Key:       fillingStr,
 									},
 								},
 							},
@@ -194,15 +141,14 @@ func TestNewClient(t *testing.T) {
 			},
 		},
 		"Authentication method empty": {
-			should: "missing authentication method",
-			err:    true,
-			kube:   kube,
+			errshould: "missing authentication method",
+			kube:      kube,
 			store: &esv1.SecretStore{
 				Spec: esv1.SecretStoreSpec{
 					Provider: &esv1.SecretStoreProvider{
 						Ovh: &esv1.OvhProvider{
-							Server: "string",
-							OkmsID: "11111111-1111-1111-1111-111111111111",
+							Server: fillingStr,
+							OkmsID: okmsId,
 							Auth:   esv1.OvhAuth{},
 						},
 					},
@@ -210,21 +156,20 @@ func TestNewClient(t *testing.T) {
 			},
 		},
 		"Valid token auth": {
-			should: "",
-			err:    false,
-			kube:   kube,
+			errshould: "",
+			kube:      kube,
 			store: &esv1.SecretStore{
 				Spec: esv1.SecretStoreSpec{
 					Provider: &esv1.SecretStoreProvider{
 						Ovh: &esv1.OvhProvider{
-							Server: "string",
-							OkmsID: "11111111-1111-1111-1111-111111111111",
+							Server: fillingStr,
+							OkmsID: okmsId,
 							Auth: esv1.OvhAuth{
 								ClientToken: &esv1.OvhClientToken{
 									ClientTokenSecret: &esmeta.SecretKeySelector{
-										Name:      "Valid token auth",
+										Name:      validTokenAuth,
 										Namespace: &namespace,
-										Key:       "string",
+										Key:       fillingStr,
 									},
 								},
 							},
@@ -234,15 +179,14 @@ func TestNewClient(t *testing.T) {
 			},
 		},
 		"Empty token auth": {
-			should: "ovh store auth.token.tokenSecretRef cannot be empty",
-			err:    true,
-			kube:   kube,
+			errshould: "failed to create new ovh provider client: ovh store auth.token.tokenSecretRef cannot be empty",
+			kube:      kube,
 			store: &esv1.SecretStore{
 				Spec: esv1.SecretStoreSpec{
 					Provider: &esv1.SecretStoreProvider{
 						Ovh: &esv1.OvhProvider{
-							Server: "string",
-							OkmsID: "11111111-1111-1111-1111-111111111111",
+							Server: fillingStr,
+							OkmsID: okmsId,
 							Auth: esv1.OvhAuth{
 								ClientToken: &esv1.OvhClientToken{
 									ClientTokenSecret: &esmeta.SecretKeySelector{},
@@ -254,26 +198,25 @@ func TestNewClient(t *testing.T) {
 			},
 		},
 		"Valid mtls auth": {
-			should: "",
-			err:    false,
-			kube:   kube,
+			errshould: "",
+			kube:      kube,
 			store: &esv1.SecretStore{
 				Spec: esv1.SecretStoreSpec{
 					Provider: &esv1.SecretStoreProvider{
 						Ovh: &esv1.OvhProvider{
-							Server: "string",
-							OkmsID: "11111111-1111-1111-1111-111111111111",
+							Server: fillingStr,
+							OkmsID: okmsId,
 							Auth: esv1.OvhAuth{
 								ClientMTLS: &esv1.OvhClientMTLS{
 									ClientCertificate: &esmeta.SecretKeySelector{
-										Name:      "Valid mtls client certificate",
+										Name:      validClientCert,
 										Namespace: &namespace,
-										Key:       "string",
+										Key:       fillingStr,
 									},
 									ClientKey: &esmeta.SecretKeySelector{
-										Name:      "Valid mtls client key",
+										Name:      validClientKey,
 										Namespace: &namespace,
-										Key:       "string",
+										Key:       fillingStr,
 									},
 								},
 							},
@@ -283,21 +226,20 @@ func TestNewClient(t *testing.T) {
 			},
 		},
 		"Empty mtls client certificate": {
-			should: "missing tls certificate or key",
-			err:    true,
-			kube:   kube,
+			errshould: "missing tls certificate or key",
+			kube:      kube,
 			store: &esv1.SecretStore{
 				Spec: esv1.SecretStoreSpec{
 					Provider: &esv1.SecretStoreProvider{
 						Ovh: &esv1.OvhProvider{
-							Server: "string",
-							OkmsID: "11111111-1111-1111-1111-111111111111",
+							Server: fillingStr,
+							OkmsID: okmsId,
 							Auth: esv1.OvhAuth{
 								ClientMTLS: &esv1.OvhClientMTLS{
 									ClientKey: &esmeta.SecretKeySelector{
-										Name:      "Valid mtls client key",
+										Name:      validClientKey,
 										Namespace: &namespace,
-										Key:       "string",
+										Key:       fillingStr,
 									},
 								},
 							},
@@ -307,21 +249,20 @@ func TestNewClient(t *testing.T) {
 			},
 		},
 		"Empty mtls client key": {
-			should: "missing tls certificate or key",
-			err:    true,
-			kube:   kube,
+			errshould: "missing tls certificate or key",
+			kube:      kube,
 			store: &esv1.SecretStore{
 				Spec: esv1.SecretStoreSpec{
 					Provider: &esv1.SecretStoreProvider{
 						Ovh: &esv1.OvhProvider{
-							Server: "string",
-							OkmsID: "11111111-1111-1111-1111-111111111111",
+							Server: fillingStr,
+							OkmsID: okmsId,
 							Auth: esv1.OvhAuth{
 								ClientMTLS: &esv1.OvhClientMTLS{
 									ClientCertificate: &esmeta.SecretKeySelector{
-										Name:      "Valid mtls client certificate",
+										Name:      validClientCert,
 										Namespace: &namespace,
-										Key:       "string",
+										Key:       fillingStr,
 									},
 								},
 							},
@@ -335,17 +276,15 @@ func TestNewClient(t *testing.T) {
 	for name, testCase := range tests {
 		t.Run(name, func(t *testing.T) {
 			provider := Provider{
-				SecretKeyRef: ephemeralMTLS.SecretKeyRef,
+				secretKeyResolver: &fake.FakeSecretKeyResolver{},
 			}
 			_, err := provider.NewClient(ctx, testCase.store, testCase.kube, "namespace")
-			if testCase.err == true {
+			if testCase.errshould != "" {
 				if err == nil {
-					t.Error()
-				} else if err.Error() != testCase.should {
-					t.Error()
+					t.Errorf("\nexpected error: %s\nactual error:   <nil>\n\n", testCase.errshould)
+				} else if err.Error() != testCase.errshould {
+					t.Errorf("\nexpected error: %s\nactual error:   %v\n\n", testCase.errshould, err)
 				}
-			} else if err != nil {
-				t.Error()
 			}
 		})
 	}
@@ -354,15 +293,13 @@ func TestNewClient(t *testing.T) {
 func TestValidateStore(t *testing.T) {
 	var namespace string = "namespace"
 	tests := map[string]struct {
-		should string
-		err    bool
-		kube   kclient.Client
-		store  *esv1.SecretStore
+		errshould string
+		kube      kclient.Client
+		store     *esv1.SecretStore
 	}{
 		"Nil store": {
-			should: "store provider is nil",
-			err:    true,
-			kube:   kube,
+			errshould: "store provider is nil",
+			kube:      kube,
 			store: &esv1.SecretStore{
 				Spec: esv1.SecretStoreSpec{
 					Provider: nil,
@@ -370,9 +307,8 @@ func TestValidateStore(t *testing.T) {
 			},
 		},
 		"Nil ovh provider": {
-			should: "ovh store provider is nil",
-			err:    true,
-			kube:   kube,
+			errshould: "ovh store provider is nil",
+			kube:      kube,
 			store: &esv1.SecretStore{
 				Spec: esv1.SecretStoreSpec{
 					Provider: &esv1.SecretStoreProvider{
@@ -382,33 +318,32 @@ func TestValidateStore(t *testing.T) {
 			},
 		},
 		"Authentication method conflict": {
-			should: "only one authentication method allowed (mtls | token)",
-			err:    true,
-			kube:   kube,
+			errshould: "only one authentication method allowed (mtls | token)",
+			kube:      kube,
 			store: &esv1.SecretStore{
 				Spec: esv1.SecretStoreSpec{
 					Provider: &esv1.SecretStoreProvider{
 						Ovh: &esv1.OvhProvider{
-							Server: "string",
-							OkmsID: "11111111-1111-1111-1111-111111111111",
+							Server: fillingStr,
+							OkmsID: okmsId,
 							Auth: esv1.OvhAuth{
 								ClientMTLS: &esv1.OvhClientMTLS{
 									ClientCertificate: &esmeta.SecretKeySelector{
-										Name:      "string",
+										Name:      fillingStr,
 										Namespace: &namespace,
-										Key:       "string",
+										Key:       fillingStr,
 									},
 									ClientKey: &esmeta.SecretKeySelector{
-										Name:      "string",
+										Name:      fillingStr,
 										Namespace: &namespace,
-										Key:       "string",
+										Key:       fillingStr,
 									},
 								},
 								ClientToken: &esv1.OvhClientToken{
 									ClientTokenSecret: &esmeta.SecretKeySelector{
-										Name:      "string",
+										Name:      fillingStr,
 										Namespace: &namespace,
-										Key:       "string",
+										Key:       fillingStr,
 									},
 								},
 							},
@@ -418,21 +353,20 @@ func TestValidateStore(t *testing.T) {
 			},
 		},
 		"Valid token auth": {
-			should: "",
-			err:    false,
-			kube:   kube,
+			errshould: "",
+			kube:      kube,
 			store: &esv1.SecretStore{
 				Spec: esv1.SecretStoreSpec{
 					Provider: &esv1.SecretStoreProvider{
 						Ovh: &esv1.OvhProvider{
-							Server: "string",
-							OkmsID: "11111111-1111-1111-1111-111111111111",
+							Server: fillingStr,
+							OkmsID: okmsId,
 							Auth: esv1.OvhAuth{
 								ClientToken: &esv1.OvhClientToken{
 									ClientTokenSecret: &esmeta.SecretKeySelector{
-										Name:      "string",
+										Name:      fillingStr,
 										Namespace: &namespace,
-										Key:       "string",
+										Key:       fillingStr,
 									},
 								},
 							},
@@ -442,26 +376,25 @@ func TestValidateStore(t *testing.T) {
 			},
 		},
 		"Valid mtls auth": {
-			should: "",
-			err:    false,
-			kube:   kube,
+			errshould: "",
+			kube:      kube,
 			store: &esv1.SecretStore{
 				Spec: esv1.SecretStoreSpec{
 					Provider: &esv1.SecretStoreProvider{
 						Ovh: &esv1.OvhProvider{
-							Server: "string",
-							OkmsID: "11111111-1111-1111-1111-111111111111",
+							Server: fillingStr,
+							OkmsID: okmsId,
 							Auth: esv1.OvhAuth{
 								ClientMTLS: &esv1.OvhClientMTLS{
 									ClientCertificate: &esmeta.SecretKeySelector{
-										Name:      "string",
+										Name:      fillingStr,
 										Namespace: &namespace,
-										Key:       "string",
+										Key:       fillingStr,
 									},
 									ClientKey: &esmeta.SecretKeySelector{
-										Name:      "string",
+										Name:      fillingStr,
 										Namespace: &namespace,
-										Key:       "string",
+										Key:       fillingStr,
 									},
 								},
 							},
@@ -471,21 +404,20 @@ func TestValidateStore(t *testing.T) {
 			},
 		},
 		"Invalid mtls auth: missing client certificate": {
-			should: "missing tls certificate or key",
-			err:    true,
-			kube:   kube,
+			errshould: "missing tls certificate or key",
+			kube:      kube,
 			store: &esv1.SecretStore{
 				Spec: esv1.SecretStoreSpec{
 					Provider: &esv1.SecretStoreProvider{
 						Ovh: &esv1.OvhProvider{
-							Server: "string",
-							OkmsID: "11111111-1111-1111-1111-111111111111",
+							Server: fillingStr,
+							OkmsID: okmsId,
 							Auth: esv1.OvhAuth{
 								ClientMTLS: &esv1.OvhClientMTLS{
 									ClientKey: &esmeta.SecretKeySelector{
-										Name:      "string",
+										Name:      fillingStr,
 										Namespace: &namespace,
-										Key:       "string",
+										Key:       fillingStr,
 									},
 								},
 							},
@@ -495,21 +427,20 @@ func TestValidateStore(t *testing.T) {
 			},
 		},
 		"Invalid mtls auth: missing key certificate": {
-			should: "missing tls certificate or key",
-			err:    true,
-			kube:   kube,
+			errshould: "missing tls certificate or key",
+			kube:      kube,
 			store: &esv1.SecretStore{
 				Spec: esv1.SecretStoreSpec{
 					Provider: &esv1.SecretStoreProvider{
 						Ovh: &esv1.OvhProvider{
-							Server: "string",
-							OkmsID: "11111111-1111-1111-1111-111111111111",
+							Server: fillingStr,
+							OkmsID: okmsId,
 							Auth: esv1.OvhAuth{
 								ClientMTLS: &esv1.OvhClientMTLS{
 									ClientCertificate: &esmeta.SecretKeySelector{
-										Name:      "string",
+										Name:      fillingStr,
 										Namespace: &namespace,
-										Key:       "string",
+										Key:       fillingStr,
 									},
 								},
 							},
@@ -519,15 +450,14 @@ func TestValidateStore(t *testing.T) {
 			},
 		},
 		"Empty auth": {
-			should: "missing authentication method",
-			err:    true,
-			kube:   kube,
+			errshould: "missing authentication method",
+			kube:      kube,
 			store: &esv1.SecretStore{
 				Spec: esv1.SecretStoreSpec{
 					Provider: &esv1.SecretStoreProvider{
 						Ovh: &esv1.OvhProvider{
-							Server: "string",
-							OkmsID: "11111111-1111-1111-1111-111111111111",
+							Server: fillingStr,
+							OkmsID: okmsId,
 						},
 					},
 				},
@@ -538,14 +468,12 @@ func TestValidateStore(t *testing.T) {
 		t.Run(name, func(t *testing.T) {
 			provider := Provider{}
 			_, err := provider.ValidateStore(testCase.store)
-			if testCase.err == true {
+			if testCase.errshould != "" {
 				if err == nil {
-					t.Error()
-				} else if err.Error() != testCase.should {
-					t.Error()
+					t.Errorf("\nexpected error: %s\nactual error:   <nil>\n\n", testCase.errshould)
+				} else if err.Error() != testCase.errshould {
+					t.Errorf("\nexpected error: %s\nactual error:   %v\n\n", testCase.errshould, err)
 				}
-			} else if err != nil {
-				t.Error()
 			}
 		})
 	}