Browse Source

Merge pull request #138 from gabibeyer/sm-testcases-44

Add tweaks for secretsManager tests
Gabi Beyer 5 years ago
parent
commit
303ac560f8
1 changed files with 167 additions and 239 deletions
  1. 167 239
      pkg/provider/aws/secretsmanager/secretsmanager_test.go

+ 167 - 239
pkg/provider/aws/secretsmanager/secretsmanager_test.go

@@ -37,256 +37,184 @@ func TestConstructor(t *testing.T) {
 	assert.NotNil(t, c.client)
 }
 
+type secretsManagerTestCase struct {
+	fakeClient     *fakesm.Client
+	apiInput       *awssm.GetSecretValueInput
+	apiOutput      *awssm.GetSecretValueOutput
+	ref            *esv1alpha1.ExternalSecretDataRemoteRef
+	apiErr         error
+	expectError    string
+	expectedSecret string
+	// for testing secretmap
+	expectedData map[string]string
+}
+
+func makeValidSecretsManagerTestCase() *secretsManagerTestCase {
+	smtc := secretsManagerTestCase{
+		fakeClient:     &fakesm.Client{},
+		apiInput:       makeValidAPIInput(),
+		ref:            makeValidRef(),
+		apiOutput:      makeValidAPIOutput(),
+		apiErr:         nil,
+		expectError:    "",
+		expectedSecret: "",
+		expectedData:   map[string]string{},
+	}
+	smtc.fakeClient.WithValue(smtc.apiInput, smtc.apiOutput, smtc.apiErr)
+	return &smtc
+}
+
+func makeValidRef() *esv1alpha1.ExternalSecretDataRemoteRef {
+	return &esv1alpha1.ExternalSecretDataRemoteRef{
+		Key:     "/baz",
+		Version: "AWSCURRENT",
+	}
+}
+
+func makeValidAPIInput() *awssm.GetSecretValueInput {
+	return &awssm.GetSecretValueInput{
+		SecretId:     aws.String("/baz"),
+		VersionStage: aws.String("AWSCURRENT"),
+	}
+}
+
+func makeValidAPIOutput() *awssm.GetSecretValueOutput {
+	return &awssm.GetSecretValueOutput{
+		SecretString: aws.String(""),
+	}
+}
+
+func makeValidSecretsManagerTestCaseCustom(tweaks ...func(smtc *secretsManagerTestCase)) *secretsManagerTestCase {
+	smtc := makeValidSecretsManagerTestCase()
+	for _, fn := range tweaks {
+		fn(smtc)
+	}
+	smtc.fakeClient.WithValue(smtc.apiInput, smtc.apiOutput, smtc.apiErr)
+	return smtc
+}
+
+// This case can be shared by both GetSecret and GetSecretMap tests.
+// bad case: set apiErr.
+var setAPIErr = func(smtc *secretsManagerTestCase) {
+	smtc.apiErr = fmt.Errorf("oh no")
+	smtc.expectError = "oh no"
+}
+
 // test the sm<->aws interface
 // make sure correct values are passed and errors are handled accordingly.
