awsmocker

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 8, 2022 License: MIT Imports: 36 Imported by: 0

README

AWS Mocker for Go

godoc License Go Report Card

Easily create a proxy to allow easy testing of AWS API calls.

⚠ This is considered alpha quality right now. It might not work for all of AWS's APIs.

If you find problems, please create an Issue or make a PR.

Installation

go get -u github.com/webdestroya/awsmocker

Usage

func TestSomethingThatCallsAws(t *testing.T) {
	awsmocker.Start(t, &awsmocker.MockerOptions{
		// List out the mocks
		Mocks: []*awsmocker.MockedEndpoint{
			// Simple construction of a response
			awsmocker.NewSimpleMockedEndpoint("sts", "GetCallerIdentity", sts.GetCallerIdentityOutput{
				Account: aws.String("123456789012"),
				Arn:     aws.String("arn:aws:iam::123456789012:user/fakeuser"),
				UserId:  aws.String("AKIAI44QH8DHBEXAMPLE"),
			}),

			// advanced construction
			{
				Request: &awsmocker.MockedRequest{
					// specify the service/action to respond to
					Service: "ecs",
					Action:  "DescribeServices",
				},
				// provide the response to give
				Response: &awsmocker.MockedResponse{
					Body: map[string]interface{}{
						"services": []map[string]interface{}{
							{
								"serviceName": "someservice",
							},
						},
					},
				},
			},
		},
	})

	cfg, _ := config.LoadDefaultConfig(context.TODO())

	stsClient := sts.NewFromConfig(cfg)

	resp, err := stsClient.GetCallerIdentity(context.TODO(), nil)
	if err != nil {
		t.Errorf("Error STS.GetCallerIdentity: %s", err)
		return
	}

	if *resp.Account != "123456789012" {
		t.Errorf("AccountID Mismatch: %v", *resp.Account)
	}

	// ... do the rest of your test here
}

Defining Mocks

Dynamic Response
func Mock_Events_PutRule_Generic() *awsmocker.MockedEndpoint {
	return &awsmocker.MockedEndpoint{
		Request: &awsmocker.MockedRequest{
			Service: "events",
			Action:  "PutRule",
		},
		Response: &awsmocker.MockedResponse{
			Body: func(rr *awsmocker.ReceivedRequest) string {

				name, _ := jmespath.Search("Name", rr.JsonPayload)

				return util.Must(util.Jsonify(map[string]interface{}{
					"RuleArn": fmt.Sprintf("arn:aws:events:%s:%s:rule/%s", rr.Region, awsmocker.DefaultAccountId, name.(string)),
				}))
			},
		},
	}
}

Viewing Requests/Responses

To see the request/response traffic, you can use either of the following:

  • Set awsmocker.GlobalDebugMode = true in your tests
  • Use the AWSMOCKER_DEBUG=true environment variable

Assumptions/Limitations

  • The first matching mock is returned.
  • Service is assumed by the credential header
  • Action is calculated by the Action parameter, or the X-amz-target header.
  • if you provide a response object, it will be encoded to JSON or XML based on the requesting content type. If you need a response in a special format, please provide the content type and a string for the body.
  • There is very little "error handling". If something goes wrong, it just panics. This might be less than ideal, but the only usecase for this library is within a test, which would make the test fail. This is the goal.

See Also

Documentation

Index

Constants

View Source
const (
	ContentTypeXML  = "text/xml"
	ContentTypeJSON = "application/json"
	ContentTypeText = "text/plain"
)
View Source
const (
	DefaultAccountId = "555555555555"
	DefaultRegion    = "us-east-1"
)

Variables

