package org.cloudfoundry.community.servicebroker.datalifecycle.aws;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.krujos.test.aws.request.AWSRequestMatcher.awsRqst;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.concurrent.TimeoutException;
import java.util.function.Predicate;
import org.cloudfoundry.community.servicebroker.datalifecycle.utils.HostUtils;
import org.cloudfoundry.community.servicebroker.exception.ServiceBrokerException;
import org.cloudfoundry.community.servicebroker.exception.ServiceInstanceBindingExistsException;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import com.amazonaws.services.ec2.AmazonEC2Client;
import com.amazonaws.services.ec2.model.Address;
import com.amazonaws.services.ec2.model.CreateImageResult;
import com.amazonaws.services.ec2.model.DescribeAddressesResult;
import com.amazonaws.services.ec2.model.DescribeImagesResult;
import com.amazonaws.services.ec2.model.DescribeInstanceStatusResult;
import com.amazonaws.services.ec2.model.DescribeInstancesResult;
import com.amazonaws.services.ec2.model.DescribeSnapshotsResult;
import com.amazonaws.services.ec2.model.DescribeVolumesRequest;
import com.amazonaws.services.ec2.model.DescribeVolumesResult;
import com.amazonaws.services.ec2.model.Filter;
import com.amazonaws.services.ec2.model.Image;
import com.amazonaws.services.ec2.model.Instance;
import com.amazonaws.services.ec2.model.InstanceState;
import com.amazonaws.services.ec2.model.InstanceStatus;
import com.amazonaws.services.ec2.model.Reservation;
import com.amazonaws.services.ec2.model.RunInstancesResult;
import com.amazonaws.services.ec2.model.Snapshot;
import com.amazonaws.services.ec2.model.Volume;
public class AWSHelperTest {
@Mock
private AmazonEC2Client ec2Client;
private AWSHelper aws;
private DescribeImagesResult describeImagesResult = new DescribeImagesResult()
.withImages(new Image().withState("available"));
private Instance instance = new Instance().withInstanceId("test_instance");
private RunInstancesResult runInstanceResult = new RunInstancesResult()
.withReservation(new Reservation().withInstances(Collections
.singletonList(instance)));
@Mock
private HostUtils hostUtils;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
aws = new AWSHelper(ec2Client, "test_subnet", "source_instance",
hostUtils, 5432);
}
@Test
public void itShouldCreateAnAMI() throws Exception {
when(
ec2Client.createImage(awsRqst(r -> r.getInstanceId().equals(
"test_source_instance")
&& true == r.getNoReboot()))).thenReturn(
new CreateImageResult().withImageId("test_image"));
when(
ec2Client.describeImages(awsRqst(r -> r.getImageIds().get(0)
.equals("test_image")))).thenReturn(
describeImagesResult);
String amiId = aws
.createAMI("test_source_instance", "test_description");
assertThat(amiId, is(equalTo("test_image")));
}
@Test
public void itShouldStartAnEC2InstanceFromAnAMI()
throws ServiceBrokerException {
when(
ec2Client.runInstances(awsRqst(r -> r.getImageId().equals(
"test_image")))).thenReturn(runInstanceResult);
when(ec2Client.describeAddresses()).thenReturn(
new DescribeAddressesResult().withAddresses(Collections
.singleton(new Address().withPublicIp("10.10.10.10"))));
when(ec2Client.describeInstanceStatus(any())).thenReturn(
new DescribeInstanceStatusResult()
.withInstanceStatuses(Collections
.singleton(new InstanceStatus()
.withInstanceState(new InstanceState()
.withName("running")))));
when(hostUtils.waitForBoot(anyString(), anyInt())).thenReturn(true);
assertThat(aws.startEC2Instance("test_image"),
is(equalTo("test_instance")));
}
// TODO this should not throw a service broker exception.
@Test(expected = TimeoutException.class)
public void itShouldFailWhenImageStateIsFailed() throws TimeoutException {
when(ec2Client.createImage(any())).thenReturn(
new CreateImageResult().withImageId("test_image"));
describeImagesResult.getImages().get(0).setState("failed");
when(ec2Client.describeImages(any())).thenReturn(describeImagesResult);
aws.createAMI("test_source_instance", "it's not gonna work");
}
@Test
public void itShouldTerminateTheInstance() {
aws.terminateEc2Instance("test_instance");
verify(ec2Client)
.terminateInstances(
awsRqst(r -> r.getInstanceIds().get(0)
.equals("test_instance")));
}
@Test
public void itShouldDeregisterTheAMI() {
aws.deregisterAMI("test_image");
verify(ec2Client).deregisterImage(
awsRqst(r -> r.getImageId().equals("test_image")));
}
@Test
public void itShouldDeleteTheStorageArtifacts()
throws ServiceInstanceBindingExistsException,
ServiceBrokerException {
when(ec2Client.describeSnapshots())
.thenReturn(
new DescribeSnapshotsResult().withSnapshots(Arrays.asList(
new Snapshot()
.withDescription("Created by CreateImage(source_instance) for ami-9687d2fe from vol-e7526fac"),
new Snapshot()
.withDescription(
"Created by CreateImage(source_instance) for test_image from vol-e7526fac")
.withSnapshotId("test_snapshot"),
new Snapshot()
.withDescription("Created by CreateImage(i-bf72d345) for ami-xx from vol-e7526fac"),
new Snapshot())));
Predicate<DescribeVolumesRequest> pred = new Predicate<DescribeVolumesRequest>() {
@Override
public boolean test(DescribeVolumesRequest r) {
Filter filter = r.getFilters().stream().findFirst().get();
return filter.getName().equals("snapshot-id")
&& filter.getValues().stream().findFirst().get()
.equals("test_snapshot");
}
};
DescribeVolumesResult volumesResult = new DescribeVolumesResult()
.withVolumes(Collections.singletonList(new Volume()
.withVolumeId("test_volume")));
when(ec2Client.describeVolumes(awsRqst(pred)))
.thenReturn(volumesResult);
aws.deleteStorageArtifacts("test_image");
verify(ec2Client).deleteSnapshot(
awsRqst(r -> r.getSnapshotId().equals("test_snapshot")));
verify(ec2Client).deleteVolume(
awsRqst(r -> r.getVolumeId().equals("test_volume")));
}
@Test(expected = ServiceBrokerException.class)
public void itShouldThrowWhenMoreThanOneAMIIsFoundToBeDeleted()
throws ServiceBrokerException,
ServiceInstanceBindingExistsException {
when(ec2Client.describeSnapshots())
.thenReturn(
new DescribeSnapshotsResult().withSnapshots(Arrays.asList(
new Snapshot()
.withDescription("Created by CreateImage(source_instance) for test_image from vol-e7526fac"),
new Snapshot()
.withDescription(
"Created by CreateImage(source_instance) for test_image from vol-e7526fac")
.withSnapshotId("test_snapshot"),
new Snapshot()
.withDescription("Created by CreateImage(source_instance) for ami-xx from vol-e7526fac"),
new Snapshot())));
aws.deleteStorageArtifacts("test_image");
verify(ec2Client, never()).deleteSnapshot(any());
}
@Test
public void itShouldGetTheInstanceDNSName() {
when(ec2Client.describeInstances(any())).thenReturn(
new DescribeInstancesResult()
.withReservations(new Reservation()
.withInstances(new Instance()
.withPublicIpAddress("0.0.0.0"))));
assertThat(aws.getEC2InstancePublicIp(instance.getInstanceId()),
is(equalTo("0.0.0.0")));
}
@Test
public void itShouldReturnAFreeElasticIp() throws ServiceBrokerException {
when(ec2Client.describeAddresses()).thenReturn(
new DescribeAddressesResult().withAddresses(Collections
.singleton(new Address().withPublicIp("10.10.10.10"))));
assertThat("10.10.10.10", is(aws.getAvaliableElasticIp()));
}
@Test
public void itShouldReturnOnlyOneFreeElasticIp()
throws ServiceBrokerException {
when(ec2Client.describeAddresses()).thenReturn(
new DescribeAddressesResult().withAddresses(Arrays.asList(
new Address().withPublicIp("10.10.10.10")
.withInstanceId(null),
new Address().withPublicIp("10.10.10.11")
.withInstanceId(null))));
assertThat("10.10.10.10", is(aws.getAvaliableElasticIp()));
}
@Test(expected = ServiceBrokerException.class)
public void itShouldReturnNullIfNoElasticIpIsAvaliable()
throws ServiceBrokerException {
when(ec2Client.describeAddresses()).thenReturn(
new DescribeAddressesResult().withAddresses(new ArrayList<>()));
assertNull(aws.getAvaliableElasticIp());
}
@Test
public void itShouldFilterOutAttachedElasticIPs()
throws ServiceBrokerException {
when(ec2Client.describeAddresses()).thenReturn(
new DescribeAddressesResult().withAddresses(Arrays.asList(
new Address().withPublicIp("10.10.10.10")
.withInstanceId("the-instance"),
new Address().withPublicIp("10.10.10.11")
.withInstanceId(null))));
assertThat("10.10.10.11", is(aws.getAvaliableElasticIp()));
}
}