github.com/webdestroya/awsmocker@v0.2.6/README.md (about)

     1  # AWS Mocker for Go
     2  
     3  [![godoc](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](https://godoc.org/github.com/webdestroya/awsmocker)
     4  [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/webdestroya/awsmocker/blob/main/LICENSE)
     5  [![Go Report Card](https://goreportcard.com/badge/github.com/webdestroya/awsmocker)](https://goreportcard.com/report/github.com/webdestroya/awsmocker)
     6  
     7  Easily create a proxy to allow easy testing of AWS API calls.
     8  
     9  **:warning: This is considered alpha quality right now. It might not work for all of AWS's APIs.**
    10  
    11  If you find problems, please create an Issue or make a PR.
    12  
    13  ## Installation
    14  ```shell
    15  go get -u github.com/webdestroya/awsmocker
    16  ```
    17  
    18  ## Configuration
    19  The default configuration when passing `nil` will setup a few mocks for STS.
    20  ```go
    21  awsmocker.Start(t, nil)
    22  ```
    23  
    24  For advanced usage and adding other mocks, you can use the following options:
    25  
    26  ```go
    27  awsmocker.Start(t, &awsmocker.MockerOptions{
    28    // parameters
    29  })
    30  ```
    31  
    32  | Option Key | Type | Description |
    33  | ----------- | ---- | ------ |
    34  | `Mocks` | `[]*MockedEndpoint` | A list of MockedEndpoints that will be matched against all incoming requests. |
    35  | `Timeout` | `time.Duration` | If provided, then requests that run longer than this will be terminated. Generally you should not need to set this |
    36  | `MockEc2Metadata` | `bool` | Set this to `true` and mocks for common EC2 IMDS endpoints will be added. These are not exhaustive, so if you have a special need you will have to add it. |
    37  | `SkipDefaultMocks` | `bool` | Setting this to true will prevent mocks for STS being added. Note: any mocks you add will be evaluated before the default mocks, so this option is generally not necessary. |
    38  | `ReturnAwsConfig` | `bool` | For many applications, the test suite will have the ability to pass a custom `aws.Config` value. If you have the ability to do this, you can bypass setting all the HTTP_PROXY environment variables. This makes your test cleaner. Setting this to true will add the `AwsConfig` value to the returned value of the Start call. |
    39  | `DoNotProxy` | `string` | Optional list of hostname globs that will be added to the `NO_PROXY` environment variable. These hostnames will bypass the mocker. Use this if you are making actual HTTP requests elsewhere in your code that you want to allow through. |
    40  | `DoNotFailUnhandledRequests` | `bool` | By default, if the mocker receives any request that does not have a matching mock, it will fail the test. This is usually desired as it prevents requests without error checking from allowing tests to pass. If you explicitly want a request to fail, you can define that. |
    41  | `DoNotOverrideCreds` | `bool` | This will stop the test mocker from overriding the AWS environment variables with fake values. This means if you do not properly configure the mocker, you could end up making real requests to AWS. This is not recommended. |
    42  
    43  ## Defining Mocks
    44  
    45  ```go
    46  &awsmocker.MockedEndpoint{
    47    Request:  &awsmocker.MockedRequest{},
    48    Response: &awsmocker.MockedResponse{},
    49  }
    50  ```
    51  
    52  ### Mocking Requests
    53  | Key | Type | Description |
    54  | --- | ---- | ---- |
    55  | `Service`         | `string` | The AWS shortcode/subdomain for the service. (`ec2`, `ecs`, `iam`, `dynamodb`, etc) |
    56  | `Action`          | `string` | The AWS action name that is being mocked. (`DescribeSubnets`, `ListClusters`, `AssumeRole`, etc) |
    57  | `Params`          | `url.Values` | Matches against POST FORM PARAMs. This is only useful for older XML style API requests. This will not match against newer JSON requests. |
    58  | `Method`          | `string` | Uppercase string of the HTTP method to match against |
    59  | `Path`            | `string` | Matches the request path |
    60  | `PathRegex`       | `string` | Matches the request path using regex |
    61  | `IsEc2IMDS`       | `bool` | If set to true, then will match against the IPv4 and IPv6 hostname for EC2 IMDS |
    62  | `JMESPathMatches` | `map[string]any` | A map of [JMESpath](https://jmespath.org/) expressions with their expected values. This will be matched against the JSON payload. |
    63  | `Matcher`         | `func(*ReceivedRequest) bool` | A custom function that you can use to do any complex logic you want. This is run after the other matchers, so you can use them to filter down requests before they hit your matcher. |
    64  | `MaxMatchCount`   | `int` | If this is greater than zero, then this mock will stop matching after it reaches the provided number of matches. This is useful for doing waiters. |
    65  | `Hostname`        | `string` | Matches a specific hostname. This is normally not recommended unless you are mocking non-AWS services. |
    66  | `Body`            | `string` | This matches a body of a request verbatim. This is not recommend unless you want to _exactly_ match a request. |
    67  | `Strict`          | `bool` | This is only relevant if you provided `Params`. If strict mode is on, then the parameters much match entirely (and only) the provided parameter set. |
    68  
    69  ### Mocking Responses
    70  | Key | Type | Description |
    71  | --- | ---- | ---- |
    72  | `Body` | SEE BELOW | SEE BELOW |
    73  | `StatusCode` | `int` | Default 200. Allows you to override the status code for this response |
    74  | `ContentType` | `string` | Allows overriding the content type header. By default this is handled for you based on the request |
    75  | `Encoding` | `ResponseEncoding` | Allows you to force how the body will be encoded. By default, requests that use newer API style will receive JSON responses, and older request styles will get an XML document. |
    76  | `DoNotWrap` | `bool` | Prevents wrapping XML responses with ACTIONResponse>ACTIONResult. Set this to true if you are doing some custom XML |
    77  | `RootTag` | `string` | If you are doing custom XML responses, they will need a wrapping parent tag. This is where you specify the name. |
    78  | `Handler` | `func(*ReceivedRequest) *http.Response` | If you want to handle the request entirely on your own, you can provide a function that will be passed the request and you can return an HTTP Response |
    79  
    80  **Specifying Response Body:**
    81  
    82  | `Body` variable type | Description |
    83  | -------------------- | ----------- |
    84  | `string` | Default. Body will be returned as the string verbatim |
    85  | `func(*ReceivedRequest) (string)` | The function will be executed and the resulting string will be returned with 200OK and a default content type. |
    86  | `func(*ReceivedRequest) (string, int)` | Same as above, but with custom status code |
    87  | `func(*ReceivedRequest) (string, int, string)` | Same as above, but with custom content type. |
    88  | `map` or `struct` | Will be encoded into either JSON or XML depending on the request. |
    89  
    90  
    91  ## Usage
    92  
    93  ```go
    94  func TestSomethingThatCallsAws(t *testing.T) {
    95    awsmocker.Start(t, &awsmocker.MockerOptions{
    96      // List out the mocks
    97      Mocks: []*awsmocker.MockedEndpoint{
    98        // Simple construction of a response
    99        awsmocker.NewSimpleMockedEndpoint("sts", "GetCallerIdentity", sts.GetCallerIdentityOutput{
   100          Account: aws.String("123456789012"),
   101          Arn:     aws.String("arn:aws:iam::123456789012:user/fakeuser"),
   102          UserId:  aws.String("AKIAI44QH8DHBEXAMPLE"),
   103        }),
   104  
   105        // advanced construction
   106        {
   107          Request: &awsmocker.MockedRequest{
   108            // specify the service/action to respond to
   109            Service: "ecs",
   110            Action:  "DescribeServices",
   111          },
   112          // provide the response to give
   113          Response: &awsmocker.MockedResponse{
   114            Body: map[string]interface{}{
   115              "services": []map[string]interface{}{
   116                {
   117                  "serviceName": "someservice",
   118                },
   119              },
   120            },
   121          },
   122        },
   123      },
   124    })
   125  
   126    cfg, _ := config.LoadDefaultConfig(context.TODO())
   127  
   128    stsClient := sts.NewFromConfig(cfg)
   129  
   130    resp, err := stsClient.GetCallerIdentity(context.TODO(), nil)
   131    if err != nil {
   132      t.Errorf("Error STS.GetCallerIdentity: %s", err)
   133      return
   134    }
   135  
   136    if *resp.Account != "123456789012" {
   137      t.Errorf("AccountID Mismatch: %v", *resp.Account)
   138    }
   139  
   140    // ... do the rest of your test here
   141  }
   142  ```
   143  
   144  ### Dynamic Response
   145  ```go
   146  func Mock_Events_PutRule_Generic() *awsmocker.MockedEndpoint {
   147    return &awsmocker.MockedEndpoint{
   148      Request: &awsmocker.MockedRequest{
   149        Service: "events",
   150        Action:  "PutRule",
   151      },
   152      Response: &awsmocker.MockedResponse{
   153        Body: func(rr *awsmocker.ReceivedRequest) string {
   154  
   155          name, _ := jmespath.Search("Name", rr.JsonPayload)
   156  
   157          return util.Must(util.Jsonify(map[string]interface{}{
   158            "RuleArn": fmt.Sprintf("arn:aws:events:%s:%s:rule/%s", rr.Region, awsmocker.DefaultAccountId, name.(string)),
   159          }))
   160        },
   161      },
   162    }
   163  }
   164  ```
   165  
   166  ## Viewing Requests/Responses
   167  
   168  To see the request/response traffic, you can use either of the following:
   169  
   170  * Set `awsmocker.GlobalDebugMode = true` in your tests
   171  * Use the `AWSMOCKER_DEBUG=true` environment variable
   172  
   173  ## Assumptions/Limitations
   174  * The first matching mock is returned.
   175  * Service is assumed by the credential header
   176  * Action is calculated by the `Action` parameter, or the `X-amz-target` header.
   177  * 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.
   178  * 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.
   179  
   180  ## See Also
   181  * Heavily influenced by [hashicorp's servicemocks](github.com/hashicorp/aws-sdk-go-base/v2/servicemocks)