View Source
var (
	// Will Print out all the Request/Response traffic from the proxy
	GlobalDebugMode = false

	// Whether unmatched requests should be proxied through
	// If your tests contact outside endpoints during tests
	// then this should be set to true.
	DefaultAllowPassthrough = true
)
View Source
var (
	MockStsGetCallerIdentityValid = &MockedEndpoint{
		Request: &MockedRequest{
			Service: "sts",
			Action:  "GetCallerIdentity",
		},
		Response: &MockedResponse{
			StatusCode: http.StatusOK,
			Encoding:   ResponseEncodingXML,
			Body: map[string]interface{}{
				"Account": DefaultAccountId,
				"Arn":     fmt.Sprintf("arn:aws:iam::%s:user/fakeuser", DefaultAccountId),
				"UserId":  "AKIAI44QH8DHBEXAMPLE",
			},
		},
	}
)

Functions

func CACert

func CACert() *x509.Certificate

Returns the parsed X509 Certificate

func CACertPEM

func CACertPEM() []byte

Exports the PEM Bytes of the CA Certificate (if you need to use it)

func EncodeAsJson added in v0.2.0

func EncodeAsJson(obj interface{}) string

Types

type CertStorage added in v0.2.0

type CertStorage struct {
	// contains filtered or unexported fields
}

func (*CertStorage) Fetch added in v0.2.0

func (tcs *CertStorage) Fetch(hostname string) *tls.Certificate

type IMDSMockOptions added in v0.2.0

type IMDSMockOptions struct {
	// The identity document to return
	IdentityDocument imds.InstanceIdentityDocument

	// any custom user data
	UserData string

	// if you want to override the role name that is used for EC2 creds
	RoleName string

	// Override the instance profile name
	InstanceProfileName string
}

Override the default settings when using a default IMDS mock

type MockedEndpoint

type MockedEndpoint struct {
	Request  *MockedRequest
	Response *MockedResponse
}

func Mock_IMDS_API_Token added in v0.2.0

func Mock_IMDS_API_Token() *MockedEndpoint

func Mock_IMDS_Common added in v0.2.0

func Mock_IMDS_Common(optFns ...func(*IMDSMockOptions)) []*MockedEndpoint

Provides an array of mocks that will provide a decent replication of the EC2 Instance Metadata Service

func Mock_IMDS_IAM_Credentials added in v0.2.0

func Mock_IMDS_IAM_Credentials(roleName string) *MockedEndpoint

func Mock_IMDS_IAM_Info added in v0.2.0

func Mock_IMDS_IAM_Info(profileName string) *MockedEndpoint

func Mock_IMDS_IAM_RoleList added in v0.2.0

func Mock_IMDS_IAM_RoleList(roleName string) *MockedEndpoint

func Mock_IMDS_IdentityDocument added in v0.2.0

func Mock_IMDS_IdentityDocument(optFns ...func(*imds.InstanceIdentityDocument)) *MockedEndpoint

Provide a document to be returned, or nil to use a default one

func Mock_IMDS_MetaData_KeyValue added in v0.2.0

func Mock_IMDS_MetaData_KeyValue(k, v string) *MockedEndpoint

func Mock_IMDS_UserData added in v0.2.0

func Mock_IMDS_UserData(userData string) *MockedEndpoint

func NewSimpleMockedEndpoint

func NewSimpleMockedEndpoint(service, action string, responseObj interface{}) *MockedEndpoint

type MockedRequest

type MockedRequest struct {
	// Require that fields are matched exactly
	//
	// Nonstrict (default) means that Params listed are matched against
	// the request to ensure the ones specified match
	//
	// Strict mode requires that the request contain ONLY the params listed
	// any extra parameters will cause the request to fail to match
	Strict bool

	// The hostname only. Does not include the port
	Hostname string

	// The AWS service shortcode
	Service string

	// The AWS API Action being performed
	Action string

	// Body to match against
	Body string

	// Match against specific parameters in the request.
	// This is only used for XML/Form requests (not the newer JSON ones)
	Params url.Values

	// Match a specific HTTP method
	Method string

	// Match the URL path
	Path string

	// Match the URL path, using a regex
	PathRegex *regexp.Regexp

	// Is this an instance metadata request?
	// setting this to true will match against both the IPv4 and IPv6 hostnames
	IsEc2IMDS bool

	// Write a custom matcher function that will be used to match a request.
	// this runs after checking the other fields, so you can use those as filters.
	Matcher func(*ReceivedRequest) bool

	// Stop matching this request after it has been matched X times
	//
	// 0 (default) means it will live forever
	MaxMatchCount int
	// contains filtered or unexported fields
}