-func TestGetSecret(t *testing.T) {
-	fake := &fakesm.Client{}
-	p := &SecretsManager{
-		client: fake,
+func TestSecretsManagerGetSecret(t *testing.T) {
+	// good case: default version is set
+	// key is passed in, output is sent back
+	setSecretString := func(smtc *secretsManagerTestCase) {
+		smtc.apiOutput.SecretString = aws.String("testtesttest")
+		smtc.expectedSecret = "testtesttest"
+	}
+
+	// good case: extract property
+	// Testing that the property exists in the SecretString
+	setRefPropertyExistsInKey := func(smtc *secretsManagerTestCase) {
+		smtc.ref.Property = "/shmoo"
+		smtc.apiOutput.SecretString = aws.String(`{"/shmoo": "bang"}`)
+		smtc.expectedSecret = "bang"
+	}
+
+	// bad case: missing property
+	setRefMissingProperty := func(smtc *secretsManagerTestCase) {
+		smtc.ref.Property = "INVALPROP"
+		smtc.expectError = "key INVALPROP does not exist in secret"
+	}
+
+	// bad case: extract property failure due to invalid json
+	setRefMissingPropertyInvalidJSON := func(smtc *secretsManagerTestCase) {
+		smtc.ref.Property = "INVALPROP"
+		smtc.apiOutput.SecretString = aws.String(`------`)
+		smtc.expectError = "key INVALPROP does not exist in secret"
+	}
+
+	// good case: set .SecretString to nil but set binary with value
+	setSecretBinaryNotSecretString := func(smtc *secretsManagerTestCase) {
+		smtc.apiOutput.SecretBinary = []byte("yesplease")
+		// needs to be set as nil, empty quotes ("") is considered existing
+		smtc.apiOutput.SecretString = nil
+		smtc.expectedSecret = "yesplease"
+	}
+
+	// bad case: both .SecretString and .SecretBinary are nil
+	setSecretBinaryAndSecretStringToNil := func(smtc *secretsManagerTestCase) {
+		smtc.apiOutput.SecretBinary = nil
+		smtc.apiOutput.SecretString = nil
+		smtc.expectError = "no secret string nor binary for key"
+	}
+	// good case: secretOut.SecretBinary JSON parsing
+	setNestedSecretValueJSONParsing := func(smtc *secretsManagerTestCase) {
+		smtc.apiOutput.SecretString = nil
+		smtc.apiOutput.SecretBinary = []byte(`{"foobar":{"baz":"nestedval"}}`)
+		smtc.ref.Property = "foobar.baz"
+		smtc.expectedSecret = "nestedval"
 	}
-	for i, row := range []struct {
-		apiInput       *awssm.GetSecretValueInput
-		apiOutput      *awssm.GetSecretValueOutput
-		rr             esv1alpha1.ExternalSecretDataRemoteRef
-		apiErr         error
-		expectError    string
-		expectedSecret string
-	}{
-		{
-			// good case: default version is set
-			// key is passed in, output is sent back
-			apiInput: &awssm.GetSecretValueInput{
-				SecretId:     aws.String("/baz"),
-				VersionStage: aws.String("AWSCURRENT"),
-			},
-			rr: esv1alpha1.ExternalSecretDataRemoteRef{
-				Key: "/baz",
-			},
-			apiOutput: &awssm.GetSecretValueOutput{
-				SecretString: aws.String("RRRRR"),
-			},
-			apiErr:         nil,
-			expectError:    "",
-			expectedSecret: "RRRRR",
-		},
-		{
-			// good case: extract property
-			apiInput: &awssm.GetSecretValueInput{
-				SecretId:     aws.String("/baz"),
-				VersionStage: aws.String("AWSCURRENT"),
-			},
-			rr: esv1alpha1.ExternalSecretDataRemoteRef{
-				Key:      "/baz",
-				Property: "/shmoo",
-			},
-			apiOutput: &awssm.GetSecretValueOutput{
-				SecretString: aws.String(`{"/shmoo": "bang"}`),
-			},
-			apiErr:         nil,
-			expectError:    "",
-			expectedSecret: "bang",
-		},
-		{
-			// bad case: missing property
-			apiInput: &awssm.GetSecretValueInput{
-				SecretId:     aws.String("/baz"),
-				VersionStage: aws.String("AWSCURRENT"),
-			},
-			rr: esv1alpha1.ExternalSecretDataRemoteRef{
-				Key:      "/baz",
-				Property: "INVALPROP",
-			},
-			apiOutput: &awssm.GetSecretValueOutput{
-				SecretString: aws.String(`{"/shmoo": "bang"}`),
-			},
-			apiErr:         nil,
-			expectError:    "key INVALPROP does not exist in secret",
-			expectedSecret: "",
-		},
-		{
-			// bad case: extract property failure due to invalid json
-			apiInput: &awssm.GetSecretValueInput{
-				SecretId:     aws.String("/baz"),
-				VersionStage: aws.String("AWSCURRENT"),
-			},
-			rr: esv1alpha1.ExternalSecretDataRemoteRef{
-				Key:      "/baz",
-				Property: "INVALPROP",
-			},
-			apiOutput: &awssm.GetSecretValueOutput{
-				SecretString: aws.String(`------`),
-			},
-			apiErr:         nil,
-			expectError:    "key INVALPROP does not exist in secret",
-			expectedSecret: "",
-		},
-		{
-			// case: ssm.SecretString may be nil but binary is set
-			apiInput: &awssm.GetSecretValueInput{
-				SecretId:     aws.String("/baz"),
-				VersionStage: aws.String("AWSCURRENT"),
-			},
-			rr: esv1alpha1.ExternalSecretDataRemoteRef{
-				Key: "/baz",
-			},
-			apiOutput: &awssm.GetSecretValueOutput{
-				SecretString: nil,
-				SecretBinary: []byte("yesplease"),
-			},
-			apiErr:         nil,
-			expectError:    "",
-			expectedSecret: "yesplease",
-		},
-		{
-			// case: both .SecretString and .SecretBinary is nil
-			apiInput: &awssm.GetSecretValueInput{
-				SecretId:     aws.String("/baz"),
-				VersionStage: aws.String("AWSCURRENT"),
-			},
-			rr: esv1alpha1.ExternalSecretDataRemoteRef{
-				Key: "/baz",
-			},
-			apiOutput: &awssm.GetSecretValueOutput{
-				SecretString: nil,
-				SecretBinary: nil,
-			},
-			apiErr:         nil,
-			expectError:    "no secret string nor binary for key",
-			expectedSecret: "",
-		},
-		{
-			// case: secretOut.SecretBinary JSON parsing
-			apiInput: &awssm.GetSecretValueInput{
-				SecretId:     aws.String("/baz"),
-				VersionStage: aws.String("AWSCURRENT"),
-			},
-			rr: esv1alpha1.ExternalSecretDataRemoteRef{
-				Key:      "/baz",
-				Property: "foobar.baz",
-			},
-			apiOutput: &awssm.GetSecretValueOutput{
-				SecretString: nil,
-				SecretBinary: []byte(`{"foobar":{"baz":"nestedval"}}`),
-			},
-			apiErr:         nil,
-			expectError:    "",
-			expectedSecret: "nestedval",
-		},
-		{
-			// should pass version
-			apiInput: &awssm.GetSecretValueInput{
-				SecretId:     aws.String("/foo/bar"),
-				VersionStage: aws.String("1234"),
-			},
-			rr: esv1alpha1.ExternalSecretDataRemoteRef{
-				Key:     "/foo/bar",
-				Version: "1234",
-			},
-			apiOutput: &awssm.GetSecretValueOutput{
-				SecretString: aws.String("FOOBA!"),
-			},
-			apiErr:         nil,
-			expectError:    "",
-			expectedSecret: "FOOBA!",
-		},
-		{
-			// should return err
-			apiInput: &awssm.GetSecretValueInput{
-				SecretId:     aws.String("/foo/bar"),
-				VersionStage: aws.String("AWSCURRENT"),
-			},
-			rr: esv1alpha1.ExternalSecretDataRemoteRef{
-				Key: "/foo/bar",
-			},
-			apiOutput:   &awssm.GetSecretValueOutput{},
-			apiErr:      fmt.Errorf("oh no"),
-			expectError: "oh no",
-		},
-	} {
-		fake.WithValue(row.apiInput, row.apiOutput, row.apiErr)
-		out, err := p.GetSecret(context.Background(), row.rr)
-		if !ErrorContains(err, row.expectError) {
-			t.Errorf("[%d] unexpected error: %s, expected: '%s'", i, err.Error(), row.expectError)
+
+	// good case: custom version set
+	setCustomVersion := func(smtc *secretsManagerTestCase) {
+		smtc.apiInput.VersionStage = aws.String("1234")
+		smtc.ref.Version = "1234"
+		smtc.apiOutput.SecretString = aws.String("FOOBA!")
+		smtc.expectedSecret = "FOOBA!"
+	}
+
+	successCases := []*secretsManagerTestCase{
+		makeValidSecretsManagerTestCase(),
+		makeValidSecretsManagerTestCaseCustom(setSecretString),
+		makeValidSecretsManagerTestCaseCustom(setRefPropertyExistsInKey),
+		makeValidSecretsManagerTestCaseCustom(setRefMissingProperty),
+		makeValidSecretsManagerTestCaseCustom(setRefMissingPropertyInvalidJSON),
+		makeValidSecretsManagerTestCaseCustom(setSecretBinaryNotSecretString),
+		makeValidSecretsManagerTestCaseCustom(setSecretBinaryAndSecretStringToNil),
+		makeValidSecretsManagerTestCaseCustom(setNestedSecretValueJSONParsing),
+		makeValidSecretsManagerTestCaseCustom(setCustomVersion),
+		makeValidSecretsManagerTestCaseCustom(setAPIErr),
+	}
+
+	sm := SecretsManager{}
+	for k, v := range successCases {
+		sm.client = v.fakeClient
+		out, err := sm.GetSecret(context.Background(), *v.ref)
+		if !ErrorContains(err, v.expectError) {
+			t.Errorf("[%d] unexpected error: %s, expected: '%s'", k, err.Error(), v.expectError)
 		}
-		if string(out) != row.expectedSecret {
-			t.Errorf("[%d] unexpected secret: expected %s, got %s", i, row.expectedSecret, string(out))
+		if string(out) != v.expectedSecret {
+			t.Errorf("[%d] unexpected secret: expected %s, got %s", k, v.expectedSecret, string(out))
 		}
 	}
 }
 
 func TestGetSecretMap(t *testing.T) {
-	fake := &fakesm.Client{}
-	p := &SecretsManager{
-		client: fake,
+	// good case: default version & deserialization
+	setDeserialization := func(smtc *secretsManagerTestCase) {
+		smtc.apiOutput.SecretString = aws.String(`{"foo":"bar"}`)
+		smtc.expectedData["foo"] = "bar"
 	}
-	for i, row := range []struct {
-		apiInput     *awssm.GetSecretValueInput
-		apiOutput    *awssm.GetSecretValueOutput
-		rr           esv1alpha1.ExternalSecretDataRemoteRef
-		expectedData map[string]string
-		apiErr       error
-		expectError  string
-	}{
-		{
-			// good case: default version & deserialization
-			apiInput: &awssm.GetSecretValueInput{
-				SecretId:     aws.String("/baz"),
-				VersionStage: aws.String("AWSCURRENT"),
-			},
-			apiOutput: &awssm.GetSecretValueOutput{
-				SecretString: aws.String(`{"foo":"bar"}`),
-			},
-			rr: esv1alpha1.ExternalSecretDataRemoteRef{
-				Key: "/baz",
-			},
-			expectedData: map[string]string{
-				"foo": "bar",
-			},
-			apiErr:      nil,
-			expectError: "",
-		},
-		{
-			// bad case: api error returned
-			apiInput: &awssm.GetSecretValueInput{
-				SecretId:     aws.String("/baz"),
-				VersionStage: aws.String("AWSCURRENT"),
-			},
-			apiOutput: &awssm.GetSecretValueOutput{
-				SecretString: aws.String(`{"foo":"bar"}`),
-			},
-			rr: esv1alpha1.ExternalSecretDataRemoteRef{
-				Key: "/baz",
-			},
-			expectedData: map[string]string{
-				"foo": "bar",
-			},
-			apiErr:      fmt.Errorf("some api err"),
-			expectError: "some api err",
-		},
-		{
-			// bad case: invalid json
-			apiInput: &awssm.GetSecretValueInput{
-				SecretId:     aws.String("/baz"),
-				VersionStage: aws.String("AWSCURRENT"),
-			},
-			apiOutput: &awssm.GetSecretValueOutput{
-				SecretString: aws.String(`-----------------`),
-			},
-			rr: esv1alpha1.ExternalSecretDataRemoteRef{
-				Key: "/baz",
-			},
-			expectedData: map[string]string{},
-			apiErr:       nil,
-			expectError:  "unable to unmarshal secret",
-		},
-	} {
-		fake.WithValue(row.apiInput, row.apiOutput, row.apiErr)
-		out, err := p.GetSecretMap(context.Background(), row.rr)
-		if !ErrorContains(err, row.expectError) {
-			t.Errorf("[%d] unexpected error: %s, expected: '%s'", i, err.Error(), row.expectError)
+
+	// bad case: invalid json
+	setInvalidJSON := func(smtc *secretsManagerTestCase) {
+		smtc.apiOutput.SecretString = aws.String(`-----------------`)
+		smtc.expectError = "unable to unmarshal secret"
+	}
+
+	successCases := []*secretsManagerTestCase{
+		makeValidSecretsManagerTestCaseCustom(setDeserialization),
+		makeValidSecretsManagerTestCaseCustom(setAPIErr),
+		makeValidSecretsManagerTestCaseCustom(setInvalidJSON),
+	}
+
+	sm := SecretsManager{}
+	for k, v := range successCases {
+		sm.client = v.fakeClient
+		out, err := sm.GetSecretMap(context.Background(), *v.ref)
+		if !ErrorContains(err, v.expectError) {
+			t.Errorf("[%d] unexpected error: %s, expected: '%s'", k, err.Error(), v.expectError)
 		}
-		if cmp.Equal(out, row.expectedData) {
-			t.Errorf("[%d] unexpected secret data: expected %#v, got %#v", i, row.expectedData, out)
+		if cmp.Equal(out, v.expectedData) {
+			t.Errorf("[%d] unexpected secret data: expected %#v, got %#v", k, v.expectedData, out)
 		}
 	}
 }