package tw.com.unit;
import com.amazonaws.services.cloudformation.model.Parameter;
import com.amazonaws.services.cloudformation.model.Stack;
import com.amazonaws.services.cloudformation.model.TemplateParameter;
import com.amazonaws.services.ec2.model.KeyPair;
import com.amazonaws.services.ec2.model.Tag;
import com.amazonaws.services.ec2.model.Vpc;
import org.easymock.EasyMock;
import org.easymock.EasyMockRunner;
import org.easymock.EasyMockSupport;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import tw.com.AwsFacade;
import tw.com.EnvironmentSetupForTests;
import tw.com.FilesForTesting;
import tw.com.MonitorStackEvents;
import tw.com.entity.InstanceSummary;
import tw.com.entity.ProjectAndEnv;
import tw.com.entity.SearchCriteria;
import tw.com.entity.StackEntry;
import tw.com.exceptions.*;
import tw.com.providers.IdentityProvider;
import tw.com.providers.NotificationSender;
import tw.com.providers.SavesFile;
import tw.com.repository.CloudFormRepository;
import tw.com.repository.CloudRepository;
import tw.com.repository.ELBRepository;
import tw.com.repository.VpcRepository;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import static org.junit.Assert.*;
@RunWith(EasyMockRunner.class)
public class TestAwsFacade extends EasyMockSupport {
private AwsFacade aws;
private ProjectAndEnv projectAndEnv = EnvironmentSetupForTests.getMainProjectAndEnv();
private CloudFormRepository cfnRepository;
private VpcRepository vpcRepository;
private CloudRepository cloudRepository;
@Before
public void beforeEachTestRuns() {
MonitorStackEvents monitor = createMock(MonitorStackEvents.class);
cfnRepository = createMock(CloudFormRepository.class);
vpcRepository = createMock(VpcRepository.class);
ELBRepository elbRepository = createMock(ELBRepository.class);
cloudRepository = createStrictMock(CloudRepository.class);
IdentityProvider identityProvider = createStrictMock(IdentityProvider.class);
NotificationSender notificationSender = createStrictMock(NotificationSender.class);
String regionName = EnvironmentSetupForTests.getRegion().getName();
aws = new AwsFacade(monitor, cfnRepository, vpcRepository, elbRepository, cloudRepository, notificationSender, identityProvider,regionName);
}
@Test
public void shouldInitTagsOnVpc() throws CfnAssistException {
EasyMock.expect(vpcRepository.getCopyOfVpc(projectAndEnv)).andReturn(null);
vpcRepository.initAllTags("targetVpc", projectAndEnv);
EasyMock.expectLastCall();
replayAll();
aws.initEnvAndProjectForVPC("targetVpc", projectAndEnv);
verifyAll();
}
@Test
public void shouldSetTagOnVPC() {
vpcRepository.setVpcTag(projectAndEnv, "tagKey", "tagValue");
EasyMock.expectLastCall();
replayAll();
aws.setTagForVpc(projectAndEnv, "tagKey", "tagValue");
verifyAll();
}
@Test
public void shouldInitTagsOnVpcThrowIfAlreadyExists() throws CfnAssistException {
EasyMock.expect(vpcRepository.getCopyOfVpc(projectAndEnv)).andReturn(new Vpc().withVpcId("existingId"));
replayAll();
try {
aws.initEnvAndProjectForVPC("targetVpc", projectAndEnv);
fail("expected exception");
}
catch(TagsAlreadyInit expected) {
// expected
}
verifyAll();
}
@Test
public void shouldGetDeltaIndex() throws CfnAssistException {
EasyMock.expect(vpcRepository.getVpcIndexTag(projectAndEnv)).andReturn("42");
replayAll();
int result = aws.getDeltaIndex(projectAndEnv);
assertEquals(42, result);
verifyAll();
}
@Test
public void shouldGetDeltaIndexThrowsOnNonNumeric() throws CfnAssistException {
EasyMock.expect(vpcRepository.getVpcIndexTag(projectAndEnv)).andReturn("NaN");
replayAll();
try {
aws.getDeltaIndex(projectAndEnv);
fail("expected exception");
}
catch(BadVPCDeltaIndexException expectedException) {
// no op
}
verifyAll();
}
@Test
public void shouldSetAndResetDeltaIndex() throws CannotFindVpcException {
vpcRepository.setVpcIndexTag(projectAndEnv,"99");
EasyMock.expectLastCall();
vpcRepository.setVpcIndexTag(projectAndEnv,"0");
EasyMock.expectLastCall();
replayAll();
aws.setDeltaIndex(projectAndEnv, 99);
aws.resetDeltaIndex(projectAndEnv);
verifyAll();
}
@Test
public void shouldThrowForUnknownProjectAndEnvCombinationOnDeltaSet() throws CannotFindVpcException {
vpcRepository.setVpcIndexTag(projectAndEnv, "99");
EasyMock.expectLastCall().andThrow(new CannotFindVpcException(projectAndEnv));
replayAll();
try {
aws.setDeltaIndex(projectAndEnv, 99);
fail("Should have thrown exception");
}
catch(CannotFindVpcException expected) {
// expected
}
verifyAll();
}
@Test
public void shouldListStacksEnvSupplied() {
List<StackEntry> stacks = new LinkedList<>();
stacks.add(new StackEntry("proj", projectAndEnv.getEnvTag(), new Stack()));
EasyMock.expect(cfnRepository.getStacks(projectAndEnv.getEnvTag())).andReturn(stacks);
replayAll();
List<StackEntry> results = aws.listStacks(projectAndEnv);
assertEquals(1, results.size());
verifyAll();
}
@Test
public void shouldListSummaryOfInstancesWithEnv() throws CfnAssistException {
String idA = "instanceIdA";
String idB = "instanceIdB";
List<Tag> tagsA = new LinkedList<>();
tagsA.add(EnvironmentSetupForTests.createEc2Tag("ENV", "env"));
List<Tag> tagsB = new LinkedList<>();
tagsB.add(EnvironmentSetupForTests.createEc2Tag("TAG", "value"));
com.amazonaws.services.ec2.model.Instance instanceA = new com.amazonaws.services.ec2.model.Instance().
withInstanceId(idA).withPrivateIpAddress("10.1.2.3").withTags(tagsA);
com.amazonaws.services.ec2.model.Instance instanceB = new com.amazonaws.services.ec2.model.Instance().
withInstanceId(idB).withPrivateIpAddress("10.8.7.6").withTags(tagsB);
List<String> instanceList = new LinkedList<>();
instanceList.add(idA);
instanceList.add(idB);
SearchCriteria criteria = new SearchCriteria(projectAndEnv);
EasyMock.expect(cfnRepository.getAllInstancesFor(criteria)).andReturn(instanceList);
EasyMock.expect(cloudRepository.getInstanceById(idA)).andReturn(instanceA);
EasyMock.expect(cloudRepository.getInstanceById(idB)).andReturn(instanceB);
replayAll();
List<InstanceSummary> results = aws.listInstances(criteria);
verifyAll();
assertEquals(2, results.size());
assertTrue(results.contains(new InstanceSummary(idA, "10.1.2.3", tagsA)));
assertTrue(results.contains(new InstanceSummary(idB, "10.8.7.6", tagsB)));
}
@Test
public void shouldListStacksNoEnvSupplied() {
List<StackEntry> stacks = new LinkedList<>();
stacks.add(new StackEntry("proj", projectAndEnv.getEnvTag(), new Stack()));
EasyMock.expect(cfnRepository.getStacks()).andReturn(stacks);
replayAll();
ProjectAndEnv pattern = new ProjectAndEnv("someProject", "");
List<StackEntry> results = aws.listStacks(pattern);
assertEquals(1,results.size());
verifyAll();
}
@Test
public void shouldInvokeValidation() {
List<TemplateParameter> params = new LinkedList<>();
params.add(new TemplateParameter().withDescription("a parameter"));
EasyMock.expect(cfnRepository.validateStackTemplate("someContents")).andReturn(params);
replayAll();
List<TemplateParameter> results = aws.validateTemplate("someContents");
verifyAll();
assertEquals(1, results.size());
}
@Test
public void cannotAddEnvParameter() throws IOException, CfnAssistException, InterruptedException {
checkParameterCannotBePassed("env");
}
@Test
public void cannotAddvpcParameter() throws IOException, CfnAssistException, InterruptedException {
checkParameterCannotBePassed("vpc");
}
@Test
public void cannotAddbuildParameter() throws IOException, CfnAssistException, InterruptedException {
checkParameterCannotBePassed("build");
}
@Test
public void createStacknameFromEnvAndFile() {
String stackName = aws.createStackName(new File(FilesForTesting.SIMPLE_STACK), projectAndEnv);
assertEquals("CfnAssistTestsimpleStack", stackName);
}
@Test
public void shouldCreateStacknameFromEnvAndFileWithDelta() {
String stackName = aws.createStackName(new File(FilesForTesting.STACK_UPDATE), projectAndEnv);
assertEquals("CfnAssistTest02createSubnet", stackName);
}
@Test
public void shouldIncludeBuildNumberWhenFormingStackname() {
projectAndEnv.addBuildNumber(42);
String stackName = aws.createStackName(new File(FilesForTesting.SIMPLE_STACK),projectAndEnv);
assertEquals("CfnAssist42TestsimpleStack", stackName);
}
@Test
public void shouldCreateKeyPairAndTagVPC() throws CfnAssistException {
String filename = "fileForPem.pem";
SavesFile destination = createStrictMock(SavesFile.class);
KeyPair keypair = new KeyPair().withKeyName("CfnAssist_Test");
EasyMock.expect(destination.exists(filename)).andReturn(false);
EasyMock.expect(cloudRepository.createKeyPair("CfnAssist_Test", destination, filename)).
andReturn(keypair);
vpcRepository.setVpcTag(projectAndEnv, "keypairname", "CfnAssist_Test");
EasyMock.expectLastCall();
replayAll();
KeyPair result = aws.createKeyPair(projectAndEnv, destination, filename);
verifyAll();
assertEquals("CfnAssist_Test", result.getKeyName());
}
@Test
public void shouldNotCreateKeyPairIfFileAlreadyExists() throws CfnAssistException {
SavesFile destination = createStrictMock(SavesFile.class);
String filename = "fileForPem.pem";
EasyMock.expect(destination.exists(filename)).andReturn(true);
replayAll();
try {
aws.createKeyPair(projectAndEnv, destination, filename);
fail("should have thrown");
}
catch(CfnAssistException expected) {
// no-op
}
verifyAll();
}
@Test
public void shouldFormCorrectTestForSSHCommand() throws CfnAssistException {
String home = System.getenv("HOME");
EasyMock.expect(vpcRepository.getVpcTag(AwsFacade.KEYNAME_TAG, projectAndEnv)).andReturn("project_env_keypair");
EasyMock.expect(vpcRepository.getVpcTag(AwsFacade.NAT_EIP, projectAndEnv)).andReturn("eipAllocationId");
EasyMock.expect(cloudRepository.getIpFor("eipAllocationId")).andReturn("10.1.2.3");
replayAll();
List<String> commandText = aws.createSSHCommand(projectAndEnv, "ec2-user");
verifyAll();
StringBuilder result = new StringBuilder();
commandText.forEach(text -> {
if (result.length()>0) {
result.append(" ");
}
result.append(text);
});
assertEquals(String.format("ssh -i %s/.ssh/project_env.pem ec2-user@10.1.2.3", home), result.toString());
}
private void checkParameterCannotBePassed(String parameterName)
throws IOException,
CfnAssistException, InterruptedException {
Parameter parameter = new Parameter();
parameter.setParameterKey(parameterName);
parameter.setParameterValue("test");
Collection<Parameter> parameters = new HashSet<>();
parameters.add(parameter);
try {
aws.applyTemplate(new File(FilesForTesting.SIMPLE_STACK), projectAndEnv, parameters);
fail("Should have thrown exception");
}
catch (InvalidStackParameterException exception) {
// expected
}
}
}