Describes a request that should be matched

func (*MockedRequest) Inspect added in v0.2.0

func (m *MockedRequest) Inspect() string

Returns a string to help identify this MockedRequest

type MockedRequestHandler added in v0.2.0

type MockedRequestHandler = func(*ReceivedRequest) *http.Response

type MockedResponse

type MockedResponse struct {
	// modify the status code. default is 200
	StatusCode int

	// force the content type. default will be determined by request content type
	ContentType string

	Encoding ResponseEncoding

	// a string, struct or map that will be encoded as the response
	//
	// Also accepts a function that is of the following signatures:
	// func(*ReceivedRequest) (string) = string payload (with 200 OK, inferred content type)
	// func(*ReceivedRequest) (string, int) = string payload, <int> status code (with inferred content type)
	// func(*ReceivedRequest) (string, int, string) = string payload, <int> status code, content type
	Body interface{}

	// Do not wrap the xml response in ACTIONResponse>ACTIONResult
	DoNotWrap bool
	RootTag   string

	// If provided, then all other fields are ignored, and the user
	// is responsible for building an HTTP response themselves
	Handler MockedRequestHandler
	// contains filtered or unexported fields
}

type MockerInfo added in v0.2.0

type MockerInfo struct {
	// URL of the proxy server
	ProxyURL string

	// Aws configuration to use
	// This is only provided if you gave ReturnAwsConfig in the options
	AwsConfig *aws.Config
}

Returned when you start the server, provides you some information if needed

func Start added in v0.2.0

func Start(t TestingT, options *MockerOptions) *MockerInfo

type MockerOptions

type MockerOptions struct {
	// Add extra logging
	Verbose bool

	// if true, then env vars for various aws credentials will not be set.
	// This is dangerous, because if the proxy were to fail, then your requests may actually
	// execute on AWS with real credentials.
	//
	DoNotOverrideCreds bool

	// if this is true, then default mocks for GetCallerIdentity and role assumptions will not be provided
	SkipDefaultMocks bool

	// WARNING: Setting this to true assumes that you are able to use the config value returned
	// If you do not use the provided config and set this true, then requests will not be routed properly.
	ReturnAwsConfig bool

	// Timeout for proxied requests.
	Timeout time.Duration

	// The mocks that will be responded to
	Mocks []*MockedEndpoint

	// Comma separated list of hostname globs that should not be proxied
	// if you are doing other HTTP/HTTPS requests within your test, you should
	// add the hostnames used to this.
	DoNotProxy string

	// Add mocks for the EC2 Instance Metadata Service
	MockEc2Metadata bool
}

type ReceivedRequest added in v0.2.0

type ReceivedRequest struct {
	HttpRequest *http.Request

	Action  string
	Service string
	Region  string

	Hostname string
	Path     string

	// The expected response type based upon the request. JSON requests answered with JSON,
	// form param posts respond with XML
	AssumedResponseType string

	// This will only be populated if the request was NOT a form
	RawBody []byte

	// If the request was a JSON request, then this will be the parsed JSON
	JsonPayload interface{}
	// contains filtered or unexported fields
}

func (*ReceivedRequest) DebugDump added in v0.2.0

func (r *ReceivedRequest) DebugDump()

type ResponseEncoding

type ResponseEncoding int
const (
	// Default will try to determine encoding via the request headers
	ResponseEncodingDefault ResponseEncoding = iota
	ResponseEncodingJSON
	ResponseEncodingXML
	ResponseEncodingText
)

type TestingT added in v0.2.0

type TestingT interface {
	Setenv(key, value string)
	TempDir() string
	Cleanup(func())
	Fail()
	Errorf(format string, args ...any)
	Logf(format string, args ...any)
}

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL