Skip to content

HBOCodeLabs/infratest

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

64 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Infratest

Infratest is a Golang library that we hope makes testing your infrastructure using tests that are written in Golang easier to do. The general goals of the project are to enable testing across technologies such as:

  • AWS, including (but not limited to):
    • EC2
    • IAM
    • RDS
    • Route53
    • S3
    • DynamoDB
  • Databases such as:
    • Mongodb
    • PostgreSQL
    • Cassandra

The library takes the approach of enabling simple assertion-based testing; that is, asserting that some attribute of a resource is an expected value, that such an attribute even exists, or that a given system responds to a request in a way that you expect. Examples of things we might want to include are:

  • Asserting that a resource name matches a pattern or set of rules.
  • Asserting that an AWS IAM Policy contains a given combination of an Action, Resource, and Effect.
  • Asserting that one can connect to a database endpoint and perform some arbitrary action using provided credentials.

Note: While many of the resources that the library enables testing of can be managed by tools such as Terraform or Ansible, the project explicitly does not include libraries for interacting with or executing deployments with Terraform or any other Infrastructure-As-Code tools. Instead, we recommend other libraries are used to perform that function, such as the excellent Terratest framework.

Contribution Guidelines

We welcome pull requests for new features! Please review the following guidelines carefully to ensure the fastest acceptance of your code.

Package naming

In addition to following the general Effective Go guidelines for package naming (i.e. all lowercase and no punctuation) package names must also indicate the specific vendor or technology that the contained methods test. For example, all our code that tests AWS-based resources must be under the aws package.

Function Naming

All publicly consumable functions must follow the naming pattern Assert[Entity][Action statement], where [Entity] is the object the assertion is run against, and [Action statement] is a concise, descriptive name for what the assertion tests.

Examples of good function names:

  • AssertIAMPolicyContainsResourceAction
  • AssertEC2TagValue
  • AssertUserCanConnect
  • AssertS3BucketPublicAccessBlocked

Note that these names do not include specific product or company names, e.g. AssertAWSIAMPolicyContainsResourceAction, or AssertPostgreSQLUserCanConnect. This is intentional. Because we separate different technologies or vendors into discrete packages, the use of the vendor or technology name in the function name is redundant and makes the name longer.

For internal functions only, any method which returns an error object must have the letter E as the last character of its name.

Function signatures

  • Functions must have a context object ctx *context.Context as the first input.
  • Public Assert functions must have t *testing.T as the second input parameter.
  • Any function which requires a third-party client, such as an AWS SDK client or database client, must either accept this client object directly after the test object, or allow setting this via a functional option (in which case the method must ensure that a client has been set). This client object must be an interface type as discussed in the section on the use of interfaces over direct clients.

Common library usage

To keep the number of dependencies low, the following standard libraries must be used unless there is a compelling reason to use something else.

Library Name / URL Used For
github.com/stretchr/testify Asserting actual values equal some expected value.
github.com/aws/aws-sdk-go-v2 All AWS related interactions.
gopkg.in/square/go-jose.v2/json JSON manipulation, marshalling, etc
k8s.io/client-go Kubernetes interactions

Use of interfaces rather than direct types

Where we interact with outside libraries that themselves interact with external resources, we require use of a limited interface type. Referencing the third party type directly. (An example of this would be the AWS SDK.) We do this so that we can easily unit test our methods without relying on provisioning external resources.

Use of functional options rather than struct / explicit arguments

Methods should use functional options for passing of inputs other than a context, test, or possibly client objects, rather than using either explicit arguments or structs. This is to make preservation of method signatures easier over time, as well as making behavior more explicit.

Tests

All methods, especially ones that are public-facing, must have associated unit tests. These tests must not rely on the existence of external resources unless absolutely required; by using interfaces as described in the previous section this should be simple to accomplish.

Where code interacts with outside APIs that are themselves versioned, and where multiple versions are supported, integration tests against known supported versions of the vendor APIs are recommended, but not strictly required. Examples would include things like Hashicorp Vault and Kuberentes.

Contributing

Contributions are welcome! Please follow this process:

  • Fork the repository into your own user.
  • Create a new branch off of main in your repository; we do not accept contributions off of forks' main branches (it also makes merging future changes from our repository to yours more difficult).
  • Make your changes and commit them, including updates to any tests.
  • Run the testing suite on at least any of the packages that you updated or added.
  • Open a pull request back to our repository. Please reference any issue that you are fixing.