Package software.amazon.cloudformation.test
Sample example of AWS CLI setup
~/.aws/credentials
...
[cfn-assume-role]
aws_access_key_id=[YOUR_ACCESS_KEY_ID]
aws_secret_access_key=[YOUR_SECRET_ACCESS_KEY]
...
~/.aws/config
[profile cfn-integration]
role_arn = arn:aws:iam::0123456789012:role/cfn-integration
source_profile = cfn-assume-role
How to setup IAM managed policies, user and role credentials for above setup
- Create a Managed Policy for the user
Here the credentials section has an user credentials that is provided with only sts:assumeRole
permission. Here is the policy that is associated with cfn-assume-role user in the account.
{ "Version": "2012-10-17", "Statement": [ { "Sid": "VisualEditor0", "Effect": "Allow", "Action": "sts:AssumeRole", "Resource": "*" } ] } - Create a Managed Policy for the services you are testing with
This is needed to test all integration for CRUD+L needed for logs. You can always narrow it down further.
Recommended approach is to define the above policies as customer managed policies in IAM in the account and
associate with the role and users as appropriate. This is an example policy to test CloudWatch LogGroup
and KMS integration
{ "Version": "2012-10-17", "Statement": [ { "Sid": "VisualEditor0", "Effect": "Allow", "Action": [ "kms:*", "[INSERT_YOUR_SERVICE]:*" ], "Resource": "*" } ] } - Create a user cfn-assume-role with Managed Policy create in (1) Download the access_key, secret_key for this user and add it to the credentials file under cfn-assume-role
- Create cfn-integration role with the reference to the managed policy we created above.
- Update your poml.xml
Here is how to use this for unit testing. First add the dependency to you maven pom.xml
<!-- for sts support to assume role setup above --> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>sts</artifactId> <version>2.10.91</version> <scope>test</scope> </dependency> <!-- for kms key handling support --> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>kms</artifactId> <version>2.10.91</version> </dependency> <dependency> <groupId>software.amazon.cloudformation.test</groupId> <artifactId>cloudformation-cli-java-plugin-testing-support</artifactId> <version>1.0-SNAPSHOT</version> <scope>test</scope> </dependency>
Sample code illustrating how to use this setup with KMS. To make scheduling the key for delete in case of abort to
testing the key is aliased using the alias name KMSKeyEnabledServiceIntegrationTestBase.KEY_ALIAS
The test when it runs to completion will automatically move the KMS key for delete. If test is rerun
the KMS key will be made active again for the duration of he test run and disable and scheduled to be deleted.
Regardless of how many times we run these tests there is only one key with the alias managed in the account.
To ensure that this test does not run for build environments we Enable is using system properties using
EnabledIfSystemProperty. To run the same shown below with maven we would
use
mvn -Ddesktop=true test
package software.amazon.logs.loggroup;
import org.junit.jupiter.api.*;
import static org.assertj.core.api.Assertions.assertThat;
import software.amazon.awssdk.auth.credentials.AwsSessionCredentials;
import software.amazon.cloudformation.proxy.*;
import software.amazon.cloudformation.test.*;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class) // we order the tests to follows C to U to D
@ExtendWith(InjectProfileCredentials.class) // extend with profile based credentials
@EnabledIfSystemProperty(named = "desktop", matches = "true")
@TestInstance(TestInstance.Lifecycle.PER_CLASS) // IMP PER_CLASS
public class LifecycleTest extends KMSKeyEnabledServiceIntegrationTestBase {
//
// At the annotation software.amazon.cloudformation.test.annotations.InjectSessionCredentials to the
// constructor. This will inject the role's credentials
//
public LifecycleTest(@InjectSessionCredentials(profile = "cfn-integration") AwsSessionCredentials awsCredentials) {
super(awsCredentials, ((apiCall, provided) -> override));
}
...
...
@Order(300)
@Test
void addValidKMS() {
final ResourceModel current = ResourceModel.builder().arn(model.getArn())
.logGroupName(model.getLogGroupName()).retentionInDays(model.getRetentionInDays()).build();
// Access a KMS key. The test ensures to only create one key and recycles despite any number of runs
String kmsKeyId = getKmsKeyId();
String kmsKeyArn = getKmsKeyArn();
// Add your service to use KMS key
addServiceAccess("logs", kmsKeyId);
model.setKMSKey(kmsKeyArn);
ProgressEvent<ResourceModel, CallbackContext> event = new UpdateHandler()
.handleRequest(getProxy(), createRequest(model, current), null, getLoggerProxy());
assertThat(event.isSuccess()).isTrue();
model = event.getResourceModel();
}
...
...
}
-
Interface Summary Interface Description HandlerInvoke<ModelT,CallbackT extends software.amazon.cloudformation.proxy.StdCallbackContext> -
Class Summary Class Description AbstractLifecycleTestBase Abstract base class that does some of the mocking and proxy setup that you need for testing each of your handlers consistently in order for CRUD + LAbstractMockTestBase<CLIENT extends software.amazon.awssdk.core.SdkClient> CRUDLifecycleTestBase<ResourceModelT,CallbackT extends software.amazon.cloudformation.proxy.StdCallbackContext> InjectProfileCredentials KMSKeyEnabledServiceIntegrationTestBase Abstract base class we can derive from that adds support for a KMS key and has helpers methods to update Key policy for accessing the key for service principal