11## AWS CloudFormation Java Plugin Test Framework
22
3- This provides an easier foundation for testing handlers for CRUD along with integated support for KMS. Developers
4- can easily write sequence of CRUD lifecycle test with expectations and will be tested. There is also a mock based
3+ This provides an easier foundation for testing handlers for CRUD along with integated support for KMS. Developers
4+ can easily write sequence of CRUD lifecycle test with expectations and will be tested. There is also a mock based
55test based for local unit testing.
66
7- The framework leverages support for [ Named Profiles] ( https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html ) that allows
8- developers to test using roles and credentials, to test the exact way in which they expect to work inside CFN for their handlers. Here is the
9- sample for now this can be used for injecting credentials using the role based profile specified.
7+ The framework leverages support for [ Named Profiles] ( https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html ) that allows
8+ developers to test using roles and credentials, to test the exact way in which they expect to work inside CloudFormation for their handlers. Here is the
9+ sample for now this can be used for injecting credentials using the role based profile specified.
1010
1111** Sample AWS Named Profile Setup**
1212
13+ ```
1314 ~/.aws/credentials
1415 ...
15- ** cfn-assume-role**
16+ [ cfn-assume-role]
1617 aws_access_key_id=[YOUR_ACCESS_KEY_ID]
1718 aws_secret_access_key=[YOUR_SECRET_ACCESS_KEY]
1819 ...
19-
20+
2021 ~/.aws/config
21- [ profilei ** cfn-integration** ]
22+ [profilei cfn-integration]
2223 role_arn = arn:aws:iam::<AWS_ACCOUNT_ID>:role/<ROLE_NAME>
23- source_profile = * cfn-assume-role*
24+ source_profile = cfn-assume-role
25+ ```
2426
2527** Using the named profile for testing**
2628
@@ -30,7 +32,6 @@ sample for now this can be used for injecting credentials using the role based p
3032 <li><u>Create a Managed Policy for the user</u>
3133 Here the credentials section has an user credentials that is provided with only sts:assumeRole
3234 permission. Here is the policy that is associated with cfn-assume-role user in the account.
33-
3435 <pre>
3536 {
3637 "Version": "2012-10-17",
@@ -48,9 +49,9 @@ sample for now this can be used for injecting credentials using the role based p
4849 <li><u>Create a Managed Policy for the services you are testing with</u>
4950 This is needed to test all integration for CRUD+L needed for logs. You can always narrow it down further.
5051 Recommended approach is to define the above policies as customer managed policies in IAM in the account and
51- associate with the role and users as appropriate. This is an example policy to test CloudWatch LogGroup
52- and KMS integration
53-
52+ associate with the role and users as appropriate. This is an example policy to test, replace
53+ [INSERT_YOUR_SERVICE] with the service you are integrating with and need KMS integration. E.g.
54+ use _logs_ as the service name for integrating with CloudWatch Logs service.
5455 <pre>
5556 {
5657 "Version": "2012-10-17",
@@ -68,44 +69,41 @@ sample for now this can be used for injecting credentials using the role based p
6869 }
6970 </pre>
7071 </li>
71- <li><u>Create a user cfn-assume-role with Managed Policy create in (1)</u>
72+ <li><u>Create a user cfn-assume-role with Managed Policy create in Step (1)</u>
7273 Download the access_key, secret_key for this user and add it to the credentials file under
7374 cfn-assume-role
7475 </li>
75- <li><u>Create cfn-integration role with the con </u></li>
76+ <li><u>Create cfn-integration role with the reference to the managed policy we created above. </u></li>
7677 <li><u>Update your poml.xml</u>
7778 Here is how to use this for unit testing. First add the dependency to you maven <u>pom.xml</u>
78-
79- <pre>{@code
80- <!-- for sts support to assume role setup above -->
81- <dependency>
82- <groupId>software.amazon.awssdk</groupId>
83- <artifactId>sts</artifactId>
84- <version>2.10.91</version>
85- <scope>test</scope>
86- </dependency>
87-
88- <!-- for kms key handling support -->
89- <dependency>
90- <groupId>software.amazon.awssdk</groupId>
91- <artifactId>kms</artifactId>
92- <version>2.10.91</version>
93- </dependency>
94-
95- <dependency>
96- <groupId>software.amazon.cloudformation.test</groupId>
97- <artifactId>cloudformation-cli-java-plugin-testing-support</artifactId>
98- <version>1.0-SNAPSHOT</version>
99- <scope>test</scope>
100- </dependency>
101- }</pre>
79+ <pre><code>
80+ <!-- for sts support to assume role setup above -->
81+ <dependency>
82+ <groupId>software.amazon.awssdk</groupId>
83+ <artifactId>sts</artifactId>
84+ <version>2.10.91</version>
85+ <scope>test</scope>
86+ </dependency>
87+ <!-- for kms key handling support -->
88+ <dependency>
89+ <groupId>software.amazon.awssdk</groupId>
90+ <artifactId>kms</artifactId>
91+ <version>2.10.91</version>
92+ </dependency>
93+ <dependency>
94+ <groupId>software.amazon.cloudformation.test</groupId>
95+ <artifactId>cloudformation-cli-java-plugin-testing-support</artifactId>
96+ <version>1.0.0</version>
97+ <scope>test</scope>
98+ </dependency>
99+ </code></pre>
102100 </li>
103101</ol >
104102
105103<b >How to use it?</b >
106104<p >
107105Sample code illustrating how to use this setup with KMS. To make scheduling the key for delete in case of abort to
108- testing the key is aliased using the alias name [ KEY_ALIAS] ( src/software/amazon/cloudformation/test/KMSKeyEnabledServiceIntegrationTestBase.java )
106+ testing the key is aliased using the alias name [ KEY_ALIAS] ( src/main/ software/amazon/cloudformation/test/KMSKeyEnabledServiceIntegrationTestBase.java )
109107The test when it runs to completion will automatically move the KMS key for delete. If test is rerun
110108the KMS key will be made active again for the duration of he test run and disable and scheduled to be deleted.
111109Regardless of how many times we run these tests there is only one key with the alias managed in the account.
@@ -114,8 +112,8 @@ To ensure that this test does not run for build environments like Travis etc. we
114112{@link org.junit.jupiter.api.condition.EnabledIfSystemProperty}. To run the test with maven we would
115113use
116114
117- ```
118- mvn -Ddesktop=true test
115+ ``` sh
116+ mvn -Ddesktop=true test
119117```
120118
121119to run the test code shown below
@@ -156,8 +154,8 @@ to run the test code shown below
156154 String kmsKeyArn = getKmsKeyArn();
157155 // Add your service to use KMS key
158156 addServiceAccess(" logs" , kmsKeyId);
159- model. setKMSKey (kmsKeyArn);
160- ProgressEvent & lt; ResourceModel , CallbackContext & gt; event = new UpdateHandler ()
157+ model. setKMSKeyArn (kmsKeyArn);
158+ ProgressEvent< ResourceModel , CallbackContext > event = new UpdateHandler ()
161159 .handleRequest(getProxy(), createRequest(model, current), null , getLoggerProxy());
162160 assertThat(event. isSuccess()). isTrue();
163161 model = event. getResourceModel();
@@ -167,10 +165,101 @@ to run the test code shown below
167165 }
168166```
169167
168+ ** Example Lifecycle Testing with KMS Support**
169+
170+ ``` java
171+ @ExtendWith (InjectProfileCredentials . class)
172+ @EnabledIfSystemProperty (named = " desktop" , matches = " true" )
173+ @TestInstance (TestInstance . Lifecycle . PER_CLASS )
174+ public class CRUDLifecycleTest extends CRUDLifecycleTestBase<ResourceModel , CallbackContext > {
175+
176+ private final ReadHandler readHandler = new ReadHandler ();
177+ private final DeleteHandler deleteHandler = new DeleteHandler ();
178+ private final UpdateHandler updateHandler = new UpdateHandler ();
179+ private final CreateHandler createHandler = new CreateHandler ();
180+ private final Map<Action , HandlerInvoke<ResourceModel , CallbackContext > > handlers =
181+ ImmutableMap . < Action , HandlerInvoke<ResourceModel , CallbackContext > > builder()
182+ .put(Action . CREATE , createHandler:: handleRequest)
183+ .put(Action . READ , readHandler:: handleRequest)
184+ .put(Action . UPDATE , updateHandler:: handleRequest)
185+ .put(Action . DELETE , deleteHandler:: handleRequest)
186+ .build();
187+
188+ private final String logGroupName = " logGroup-TEST-DELETE-" + UUID . randomUUID(). toString();
189+
190+ static final Delay override = Constant . of(). delay(Duration . ofSeconds(1 ))
191+ .timeout(Duration . ofSeconds(10 )). build();
192+ public CRUDLifecycleTest (@InjectSessionCredentials (profile = " cfn-integ" ) AwsSessionCredentials sessionCredentials ) {
193+ super (sessionCredentials, ((apiCall, provided) - > override));
194+ }
195+
196+ @Override
197+ protected List<ResourceModels > testSeed () {
198+ final String kmsKeyId = getKmsKeyId();
199+ final String kmsKeyArn = getKmsKeyArn();
200+ List<ResourceModels > testGroups = new ArrayList<> (1 );
201+
202+ testGroups. add(
203+ newStepBuilder()
204+ .group(" simple_normal" )
205+ .create(ResourceModel . builder(). logGroupName(logGroupName). build())
206+ .update(ResourceModel . builder(). logGroupName(logGroupName). retentionInDays(7 ). build())
207+ .delete(ResourceModel . builder(). logGroupName(logGroupName). build()));
208+
209+ testGroups. add(
210+ newStepBuilder()
211+ .group(" complex_with_failed_kms" )
212+ .create(ResourceModel . builder(). logGroupName(logGroupName). build())
213+ .createFail(ResourceModel . builder(). logGroupName(logGroupName). build())
214+ .updateFail(ResourceModel . builder(). logGroupName(logGroupName). retentionInDays(10 ). build())
215+ .update(ResourceModel . builder(). logGroupName(logGroupName). retentionInDays(7 ). build())
216+ .updateFail(
217+ ResourceModel . builder(). logGroupName(logGroupName). retentionInDays(7 )
218+ .kMSKey(" kmsKeyDoesNotExist" ). build())
219+ //
220+ // can not access logs service
221+ //
222+ .updateFail(() - > {
223+ removeServiceAccess(" logs" , kmsKeyId, Region . US_EAST_2 );
224+ return ResourceModel . builder(). logGroupName(logGroupName). retentionInDays(7 )
225+ .kMSKey(kmsKeyArn). build();
226+ })
227+ .update(() - > {
228+ addServiceAccess(" logs" , kmsKeyId, Region . US_EAST_2 );
229+ return ResourceModel . builder(). logGroupName(logGroupName). retentionInDays(7 )
230+ .kMSKey(kmsKeyArn). build();
231+ })
232+ .delete(ResourceModel . builder(). logGroupName(logGroupName). build()));
233+ return testGroups;
234+ }
235+
236+ @Override
237+ protected Map<Action , HandlerInvoke<ResourceModel , CallbackContext > > handlers () {
238+ return handlers;
239+ }
240+
241+ @Override
242+ protected CallbackContext context () {
243+ return new CallbackContext ();
244+ }
245+ }
246+
247+ ```
248+
170249** See Also**
171250
172- software.amazon.cloudformation.test.KMSKeyEnabledServiceIntegrationTestBase
173- software.amazon.cloudformation.test.AbstractLifecycleTestBase
251+ * Lifecycle Testing*
252+
253+ These classes use the annotation and named profiles described above to make testing against live AWS services easy.
254+
255+ [ software.amazon.cloudformation.test.KMSKeyEnabledServiceIntegrationTestBase] ( src/main/software/amazon/cloudformation/test/KMSKeyEnabledServiceIntegrationTestBase.java )
256+ [ software.amazon.cloudformation.test.AbstractLifecycleTestBase] ( src/main/software/amazon/cloudformation/test/AbstractLifecycleTestBase.java )
257+
258+ * Local Unit Testing*
259+
260+ This class provides the step plumbing
261+
262+ [ software.amazon.cloudformation.test.AbstractMockTestBase] ( src/main/software/amazon/cloudformation/test/AbstractMockTestBase.java )
174263
175264
176265## License
0 commit comments