Skip to content

Commit

Permalink
added tests to project
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelwittig committed Feb 23, 2017
1 parent cfc0afb commit fdd1612
Show file tree
Hide file tree
Showing 21 changed files with 1,379 additions and 0 deletions.
3 changes: 3 additions & 0 deletions test/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
target/
.idea/
*.iml
73 changes: 73 additions & 0 deletions test/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Free Templates for AWS CloudFormation

Tests for our free Templates for AWS CloudFormation. The goal of this tests is to ensure that our templates are always working. The test are implemented in Java 8 and run in JUnit 4.

If you run this tests, many AWS CloudFormation tests are created and **charges will apply**!

[widdix GmbH](https://widdix.net) sponsors the test runs on every push and once per week to ensure that everything is working as expected.

## Prerequisits

To run this tests you need:
* A resolvable Route 53 hosted zone where record sets can be added automatically (**NOT** your production environment!)
* A domain suffix that cen be used for subdomains (e.g. `awstest.mydomain.com`)
* A wildcard ACM certificate in `us-east-1` that matches with the domain suffix from above (e.g. `*.awstest.mydomain.com`)
* A wildcard ACM certificate in the region you want to run this tests in like above

## Supported env variables

* `HOSTED_ZONE_ID` **required** A hosted zone id of your Route 53 hosted zone where the tests can create record sets
* `DOMAIN_SUFFIX` **required** A domain suffix that is part of your hosted zone
* `CLOUDFRONT_ACM_CERTIFICATE_ARN` **required** A wildcard ACM certificate in `us-east-1`
* `ACM_CERTIFICATE_ARN` **required** A wildcard ACM certificate in the region where the tests run
* `IAM_ROLE_ARN` if the tests should assume an IAM role before they run supply the ARN of the IAM role
* `TEMPLATE_DIR` Load templates from local disk (instead of S3 bucket `widdix-aws-cf-templates`). Must end with an `/`. See `BUCKET` as well.
* `BUCKET` Some templates are to big to be passed as a string from local disk, therefore you need to supply the name of the bucket that is used to upload templates.

## Usage

### AWS credentials

The AWS credentials are passed in as defined by the AWS SDK for Java: http://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/credentials.html

One addition is, that you can supply the env variable `IAM_ROLE_ARN` which let's the tests assume a role before they start with the default credentials.

### Region selection

The region selection works like defined by the AWS SDK for Java: http://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/java-dg-region-selection.html

### Run all tests

```
AWS_REGION="us-east-1" HOSTED_ZONE_ID="..." DOMAIN_SUFFIX="..." CLOUDFRONT_ACM_CERTIFICATE_ARN="..." ACM_CERTIFICATE_ARN="..." mvn test
```

### Run a single test suite

to run the `TestJenkins` tests:

```
AWS_REGION="us-east-1" HOSTED_ZONE_ID="..." DOMAIN_SUFFIX="..." CLOUDFRONT_ACM_CERTIFICATE_ARN="..." ACM_CERTIFICATE_ARN="..." mvn -Dtest=TestJenkins test
```

### Run a single test

to run the `TestJenkins.testHA` test:

```
AWS_REGION="us-east-1" HOSTED_ZONE_ID="..." DOMAIN_SUFFIX="..." CLOUDFRONT_ACM_CERTIFICATE_ARN="..." ACM_CERTIFICATE_ARN="..." mvn -Dtest=TestJenkins#testHA test
```

### Load templates from local file system

```
AWS_REGION="us-east-1" HOSTED_ZONE_ID="..." DOMAIN_SUFFIX="..." CLOUDFRONT_ACM_CERTIFICATE_ARN="..." ACM_CERTIFICATE_ARN="..." BUCKET="..." TEMPLATE_DIR="/path/to/widdix-aws-cf-templates/" mvn test
```

### Assume role

This is useful if you run on a integration server like Jenkins and want to assume a different IAM role for this tests.

```
IAM_ROLE_ARN="arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME" mvn test
```
93 changes: 93 additions & 0 deletions test/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>de.widdix</groupId>
<artifactId>awscftemplates-tests</artifactId>
<version>1.0-SNAPSHOT</version>

<dependencies>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-cloudformation</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-ec2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-s3</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-route53</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-sts</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-ecs</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>de.taimos</groupId>
<artifactId>httputils</artifactId>
<version>1.10</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.evanlennick</groupId>
<artifactId>retry4j</artifactId>
<version>0.6.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.54</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-bom</artifactId>
<version>1.11.95</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
121 changes: 121 additions & 0 deletions test/src/test/java/de/widdix/awscftemplates/AAWSTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package de.widdix.awscftemplates;

import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.DefaultAWSCredentialsProviderChain;
import com.amazonaws.auth.STSAssumeRoleSessionCredentialsProvider;
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2AsyncClientBuilder;
import com.amazonaws.services.ec2.model.*;
import com.amazonaws.services.route53.AmazonRoute53AsyncClientBuilder;
import com.amazonaws.services.route53.model.*;
import com.amazonaws.services.securitytoken.AWSSecurityTokenService;
import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClientBuilder;
import com.amazonaws.services.route53.AmazonRoute53;

import java.util.List;
import java.util.UUID;

public abstract class AAWSTest extends ATest {

public final static String IAM_SESSION_NAME = "aws-cf-templates";

protected final AWSCredentialsProvider credentialsProvider;

private AmazonEC2 ec2;

private AmazonRoute53 route53;

public AAWSTest() {
super();
if (Config.has(Config.Key.IAM_ROLE_ARN)) {
final AWSSecurityTokenService sts = AWSSecurityTokenServiceClientBuilder.standard().build();
this.credentialsProvider = new STSAssumeRoleSessionCredentialsProvider.Builder(Config.get(Config.Key.IAM_ROLE_ARN), IAM_SESSION_NAME).withStsClient(sts).build();
} else {
this.credentialsProvider = new DefaultAWSCredentialsProviderChain();
}
this.ec2 = AmazonEC2AsyncClientBuilder.standard().withCredentials(this.credentialsProvider).build();
this.route53 = AmazonRoute53AsyncClientBuilder.standard().withCredentials(this.credentialsProvider).build();
}

protected final KeyPair createKey(final String keyName) {
final CreateKeyPairResult res = this.ec2.createKeyPair(new CreateKeyPairRequest().withKeyName(keyName));
return res.getKeyPair();
}

protected final void deleteKey(final String keyName) {
this.ec2.deleteKeyPair(new DeleteKeyPairRequest().withKeyName(keyName));
}

private void waitForDomain(final String name, final String changeId, final ChangeStatus finalStatus) {
System.out.println("waitForDomain[" + name + "]: to reach status " + finalStatus);
while (true) {
try {
Thread.sleep(5000);
} catch (final InterruptedException e) {
// continue
}
final GetChangeResult res = this.route53.getChange(new GetChangeRequest().withId(changeId));
final ChangeStatus currentStatus = ChangeStatus.fromValue(res.getChangeInfo().getStatus());
if (finalStatus == currentStatus) {
System.out.println("waitForDomain[" + name + "]: final status reached.");
return;
} else {
System.out.println("waitForDomain[" + name + "]: continue to wait (still in intermediate status " + currentStatus + ") ...");
}
}
}

protected final String generateDomain(final String prefix) {
return prefix + "." + Config.get(Config.Key.DOMAIN_SUFFIX);
}

protected final String createDomain(final String prefix, final String host) {
final String name = this.generateDomain(prefix);
final ResourceRecord rr = new ResourceRecord(host);
final ResourceRecordSet rrs = new ResourceRecordSet(name, RRType.CNAME).withTTL(60L).withResourceRecords(rr);
final Change create = new Change().withAction(ChangeAction.CREATE).withResourceRecordSet(rrs);
final ChangeBatch changeBatch = new ChangeBatch().withChanges(create);
final ChangeResourceRecordSetsRequest req = new ChangeResourceRecordSetsRequest().withHostedZoneId(Config.get(Config.Key.HOSTED_ZONE_ID)).withChangeBatch(changeBatch);
final ChangeResourceRecordSetsResult res = this.route53.changeResourceRecordSets(req);
this.waitForDomain(name, res.getChangeInfo().getId(), ChangeStatus.INSYNC);
return name;
}

protected final void deleteDomain(final String prefix) {
final String name = this.generateDomain(prefix);
final ListResourceRecordSetsResult res1 = this.route53.listResourceRecordSets(new ListResourceRecordSetsRequest().withHostedZoneId(Config.get(Config.Key.HOSTED_ZONE_ID)).withStartRecordName(name));
final ResourceRecordSet rrs = res1.getResourceRecordSets().get(0);
final Change delete = new Change().withAction(ChangeAction.DELETE).withResourceRecordSet(rrs);
final ChangeBatch changeBatch = new ChangeBatch().withChanges(delete);
final ChangeResourceRecordSetsRequest req = new ChangeResourceRecordSetsRequest().withHostedZoneId(Config.get(Config.Key.HOSTED_ZONE_ID)).withChangeBatch(changeBatch);
final ChangeResourceRecordSetsResult res2 = this.route53.changeResourceRecordSets(req);
this.waitForDomain(name, res2.getChangeInfo().getId(), ChangeStatus.INSYNC);
}

protected final Vpc getDefaultVPC() {
final DescribeVpcsResult res = this.ec2.describeVpcs(new DescribeVpcsRequest().withFilters(new Filter().withName("isDefault").withValues("true")));
return res.getVpcs().get(0);
}

protected final List<Subnet> getDefaultSubnets() {
final DescribeSubnetsResult res = this.ec2.describeSubnets(new DescribeSubnetsRequest().withFilters(new Filter().withName("defaultForAz").withValues("true")));
return res.getSubnets();
}

protected final SecurityGroup getDefaultSecurityGroup() {
final Vpc vpc = this.getDefaultVPC();
final DescribeSecurityGroupsResult res = this.ec2.describeSecurityGroups(new DescribeSecurityGroupsRequest().withFilters(
new Filter().withName("vpc-id").withValues(vpc.getVpcId()),
new Filter().withName("group-name").withValues("default")
));
return res.getSecurityGroups().get(0);
}

protected final String random8String() {
final String uuid = UUID.randomUUID().toString().replace("-", "").toLowerCase();
final int beginIndex = (int) (Math.random() * (uuid.length() - 7));
final int endIndex = beginIndex + 7;
return "r" + uuid.substring(beginIndex, endIndex); // must begin [a-z]
}

}
Loading

0 comments on commit fdd1612

Please sign in to comment.