|
@@ -37,216 +37,159 @@ func TestConstructor(t *testing.T) {
|
|
|
assert.NotNil(t, c.client)
|
|
assert.NotNil(t, c.client)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+type parameterstoreTestCase struct {
|
|
|
|
|
+ fakeClient *fake.Client
|
|
|
|
|
+ apiInput *ssm.GetParameterInput
|
|
|
|
|
+ apiOutput *ssm.GetParameterOutput
|
|
|
|
|
+ remoteRef *esv1alpha1.ExternalSecretDataRemoteRef
|
|
|
|
|
+ apiErr error
|
|
|
|
|
+ expectError string
|
|
|
|
|
+ expectedSecret string
|
|
|
|
|
+ expectedData map[string]string
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func makeValidParameterStoreTestCase() *parameterstoreTestCase {
|
|
|
|
|
+ return ¶meterstoreTestCase{
|
|
|
|
|
+ fakeClient: &fake.Client{},
|
|
|
|
|
+ apiInput: makeValidAPIInput(),
|
|
|
|
|
+ apiOutput: makeValidAPIOutput(),
|
|
|
|
|
+ remoteRef: makeValidRemoteRef(),
|
|
|
|
|
+ apiErr: nil,
|
|
|
|
|
+ expectError: "",
|
|
|
|
|
+ expectedSecret: "",
|
|
|
|
|
+ expectedData: make(map[string]string),
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func makeValidAPIInput() *ssm.GetParameterInput {
|
|
|
|
|
+ return &ssm.GetParameterInput{
|
|
|
|
|
+ Name: aws.String("/baz"),
|
|
|
|
|
+ WithDecryption: aws.Bool(true),
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func makeValidAPIOutput() *ssm.GetParameterOutput {
|
|
|
|
|
+ return &ssm.GetParameterOutput{
|
|
|
|
|
+ Parameter: &ssm.Parameter{
|
|
|
|
|
+ Value: aws.String("RRRRR"),
|
|
|
|
|
+ },
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func makeValidRemoteRef() *esv1alpha1.ExternalSecretDataRemoteRef {
|
|
|
|
|
+ return &esv1alpha1.ExternalSecretDataRemoteRef{
|
|
|
|
|
+ Key: "/baz",
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+func makeValidParameterStoreTestCaseCustom(tweaks ...func(pstc *parameterstoreTestCase)) *parameterstoreTestCase {
|
|
|
|
|
+ pstc := makeValidParameterStoreTestCase()
|
|
|
|
|
+ for _, fn := range tweaks {
|
|
|
|
|
+ fn(pstc)
|
|
|
|
|
+ }
|
|
|
|
|
+ pstc.fakeClient.WithValue(pstc.apiInput, pstc.apiOutput, pstc.apiErr)
|
|
|
|
|
+ return pstc
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
// test the ssm<->aws interface
|
|
// test the ssm<->aws interface
|
|
|
// make sure correct values are passed and errors are handled accordingly.
|
|
// make sure correct values are passed and errors are handled accordingly.
|
|
|
func TestGetSecret(t *testing.T) {
|
|
func TestGetSecret(t *testing.T) {
|
|
|
- f := &fake.Client{}
|
|
|
|
|
- p := &ParameterStore{
|
|
|
|
|
- client: f,
|
|
|
|
|
|
|
+ // good case: key is passed in, output is sent back
|
|
|
|
|
+ setSecretString := func(pstc *parameterstoreTestCase) {
|
|
|
|
|
+ pstc.apiOutput.Parameter.Value = aws.String("RRRRR")
|
|
|
|
|
+ pstc.expectedSecret = "RRRRR"
|
|
|
}
|
|
}
|
|
|
- for i, row := range []struct {
|
|
|
|
|
- apiInput *ssm.GetParameterInput
|
|
|
|
|
- apiOutput *ssm.GetParameterOutput
|
|
|
|
|
- rr esv1alpha1.ExternalSecretDataRemoteRef
|
|
|
|
|
- apiErr error
|
|
|
|
|
- expectError string
|
|
|
|
|
- expectedSecret string
|
|
|
|
|
- }{
|
|
|
|
|
- {
|
|
|
|
|
- // good case: key is passed in, output is sent back
|
|
|
|
|
- apiInput: &ssm.GetParameterInput{
|
|
|
|
|
- Name: aws.String("/baz"),
|
|
|
|
|
- WithDecryption: aws.Bool(true),
|
|
|
|
|
- },
|
|
|
|
|
- rr: esv1alpha1.ExternalSecretDataRemoteRef{
|
|
|
|
|
- Key: "/baz",
|
|
|
|
|
- },
|
|
|
|
|
- apiOutput: &ssm.GetParameterOutput{
|
|
|
|
|
- Parameter: &ssm.Parameter{
|
|
|
|
|
- Value: aws.String("RRRRR"),
|
|
|
|
|
- },
|
|
|
|
|
- },
|
|
|
|
|
- apiErr: nil,
|
|
|
|
|
- expectError: "",
|
|
|
|
|
- expectedSecret: "RRRRR",
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- // good case: extract property
|
|
|
|
|
- apiInput: &ssm.GetParameterInput{
|
|
|
|
|
- Name: aws.String("/baz"),
|
|
|
|
|
- WithDecryption: aws.Bool(true),
|
|
|
|
|
- },
|
|
|
|
|
- rr: esv1alpha1.ExternalSecretDataRemoteRef{
|
|
|
|
|
- Key: "/baz",
|
|
|
|
|
- Property: "/shmoo",
|
|
|
|
|
- },
|
|
|
|
|
- apiOutput: &ssm.GetParameterOutput{
|
|
|
|
|
- Parameter: &ssm.Parameter{
|
|
|
|
|
- Value: aws.String(`{"/shmoo": "bang"}`),
|
|
|
|
|
- },
|
|
|
|
|
- },
|
|
|
|
|
- apiErr: nil,
|
|
|
|
|
- expectError: "",
|
|
|
|
|
- expectedSecret: "bang",
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- // bad case: missing property
|
|
|
|
|
- apiInput: &ssm.GetParameterInput{
|
|
|
|
|
- Name: aws.String("/baz"),
|
|
|
|
|
- WithDecryption: aws.Bool(true),
|
|
|
|
|
- },
|
|
|
|
|
- rr: esv1alpha1.ExternalSecretDataRemoteRef{
|
|
|
|
|
- Key: "/baz",
|
|
|
|
|
- Property: "INVALPROP",
|
|
|
|
|
- },
|
|
|
|
|
- apiOutput: &ssm.GetParameterOutput{
|
|
|
|
|
- Parameter: &ssm.Parameter{
|
|
|
|
|
- Value: 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: &ssm.GetParameterInput{
|
|
|
|
|
- Name: aws.String("/baz"),
|
|
|
|
|
- WithDecryption: aws.Bool(true),
|
|
|
|
|
- },
|
|
|
|
|
- rr: esv1alpha1.ExternalSecretDataRemoteRef{
|
|
|
|
|
- Key: "/baz",
|
|
|
|
|
- Property: "INVALPROP",
|
|
|
|
|
- },
|
|
|
|
|
- apiOutput: &ssm.GetParameterOutput{
|
|
|
|
|
- Parameter: &ssm.Parameter{
|
|
|
|
|
- Value: aws.String(`------`),
|
|
|
|
|
- },
|
|
|
|
|
- },
|
|
|
|
|
- apiErr: nil,
|
|
|
|
|
- expectError: "key INVALPROP does not exist in secret",
|
|
|
|
|
- expectedSecret: "",
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- // case: parameter.Value may be nil but binary is set
|
|
|
|
|
- apiInput: &ssm.GetParameterInput{
|
|
|
|
|
- Name: aws.String("/baz"),
|
|
|
|
|
- WithDecryption: aws.Bool(true),
|
|
|
|
|
- },
|
|
|
|
|
- rr: esv1alpha1.ExternalSecretDataRemoteRef{
|
|
|
|
|
- Key: "/baz",
|
|
|
|
|
- },
|
|
|
|
|
- apiOutput: &ssm.GetParameterOutput{
|
|
|
|
|
- Parameter: &ssm.Parameter{
|
|
|
|
|
- Value: nil,
|
|
|
|
|
- },
|
|
|
|
|
- },
|
|
|
|
|
- apiErr: nil,
|
|
|
|
|
- expectError: "parameter value is nil for key",
|
|
|
|
|
- expectedSecret: "",
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- // should return err
|
|
|
|
|
- apiInput: &ssm.GetParameterInput{
|
|
|
|
|
- Name: aws.String("/foo/bar"),
|
|
|
|
|
- WithDecryption: aws.Bool(true),
|
|
|
|
|
- },
|
|
|
|
|
- rr: esv1alpha1.ExternalSecretDataRemoteRef{
|
|
|
|
|
- Key: "/foo/bar",
|
|
|
|
|
- },
|
|
|
|
|
- apiOutput: &ssm.GetParameterOutput{},
|
|
|
|
|
- apiErr: fmt.Errorf("oh no"),
|
|
|
|
|
- expectError: "oh no",
|
|
|
|
|
- },
|
|
|
|
|
- } {
|
|
|
|
|
- f.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: extract property
|
|
|
|
|
+ setExtractProperty := func(pstc *parameterstoreTestCase) {
|
|
|
|
|
+ pstc.apiOutput.Parameter.Value = aws.String(`{"/shmoo": "bang"}`)
|
|
|
|
|
+ pstc.expectedSecret = "bang"
|
|
|
|
|
+ pstc.remoteRef.Property = "/shmoo"
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // bad case: missing property
|
|
|
|
|
+ setMissingProperty := func(pstc *parameterstoreTestCase) {
|
|
|
|
|
+ pstc.apiOutput.Parameter.Value = aws.String(`{"/shmoo": "bang"}`)
|
|
|
|
|
+ pstc.remoteRef.Property = "INVALPROP"
|
|
|
|
|
+ pstc.expectError = "key INVALPROP does not exist in secret"
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // bad case: extract property failure due to invalid json
|
|
|
|
|
+ setPropertyFail := func(pstc *parameterstoreTestCase) {
|
|
|
|
|
+ pstc.apiOutput.Parameter.Value = aws.String(`------`)
|
|
|
|
|
+ pstc.remoteRef.Property = "INVALPROP"
|
|
|
|
|
+ pstc.expectError = "key INVALPROP does not exist in secret"
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // bad case: parameter.Value may be nil but binary is set
|
|
|
|
|
+ setParameterValueNil := func(pstc *parameterstoreTestCase) {
|
|
|
|
|
+ pstc.apiOutput.Parameter.Value = nil
|
|
|
|
|
+ pstc.expectError = "parameter value is nil for key"
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // base case: api output return error
|
|
|
|
|
+ setAPIError := func(pstc *parameterstoreTestCase) {
|
|
|
|
|
+ pstc.apiOutput = &ssm.GetParameterOutput{}
|
|
|
|
|
+ pstc.apiErr = fmt.Errorf("oh no")
|
|
|
|
|
+ pstc.expectError = "oh no"
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ successCases := []*parameterstoreTestCase{
|
|
|
|
|
+ makeValidParameterStoreTestCaseCustom(setSecretString),
|
|
|
|
|
+ makeValidParameterStoreTestCaseCustom(setExtractProperty),
|
|
|
|
|
+ makeValidParameterStoreTestCaseCustom(setMissingProperty),
|
|
|
|
|
+ makeValidParameterStoreTestCaseCustom(setPropertyFail),
|
|
|
|
|
+ makeValidParameterStoreTestCaseCustom(setParameterValueNil),
|
|
|
|
|
+ makeValidParameterStoreTestCaseCustom(setAPIError),
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ps := ParameterStore{}
|
|
|
|
|
+ for k, v := range successCases {
|
|
|
|
|
+ ps.client = v.fakeClient
|
|
|
|
|
+ out, err := ps.GetSecret(context.Background(), *v.remoteRef)
|
|
|
|
|
+ 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 cmp.Equal(out, v.expectedSecret) {
|
|
|
|
|
+ t.Errorf("[%d] unexpected secret data: expected %#v, got %#v", k, v.expectedSecret, out)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func TestGetSecretMap(t *testing.T) {
|
|
func TestGetSecretMap(t *testing.T) {
|
|
|
- f := &fake.Client{}
|
|
|
|
|
- p := &ParameterStore{
|
|
|
|
|
- client: f,
|
|
|
|
|
|
|
+ // good case: default version & deserialization
|
|
|
|
|
+ setDeserialization := func(pstc *parameterstoreTestCase) {
|
|
|
|
|
+ pstc.apiOutput.Parameter.Value = aws.String(`{"foo":"bar"}`)
|
|
|
|
|
+ pstc.expectedData["foo"] = "bar"
|
|
|
}
|
|
}
|
|
|
- for i, row := range []struct {
|
|
|
|
|
- apiInput *ssm.GetParameterInput
|
|
|
|
|
- apiOutput *ssm.GetParameterOutput
|
|
|
|
|
- rr esv1alpha1.ExternalSecretDataRemoteRef
|
|
|
|
|
- expectedData map[string]string
|
|
|
|
|
- apiErr error
|
|
|
|
|
- expectError string
|
|
|
|
|
- }{
|
|
|
|
|
- {
|
|
|
|
|
- // good case: default version & deserialization
|
|
|
|
|
- apiInput: &ssm.GetParameterInput{
|
|
|
|
|
- Name: aws.String("/baz"),
|
|
|
|
|
- WithDecryption: aws.Bool(true),
|
|
|
|
|
- },
|
|
|
|
|
- apiOutput: &ssm.GetParameterOutput{
|
|
|
|
|
- Parameter: &ssm.Parameter{
|
|
|
|
|
- Value: aws.String(`{"foo":"bar"}`),
|
|
|
|
|
- },
|
|
|
|
|
- },
|
|
|
|
|
- rr: esv1alpha1.ExternalSecretDataRemoteRef{
|
|
|
|
|
- Key: "/baz",
|
|
|
|
|
- },
|
|
|
|
|
- expectedData: map[string]string{
|
|
|
|
|
- "foo": "bar",
|
|
|
|
|
- },
|
|
|
|
|
- apiErr: nil,
|
|
|
|
|
- expectError: "",
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- // bad case: api error returned
|
|
|
|
|
- apiInput: &ssm.GetParameterInput{
|
|
|
|
|
- Name: aws.String("/baz"),
|
|
|
|
|
- WithDecryption: aws.Bool(true),
|
|
|
|
|
- },
|
|
|
|
|
- apiOutput: &ssm.GetParameterOutput{
|
|
|
|
|
- Parameter: &ssm.Parameter{},
|
|
|
|
|
- },
|
|
|
|
|
- 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: &ssm.GetParameterInput{
|
|
|
|
|
- Name: aws.String("/baz"),
|
|
|
|
|
- WithDecryption: aws.Bool(true),
|
|
|
|
|
- },
|
|
|
|
|
- apiOutput: &ssm.GetParameterOutput{
|
|
|
|
|
- Parameter: &ssm.Parameter{
|
|
|
|
|
- Value: aws.String(`-----------------`),
|
|
|
|
|
- },
|
|
|
|
|
- },
|
|
|
|
|
- rr: esv1alpha1.ExternalSecretDataRemoteRef{
|
|
|
|
|
- Key: "/baz",
|
|
|
|
|
- },
|
|
|
|
|
- expectedData: map[string]string{},
|
|
|
|
|
- apiErr: nil,
|
|
|
|
|
- expectError: "unable to unmarshal secret",
|
|
|
|
|
- },
|
|
|
|
|
- } {
|
|
|
|
|
- f.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: api error returned
|
|
|
|
|
+ setAPIError := func(pstc *parameterstoreTestCase) {
|
|
|
|
|
+ pstc.apiOutput.Parameter = &ssm.Parameter{}
|
|
|
|
|
+ pstc.expectError = "some api err"
|
|
|
|
|
+ pstc.apiErr = fmt.Errorf("some api err")
|
|
|
|
|
+ }
|
|
|
|
|
+ // bad case: invalid json
|
|
|
|
|
+ setInvalidJSON := func(pstc *parameterstoreTestCase) {
|
|
|
|
|
+ pstc.apiOutput.Parameter.Value = aws.String(`-----------------`)
|
|
|
|
|
+ pstc.expectError = "unable to unmarshal secret"
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ successCases := []*parameterstoreTestCase{
|
|
|
|
|
+ makeValidParameterStoreTestCaseCustom(setDeserialization),
|
|
|
|
|
+ makeValidParameterStoreTestCaseCustom(setAPIError),
|
|
|
|
|
+ makeValidParameterStoreTestCaseCustom(setInvalidJSON),
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ps := ParameterStore{}
|
|
|
|
|
+ for k, v := range successCases {
|
|
|
|
|
+ ps.client = v.fakeClient
|
|
|
|
|
+ out, err := ps.GetSecretMap(context.Background(), *v.remoteRef)
|
|
|
|
|
+ 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)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|