More unit testing and addins of mocks from awsutil
This commit is contained in:
5 files changed
+495
-33
No files matched your search
@@ -3,17 +3,17 @@ module github.com/hashicorp/boundary-plugin-host-aws
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/aws/aws-sdk-go v1.40.44
|
||||
github.com/fatih/color v1.12.0 // indirect
|
||||
github.com/aws/aws-sdk-go v1.40.55
|
||||
github.com/fatih/color v1.13.0 // indirect
|
||||
github.com/google/go-cmp v0.5.6 // indirect
|
||||
github.com/hashicorp/boundary/sdk v0.0.11-0.20210926154843-a834a147850b
|
||||
github.com/hashicorp/go-secure-stdlib/awsutil v0.1.4
|
||||
github.com/hashicorp/go-secure-stdlib/awsutil v0.1.6-0.20211004211126-d07ba63494a2
|
||||
github.com/hashicorp/terraform-json v0.12.0
|
||||
github.com/mattn/go-isatty v0.0.13 // indirect
|
||||
github.com/mattn/go-colorable v0.1.11 // indirect
|
||||
github.com/rogpeppe/go-internal v1.6.2 // indirect
|
||||
github.com/stretchr/testify v1.7.0
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d // indirect
|
||||
golang.org/x/sys v0.0.0-20210917161153-d61c044b1678 // indirect
|
||||
golang.org/x/sys v0.0.0-20211004093028-2c5d950f24ef // indirect
|
||||
google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83 // indirect
|
||||
google.golang.org/protobuf v1.27.1
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
|
||||
@@ -65,8 +65,8 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj
|
||||
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/aws/aws-sdk-go v1.25.37/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go v1.30.27/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
|
||||
github.com/aws/aws-sdk-go v1.40.44 h1:kECaYybTWYZY5IKHvQMxbE6Wi5Qrb+7hbkV7zQV3Sg8=
|
||||
github.com/aws/aws-sdk-go v1.40.44/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q=
|
||||
github.com/aws/aws-sdk-go v1.40.55 h1:l5xNBmafEAfdJIIe32QbTLG3j/JscH8fzZqYyMlntuI=
|
||||
github.com/aws/aws-sdk-go v1.40.55/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q=
|
||||
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
@@ -115,8 +115,8 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc=
|
||||
github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||
github.com/frankban/quicktest v1.10.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
@@ -224,8 +224,8 @@ github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER
|
||||
github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
|
||||
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
|
||||
github.com/hashicorp/go-secure-stdlib/awsutil v0.1.2/go.mod h1:QRJZ7siKie+SZJB9jLbfKrs0Gd0yPWMtbneg0iU1PrY=
|
||||
github.com/hashicorp/go-secure-stdlib/awsutil v0.1.4 h1:aCPwC2WPyomaw5gk5ZZ7DPevN8d9DS3igkmq6DxGMjU=
|
||||
github.com/hashicorp/go-secure-stdlib/awsutil v0.1.4/go.mod h1:MpCPSPGLDILGb4JMm94/mMi3YysIqsXzGCzkEZjcjXg=
|
||||
github.com/hashicorp/go-secure-stdlib/awsutil v0.1.6-0.20211004211126-d07ba63494a2 h1:P5iG1hox8kzIetqnXn/VgrARsAtooV7jK0McTkIOqQI=
|
||||
github.com/hashicorp/go-secure-stdlib/awsutil v0.1.6-0.20211004211126-d07ba63494a2/go.mod h1:MpCPSPGLDILGb4JMm94/mMi3YysIqsXzGCzkEZjcjXg=
|
||||
github.com/hashicorp/go-secure-stdlib/configutil v0.1.2/go.mod h1:EN1DJMjv9y5e/uRAuP2WPibAox5KHEiq2BjZl00aNPQ=
|
||||
github.com/hashicorp/go-secure-stdlib/listenerutil v0.1.1/go.mod h1:irE9ILwhE8VooWdhHhBy0qXzOMRlHKoWoMlr31mAFCE=
|
||||
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8=
|
||||
@@ -285,14 +285,15 @@ github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LE
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs=
|
||||
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA=
|
||||
github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/cli v1.1.2/go.mod h1:6iaV0fGdElS6dPBx0EApTxHrcWvmJphyh2n8YBLPPZ4=
|
||||
@@ -519,8 +520,10 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210917161153-d61c044b1678 h1:J27LZFQBFoihqXoegpscI10HpjZ7B5WQLLKL2FZXQKw=
|
||||
golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211004093028-2c5d950f24ef h1:fPxZ3Umkct3LZ8gK9nbk+DWDJ9fstZa2grBn+lWVKPs=
|
||||
golang.org/x/sys v0.0.0-20211004093028-2c5d950f24ef/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/iam"
|
||||
"github.com/aws/aws-sdk-go/service/iam/iamiface"
|
||||
"github.com/hashicorp/go-secure-stdlib/awsutil"
|
||||
)
|
||||
|
||||
type testMockIAMState struct {
|
||||
DeleteAccessKeyCalled bool
|
||||
}
|
||||
|
||||
func (s *testMockIAMState) Reset() {
|
||||
s.DeleteAccessKeyCalled = false
|
||||
}
|
||||
|
||||
type testMockIAM struct {
|
||||
iamiface.IAMAPI
|
||||
|
||||
State *testMockIAMState
|
||||
}
|
||||
|
||||
func newTestMockIAM(state *testMockIAMState, opts ...awsutil.MockIAMOption) awsutil.IAMAPIFunc {
|
||||
return func(sess *session.Session) (iamiface.IAMAPI, error) {
|
||||
m := &testMockIAM{
|
||||
State: state,
|
||||
}
|
||||
f := awsutil.NewMockIAM(opts...)
|
||||
var err error
|
||||
|
||||
m.IAMAPI, err = f(sess)
|
||||
return m, err
|
||||
}
|
||||
}
|
||||
|
||||
func (m *testMockIAM) DeleteAccessKey(input *iam.DeleteAccessKeyInput) (*iam.DeleteAccessKeyOutput, error) {
|
||||
m.State.DeleteAccessKeyCalled = true
|
||||
return m.IAMAPI.DeleteAccessKey(input)
|
||||
}
|
||||
+24
-16
@@ -19,6 +19,9 @@ type awsCatalogPersistedState struct {
|
||||
AccessKeyId string
|
||||
SecretAccessKey string
|
||||
CredsLastRotatedTime time.Time
|
||||
|
||||
// testOpts are options that should be used for testing only
|
||||
testOpts []awsutil.Option
|
||||
}
|
||||
|
||||
func awsCatalogPersistedStateFromProto(in *pb.HostCatalogPersisted) (*awsCatalogPersistedState, error) {
|
||||
@@ -63,15 +66,15 @@ func (s *awsCatalogPersistedState) ToProto() (*pb.HostCatalogPersisted, error) {
|
||||
}
|
||||
|
||||
func (s *awsCatalogPersistedState) ValidateCreds() error {
|
||||
c, err := awsutil.NewCredentialsConfig(
|
||||
c, err := awsutil.NewCredentialsConfig(append([]awsutil.Option{
|
||||
awsutil.WithAccessKey(s.AccessKeyId),
|
||||
awsutil.WithSecretKey(s.SecretAccessKey),
|
||||
)
|
||||
}, s.testOpts...)...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error loading credentials: %w", err)
|
||||
}
|
||||
|
||||
if _, err := c.GetCallerIdentity(); err != nil {
|
||||
if _, err := c.GetCallerIdentity(s.testOpts...); err != nil {
|
||||
return fmt.Errorf("error validating credentials: %w", err)
|
||||
}
|
||||
|
||||
@@ -79,15 +82,17 @@ func (s *awsCatalogPersistedState) ValidateCreds() error {
|
||||
}
|
||||
|
||||
func (s *awsCatalogPersistedState) RotateCreds() error {
|
||||
c, err := awsutil.NewCredentialsConfig(
|
||||
c, err := awsutil.NewCredentialsConfig(append([]awsutil.Option{
|
||||
awsutil.WithAccessKey(s.AccessKeyId),
|
||||
awsutil.WithSecretKey(s.SecretAccessKey),
|
||||
)
|
||||
}, s.testOpts...)...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error loading credentials: %w", err)
|
||||
}
|
||||
|
||||
if err := c.RotateKeys(awsutil.WithValidityCheckTimeout(rotationWaitTimeout)); err != nil {
|
||||
if err := c.RotateKeys(append([]awsutil.Option{
|
||||
awsutil.WithValidityCheckTimeout(rotationWaitTimeout),
|
||||
}, s.testOpts...)...); err != nil {
|
||||
return fmt.Errorf("error rotating credentials: %w", err)
|
||||
}
|
||||
|
||||
@@ -134,22 +139,25 @@ func (s *awsCatalogPersistedState) ReplaceCreds(accessKeyId, secretAccessKey str
|
||||
// ID, secret access key, and rotation time fields are zeroed out in
|
||||
// the state just to ensure that they cannot be re-used after.
|
||||
func (s *awsCatalogPersistedState) DeleteCreds() error {
|
||||
c, err := awsutil.NewCredentialsConfig(
|
||||
c, err := awsutil.NewCredentialsConfig(append([]awsutil.Option{
|
||||
awsutil.WithAccessKey(s.AccessKeyId),
|
||||
awsutil.WithSecretKey(s.SecretAccessKey),
|
||||
)
|
||||
}, s.testOpts...)...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error loading credentials: %w", err)
|
||||
}
|
||||
|
||||
if err := c.DeleteAccessKey(s.AccessKeyId); err != nil {
|
||||
if err := c.DeleteAccessKey(s.AccessKeyId, s.testOpts...); err != nil {
|
||||
// Determine if the deletion error was due to a missing
|
||||
// resource. If it was, just pass it.
|
||||
if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == iam.ErrCodeNoSuchEntityException {
|
||||
s.AccessKeyId = ""
|
||||
s.SecretAccessKey = ""
|
||||
s.CredsLastRotatedTime = time.Time{}
|
||||
return nil
|
||||
var awsErr awserr.Error
|
||||
if errors.As(err, &awsErr) {
|
||||
if awsErr.Code() == iam.ErrCodeNoSuchEntityException {
|
||||
s.AccessKeyId = ""
|
||||
s.SecretAccessKey = ""
|
||||
s.CredsLastRotatedTime = time.Time{}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise treat it as an actual error.
|
||||
@@ -165,10 +173,10 @@ func (s *awsCatalogPersistedState) DeleteCreds() error {
|
||||
// GetSession returns a configured AWS session for the credentials in
|
||||
// the state.
|
||||
func (s *awsCatalogPersistedState) GetSession() (*session.Session, error) {
|
||||
c, err := awsutil.NewCredentialsConfig(
|
||||
c, err := awsutil.NewCredentialsConfig(append([]awsutil.Option{
|
||||
awsutil.WithAccessKey(s.AccessKeyId),
|
||||
awsutil.WithSecretKey(s.SecretAccessKey),
|
||||
)
|
||||
}, s.testOpts...)...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -1,13 +1,24 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/service/iam"
|
||||
pb "github.com/hashicorp/boundary/sdk/pbs/plugin"
|
||||
"github.com/hashicorp/go-secure-stdlib/awsutil"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const testOptionErr = "test option error"
|
||||
const testGetCallerIdentityErr = "test error for GetCallerIdentity"
|
||||
const testGetUserErr = "test error for GetUser"
|
||||
const testDeleteAccessKeyErr = "test error for DeleteAccessKey"
|
||||
|
||||
func TestAwsCatalogPersistedStateFromProto(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
@@ -108,3 +119,403 @@ func TestAwsCatalogPersistedStateFromProto(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAwsCatalogPersistedStateToProto(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
in *awsCatalogPersistedState
|
||||
expected *pb.HostCatalogPersisted
|
||||
expectedErr string // NOTE: Here for scaffolding but hard to test deep structpb err right now
|
||||
}{
|
||||
{
|
||||
name: "good with non-zero timestamp",
|
||||
in: &awsCatalogPersistedState{
|
||||
AccessKeyId: "foobar",
|
||||
SecretAccessKey: "bazqux",
|
||||
CredsLastRotatedTime: func() time.Time {
|
||||
t, err := time.Parse(time.RFC3339, "2006-01-02T15:04:05+07:00")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return t
|
||||
}(),
|
||||
},
|
||||
expected: &pb.HostCatalogPersisted{
|
||||
Secrets: mustStruct(map[string]interface{}{
|
||||
constAccessKeyId: "foobar",
|
||||
constSecretAccessKey: "bazqux",
|
||||
constCredsLastRotatedTime: "2006-01-02T15:04:05+07:00",
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "good with zero timestamp",
|
||||
in: &awsCatalogPersistedState{
|
||||
AccessKeyId: "foobar",
|
||||
SecretAccessKey: "bazqux",
|
||||
CredsLastRotatedTime: time.Time{},
|
||||
},
|
||||
expected: &pb.HostCatalogPersisted{
|
||||
Secrets: mustStruct(map[string]interface{}{
|
||||
constAccessKeyId: "foobar",
|
||||
constSecretAccessKey: "bazqux",
|
||||
constCredsLastRotatedTime: (time.Time{}).Format(time.RFC3339Nano),
|
||||
}),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
require := require.New(t)
|
||||
actual, err := tc.in.ToProto()
|
||||
if tc.expectedErr != "" {
|
||||
require.EqualError(err, tc.expectedErr)
|
||||
return
|
||||
}
|
||||
|
||||
require.NoError(err)
|
||||
require.Equal(tc.expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAwsCatalogPersistedStateValidateCreds(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
in *awsCatalogPersistedState
|
||||
expectedErr string
|
||||
}{
|
||||
{
|
||||
name: "could not load credentials",
|
||||
in: &awsCatalogPersistedState{
|
||||
testOpts: []awsutil.Option{awsutil.MockOptionErr(errors.New(testOptionErr))},
|
||||
},
|
||||
expectedErr: fmt.Sprintf("error loading credentials: error reading options in NewCredentialsConfig: %s", testOptionErr),
|
||||
},
|
||||
{
|
||||
name: "validation error",
|
||||
in: &awsCatalogPersistedState{
|
||||
testOpts: []awsutil.Option{awsutil.WithSTSAPIFunc(awsutil.NewMockSTS(awsutil.WithGetCallerIdentityError(errors.New(testGetCallerIdentityErr))))},
|
||||
},
|
||||
expectedErr: fmt.Sprintf("error validating credentials: %s", testGetCallerIdentityErr),
|
||||
},
|
||||
{
|
||||
name: "good",
|
||||
in: &awsCatalogPersistedState{
|
||||
AccessKeyId: "foobar",
|
||||
SecretAccessKey: "bazqux",
|
||||
testOpts: []awsutil.Option{awsutil.WithSTSAPIFunc(awsutil.NewMockSTS())},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
require := require.New(t)
|
||||
err := tc.in.ValidateCreds()
|
||||
if tc.expectedErr != "" {
|
||||
require.EqualError(err, tc.expectedErr)
|
||||
return
|
||||
}
|
||||
|
||||
require.NoError(err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAwsCatalogPersistedStateRotateCreds(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
in *awsCatalogPersistedState
|
||||
expectedAccessKeyId string
|
||||
expectedSecretAccessKey string
|
||||
expectedNonZeroRotatedTime bool
|
||||
expectedErr string
|
||||
}{
|
||||
{
|
||||
name: "could not load credentials",
|
||||
in: &awsCatalogPersistedState{
|
||||
testOpts: []awsutil.Option{awsutil.MockOptionErr(errors.New(testOptionErr))},
|
||||
},
|
||||
expectedErr: fmt.Sprintf("error loading credentials: error reading options in NewCredentialsConfig: %s", testOptionErr),
|
||||
},
|
||||
{
|
||||
name: "rotation error",
|
||||
in: &awsCatalogPersistedState{
|
||||
AccessKeyId: "foobar",
|
||||
SecretAccessKey: "bazqux",
|
||||
testOpts: []awsutil.Option{
|
||||
awsutil.WithIAMAPIFunc(
|
||||
awsutil.NewMockIAM(
|
||||
awsutil.WithGetUserError(errors.New(testGetUserErr)),
|
||||
),
|
||||
),
|
||||
},
|
||||
},
|
||||
expectedErr: fmt.Sprintf("error rotating credentials: error calling CreateAccessKey: error calling aws.GetUser: %s", testGetUserErr),
|
||||
},
|
||||
{
|
||||
name: "good",
|
||||
in: &awsCatalogPersistedState{
|
||||
AccessKeyId: "foobar",
|
||||
SecretAccessKey: "bazqux",
|
||||
testOpts: []awsutil.Option{
|
||||
awsutil.WithSTSAPIFunc(
|
||||
awsutil.NewMockSTS(),
|
||||
),
|
||||
awsutil.WithIAMAPIFunc(
|
||||
awsutil.NewMockIAM(
|
||||
awsutil.WithGetUserOutput(
|
||||
&iam.GetUserOutput{
|
||||
User: &iam.User{
|
||||
Arn: aws.String("arn:aws:iam::123456789012:user/JohnDoe"),
|
||||
UserId: aws.String("AIDAJQABLZS4A3QDU576Q"),
|
||||
UserName: aws.String("JohnDoe"),
|
||||
},
|
||||
},
|
||||
),
|
||||
awsutil.WithCreateAccessKeyOutput(
|
||||
&iam.CreateAccessKeyOutput{
|
||||
AccessKey: &iam.AccessKey{
|
||||
AccessKeyId: aws.String("one"),
|
||||
SecretAccessKey: aws.String("two"),
|
||||
UserName: aws.String("JohnDoe"),
|
||||
},
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
},
|
||||
expectedAccessKeyId: "one",
|
||||
expectedSecretAccessKey: "two",
|
||||
expectedNonZeroRotatedTime: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
require := require.New(t)
|
||||
err := tc.in.RotateCreds()
|
||||
if tc.expectedErr != "" {
|
||||
require.EqualError(err, tc.expectedErr)
|
||||
return
|
||||
}
|
||||
|
||||
require.NoError(err)
|
||||
require.Equal(tc.expectedAccessKeyId, tc.in.AccessKeyId)
|
||||
require.Equal(tc.expectedSecretAccessKey, tc.in.SecretAccessKey)
|
||||
require.Equal(tc.expectedNonZeroRotatedTime, !tc.in.CredsLastRotatedTime.IsZero())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAwsCatalogPersistedStateReplaceCreds(t *testing.T) {
|
||||
// NOTE: Not safe to run this test in parallel
|
||||
state := new(testMockIAMState)
|
||||
cases := []struct {
|
||||
name string
|
||||
in *awsCatalogPersistedState
|
||||
accessKeyId string
|
||||
secretAccessKey string
|
||||
expectedAccessKeyId string
|
||||
expectedSecretAccessKey string
|
||||
expectedDeleteCalled bool
|
||||
expectedErr string
|
||||
}{
|
||||
{
|
||||
name: "missing access key id",
|
||||
in: &awsCatalogPersistedState{},
|
||||
expectedErr: "access key id cannot be empty",
|
||||
},
|
||||
{
|
||||
name: "missing access key id",
|
||||
in: &awsCatalogPersistedState{},
|
||||
accessKeyId: "one",
|
||||
expectedErr: "secret access key cannot be empty",
|
||||
},
|
||||
{
|
||||
name: "identical access key id",
|
||||
in: &awsCatalogPersistedState{
|
||||
AccessKeyId: "foobar",
|
||||
SecretAccessKey: "bazqux",
|
||||
},
|
||||
accessKeyId: "foobar",
|
||||
secretAccessKey: "bazqux",
|
||||
expectedErr: "attempting to replace access key with the same one",
|
||||
},
|
||||
{
|
||||
name: "deletion error",
|
||||
in: &awsCatalogPersistedState{
|
||||
AccessKeyId: "foobar",
|
||||
SecretAccessKey: "bazqux",
|
||||
CredsLastRotatedTime: time.Now(),
|
||||
testOpts: []awsutil.Option{
|
||||
awsutil.WithIAMAPIFunc(
|
||||
awsutil.NewMockIAM(
|
||||
awsutil.WithDeleteAccessKeyError(errors.New(testDeleteAccessKeyErr)),
|
||||
),
|
||||
),
|
||||
},
|
||||
},
|
||||
accessKeyId: "one",
|
||||
secretAccessKey: "two",
|
||||
expectedErr: fmt.Sprintf("error deleting old access key: error deleting old access key: %s", testDeleteAccessKeyErr),
|
||||
},
|
||||
{
|
||||
name: "good with delete of old rotated",
|
||||
in: &awsCatalogPersistedState{
|
||||
AccessKeyId: "foobar",
|
||||
SecretAccessKey: "bazqux",
|
||||
CredsLastRotatedTime: time.Now(),
|
||||
testOpts: []awsutil.Option{
|
||||
awsutil.WithIAMAPIFunc(
|
||||
newTestMockIAM(state),
|
||||
),
|
||||
},
|
||||
},
|
||||
accessKeyId: "one",
|
||||
secretAccessKey: "two",
|
||||
expectedAccessKeyId: "one",
|
||||
expectedSecretAccessKey: "two",
|
||||
expectedDeleteCalled: true,
|
||||
},
|
||||
{
|
||||
name: "good without delete of old rotated",
|
||||
in: &awsCatalogPersistedState{
|
||||
AccessKeyId: "foobar",
|
||||
SecretAccessKey: "bazqux",
|
||||
testOpts: []awsutil.Option{
|
||||
awsutil.WithIAMAPIFunc(
|
||||
newTestMockIAM(state),
|
||||
),
|
||||
},
|
||||
},
|
||||
accessKeyId: "one",
|
||||
secretAccessKey: "two",
|
||||
expectedAccessKeyId: "one",
|
||||
expectedSecretAccessKey: "two",
|
||||
expectedDeleteCalled: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
require := require.New(t)
|
||||
state.Reset()
|
||||
err := tc.in.ReplaceCreds(tc.accessKeyId, tc.secretAccessKey)
|
||||
if tc.expectedErr != "" {
|
||||
require.EqualError(err, tc.expectedErr)
|
||||
return
|
||||
}
|
||||
|
||||
require.NoError(err)
|
||||
require.Equal(tc.expectedAccessKeyId, tc.in.AccessKeyId)
|
||||
require.Equal(tc.expectedSecretAccessKey, tc.in.SecretAccessKey)
|
||||
require.Zero(tc.in.CredsLastRotatedTime)
|
||||
require.Equal(tc.expectedDeleteCalled, state.DeleteAccessKeyCalled)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAwsCatalogPersistedStateDeleteCreds(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
in *awsCatalogPersistedState
|
||||
expectedErr string
|
||||
}{
|
||||
{
|
||||
name: "could not load credentials",
|
||||
in: &awsCatalogPersistedState{
|
||||
testOpts: []awsutil.Option{awsutil.MockOptionErr(errors.New(testOptionErr))},
|
||||
},
|
||||
expectedErr: fmt.Sprintf("error loading credentials: error reading options in NewCredentialsConfig: %s", testOptionErr),
|
||||
},
|
||||
{
|
||||
name: "deletion error",
|
||||
in: &awsCatalogPersistedState{
|
||||
AccessKeyId: "foobar",
|
||||
SecretAccessKey: "bazqux",
|
||||
testOpts: []awsutil.Option{
|
||||
awsutil.WithIAMAPIFunc(
|
||||
awsutil.NewMockIAM(
|
||||
awsutil.WithDeleteAccessKeyError(errors.New(testDeleteAccessKeyErr)),
|
||||
),
|
||||
),
|
||||
},
|
||||
},
|
||||
expectedErr: fmt.Sprintf("error deleting old access key: error deleting old access key: %s", testDeleteAccessKeyErr),
|
||||
},
|
||||
{
|
||||
name: "deletion error, but OK because key was just gone",
|
||||
in: &awsCatalogPersistedState{
|
||||
AccessKeyId: "foobar",
|
||||
SecretAccessKey: "bazqux",
|
||||
testOpts: []awsutil.Option{
|
||||
awsutil.WithIAMAPIFunc(
|
||||
awsutil.NewMockIAM(
|
||||
awsutil.WithDeleteAccessKeyError(
|
||||
awserr.New(iam.ErrCodeNoSuchEntityException, "", nil),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "good",
|
||||
in: &awsCatalogPersistedState{
|
||||
AccessKeyId: "foobar",
|
||||
SecretAccessKey: "bazqux",
|
||||
testOpts: []awsutil.Option{
|
||||
awsutil.WithIAMAPIFunc(
|
||||
awsutil.NewMockIAM(),
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
require := require.New(t)
|
||||
err := tc.in.DeleteCreds()
|
||||
if tc.expectedErr != "" {
|
||||
require.EqualError(err, tc.expectedErr)
|
||||
return
|
||||
}
|
||||
|
||||
require.NoError(err)
|
||||
require.Empty(tc.in.AccessKeyId)
|
||||
require.Empty(tc.in.SecretAccessKey)
|
||||
require.Zero(tc.in.CredsLastRotatedTime)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAwsCatalogPersistedStateGetSessionErr(t *testing.T) {
|
||||
require := require.New(t)
|
||||
state := &awsCatalogPersistedState{
|
||||
testOpts: []awsutil.Option{awsutil.MockOptionErr(errors.New(testOptionErr))},
|
||||
}
|
||||
|
||||
_, err := state.GetSession()
|
||||
require.EqualError(err, fmt.Sprintf("error reading options in NewCredentialsConfig: %s", testOptionErr))
|
||||
}
|
||||
|
||||
func TestAwsCatalogPersistedStateEC2ClientErr(t *testing.T) {
|
||||
require := require.New(t)
|
||||
state := &awsCatalogPersistedState{
|
||||
testOpts: []awsutil.Option{awsutil.MockOptionErr(errors.New(testOptionErr))},
|
||||
}
|
||||
|
||||
_, err := state.EC2Client("someregion")
|
||||
require.EqualError(err, fmt.Sprintf("error getting AWS session: error reading options in NewCredentialsConfig: %s", testOptionErr))
|
||||
}
|
||||
Reference in new issue
Block a user