diff --git a/src/main/java/com/tlswe/awsmock/ec2/control/MockEC2QueryHandler.java b/src/main/java/com/tlswe/awsmock/ec2/control/MockEC2QueryHandler.java index ad20decb..c6dbf7b3 100644 --- a/src/main/java/com/tlswe/awsmock/ec2/control/MockEC2QueryHandler.java +++ b/src/main/java/com/tlswe/awsmock/ec2/control/MockEC2QueryHandler.java @@ -1,7 +1,6 @@ package com.tlswe.awsmock.ec2.control; import java.io.IOException; -import java.sql.Date; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -20,7 +19,6 @@ import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.math.NumberUtils; import org.joda.time.DateTime; -import org.omg.CORBA.SystemException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -90,7 +88,6 @@ import com.tlswe.awsmock.ec2.cxf_generated.SecurityGroupItemType; import com.tlswe.awsmock.ec2.cxf_generated.SecurityGroupSetType; import com.tlswe.awsmock.ec2.cxf_generated.StartInstancesResponseType; -import com.tlswe.awsmock.ec2.cxf_generated.StateReasonType; import com.tlswe.awsmock.ec2.cxf_generated.StopInstancesResponseType; import com.tlswe.awsmock.ec2.cxf_generated.SubnetSetType; import com.tlswe.awsmock.ec2.cxf_generated.SubnetType; @@ -501,8 +498,14 @@ public void handle(final Map queryParams, int minCount = Integer.parseInt(queryParams.get("MinCount")[0]); int maxCount = Integer.parseInt(queryParams.get("MaxCount")[0]); + final String[] subnetIdArray = queryParams.get("SubnetId"); + String subnetId = null; + if (subnetIdArray != null) { + subnetId = subnetIdArray[0]; + } + responseXml = JAXBUtil.marshall( - runInstances(imageID, instanceType, minCount, maxCount), + runInstances(imageID, instanceType, minCount, maxCount, subnetId), "RunInstancesResponse", version); } else if ("DescribeImages".equals(action)) { @@ -1139,9 +1142,9 @@ private DescribeInstancesResponseType describeInstances(final Set instan instItem.setDnsName(instance.getPubDns()); // set network information - instItem.setVpcId(MOCK_VPC_ID); + instItem.setVpcId(getVpcForSubnetId(instance.getSubnetId())); instItem.setPrivateIpAddress(MOCK_PRIVATE_IP_ADDRESS); - instItem.setSubnetId(MOCK_SUBNET_ID); + instItem.setSubnetId(instance.getSubnetId()); instsSet.getItem().add(instItem); @@ -1180,7 +1183,8 @@ protected String generateToken() { } /** - * Handles "runInstances" request, with only simplified filters of imageId, instanceType, minCount and maxCount. + * Handles "runInstances" request, with only simplified filters of imageId, instanceType, minCount, maxCount + * and subnetId. * * @param imageId * AMI of new mock ec2 instance(s) @@ -1190,10 +1194,12 @@ protected String generateToken() { * max count of instances to run * @param maxCount * min count of instances to run + * @param subnetId + * subnet ID of new mock ec2 instance(s). * @return a RunInstancesResponse that includes all information for the started new mock ec2 instances */ private RunInstancesResponseType runInstances(final String imageId, final String instanceType, - final int minCount, final int maxCount) { + final int minCount, final int maxCount, final String subnetId) { RunInstancesResponseType ret = new RunInstancesResponseType(); @@ -1215,7 +1221,7 @@ private RunInstancesResponseType runInstances(final String imageId, final String List newInstances = null; newInstances = mockEc2Controller - .runInstances(clazzOfMockEc2Instance, imageId, instanceType, minCount, maxCount); + .runInstances(clazzOfMockEc2Instance, imageId, instanceType, minCount, maxCount, subnetId); for (AbstractMockEc2Instance i : newInstances) { RunningInstancesItemType instItem = new RunningInstancesItemType(); @@ -1230,9 +1236,9 @@ private RunInstancesResponseType runInstances(final String imageId, final String instItem.setPlacement(DEFAULT_MOCK_PLACEMENT); // set network information - instItem.setVpcId(MOCK_VPC_ID); + instItem.setSubnetId(subnetId); + instItem.setVpcId(getVpcForSubnetId(subnetId)); instItem.setPrivateIpAddress(MOCK_PRIVATE_IP_ADDRESS); - instItem.setSubnetId(MOCK_SUBNET_ID); instSet.getItem().add(instItem); @@ -2048,4 +2054,19 @@ private String getBlankResponseXml() { } return ret; } + + /** + * Gets the VPC id for a given subnetId. + * + * @param subnetId The subnet id. + * @return The VPC id. Returns null, if no matching subnet is found. + */ + private String getVpcForSubnetId(final String subnetId) { + for (MockSubnet subnet : mockSubnetController.describeSubnets()) { + if (subnet.getSubnetId().equals(subnetId)) { + return subnet.getVpcId(); + } + } + return null; + } } diff --git a/src/main/java/com/tlswe/awsmock/ec2/control/MockEc2Controller.java b/src/main/java/com/tlswe/awsmock/ec2/control/MockEc2Controller.java index 317a1559..83df7b6f 100644 --- a/src/main/java/com/tlswe/awsmock/ec2/control/MockEc2Controller.java +++ b/src/main/java/com/tlswe/awsmock/ec2/control/MockEc2Controller.java @@ -146,12 +146,15 @@ public List listInstanceIDs(final Set instanceIDs) { * max count of instances to run (but limited to {@link #MAX_RUN_INSTANCE_COUNT_AT_A_TIME}) * @param maxCount * min count of instances to run (should larger than 0) + * @param subnetId + * The subnet id of new mock ec2 instance(s). May be null. + * * @return a list of objects of clazz as started new mock ec2 instances * */ public List runInstances(final Class clazz, final String imageId, final String instanceTypeName, - final int minCount, final int maxCount) { + final int minCount, final int maxCount, final String subnetId) { // EC2 Query Request action name final String action = "runInstances"; @@ -202,6 +205,7 @@ public List runInstances(final Class securityGroups = new TreeSet(); + /** + * Subnet id for this ec2 instance. + */ + private String subnetId = null; + /** * Flag that indicates whether internal timer of this mock ec2 instance has been started (on instance start()). */ @@ -800,6 +805,24 @@ public final InstanceState getInstanceState() { : InstanceState.STOPPED))); } + /** + * Get subnet ID of this mock ec2 instance. + * + * @return subnet ID of this mock ec2 instance + */ + public final String getSubnetId() { + return subnetId; + } + + /** + * Set the subnet ID of this mock ec2 instance. + * + * @param subnetId subnet ID of this mock ec2 instance + */ + public void setSubnetId(final String subnetId) { + this.subnetId = subnetId; + } + /** * Get the AMI this mock ec2 instance started from. * diff --git a/src/main/java/com/tlswe/awsmock/ec2/model/DefaultMockEc2Instance.java b/src/main/java/com/tlswe/awsmock/ec2/model/DefaultMockEc2Instance.java index 319b6311..93ef4b5c 100644 --- a/src/main/java/com/tlswe/awsmock/ec2/model/DefaultMockEc2Instance.java +++ b/src/main/java/com/tlswe/awsmock/ec2/model/DefaultMockEc2Instance.java @@ -15,7 +15,7 @@ public class DefaultMockEc2Instance extends AbstractMockEc2Instance { * * @see Serializable */ - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 2L; @Override public void onStarted() { diff --git a/src/test/java/com/tlswe/awsmock/ec2/control/MockEC2QueryHandlerTest.java b/src/test/java/com/tlswe/awsmock/ec2/control/MockEC2QueryHandlerTest.java index a73ead4d..2fcf010d 100644 --- a/src/test/java/com/tlswe/awsmock/ec2/control/MockEC2QueryHandlerTest.java +++ b/src/test/java/com/tlswe/awsmock/ec2/control/MockEC2QueryHandlerTest.java @@ -7,6 +7,7 @@ import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -18,6 +19,7 @@ import javax.servlet.http.HttpServletResponse; +import com.tlswe.awsmock.ec2.model.MockSubnet; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -57,12 +59,10 @@ import com.tlswe.awsmock.ec2.cxf_generated.DescribeVolumesResponseType; import com.tlswe.awsmock.ec2.cxf_generated.DescribeVpcsResponseType; import com.tlswe.awsmock.ec2.cxf_generated.InternetGatewayType; -import com.tlswe.awsmock.ec2.cxf_generated.IpPermissionType; import com.tlswe.awsmock.ec2.cxf_generated.ReservationInfoType; import com.tlswe.awsmock.ec2.cxf_generated.RunInstancesResponseType; import com.tlswe.awsmock.ec2.cxf_generated.RunningInstancesItemType; import com.tlswe.awsmock.ec2.cxf_generated.RunningInstancesSetType; -import com.tlswe.awsmock.ec2.cxf_generated.SecurityGroupItemType; import com.tlswe.awsmock.ec2.cxf_generated.VpcType; import com.tlswe.awsmock.ec2.exception.BadEc2RequestException; import com.tlswe.awsmock.ec2.model.AbstractMockEc2Instance; @@ -86,6 +86,8 @@ public class MockEC2QueryHandlerTest { private static final String ACTION_KEY = "Action"; private static final String VERSION_KEY = "Version"; private static final String VERSION_1 = "version1"; + private static final String SUBNET_ID = "subnetId"; + private static final String VPC_ID = "vpcId"; static { InputStream inputStream = null; @@ -510,17 +512,18 @@ public void Test_runInstances() throws Exception { MockEc2Controller controller = Mockito.spy(MockEc2Controller.class); Whitebox.setInternalState(handler, "mockEc2Controller", controller); + createAndInjectMockSubnetController(handler); + RunInstancesResponseType ret = Whitebox.invokeMethod(handler, "runInstances", "ami-1", - InstanceType.C1_MEDIUM.getName(), 1, 1); + InstanceType.C1_MEDIUM.getName(), 1, 1, SUBNET_ID); Assert.assertTrue(ret != null); Assert.assertTrue(ret.getInstancesSet().getItem().size() == 1); RunningInstancesItemType instItem = ret.getInstancesSet().getItem().get(0); - Assert.assertTrue(instItem.getVpcId().equals(properties.get(Constants.PROP_NAME_VPC_ID))); // from - // aws.mock-default.properties + Assert.assertTrue(instItem.getVpcId().equals(VPC_ID)); Assert.assertTrue( - instItem.getSubnetId().equals(properties.get(Constants.PROP_NAME_SUBNET_ID))); + instItem.getSubnetId().equals(SUBNET_ID)); Assert.assertTrue(instItem.getPrivateIpAddress() .equals(properties.get(Constants.PROP_NAME_PRIVATE_IP_ADDRESS))); Assert.assertTrue(instItem.getImageId().equals("ami-1")); @@ -713,9 +716,11 @@ public void Test_describeInstances() throws Exception { CustomMockEc2Instance ec2Mocked1 = new CustomMockEc2Instance(); ec2Mocked1.setInstanceType(InstanceType.C1_MEDIUM); + ec2Mocked1.setSubnetId(SUBNET_ID); CustomMockEc2Instance ec2Mocked2 = new CustomMockEc2Instance(); ec2Mocked2.setInstanceType(InstanceType.C3_8XLARGE); + ec2Mocked2.setSubnetId(SUBNET_ID); MockEc2Controller controller = Mockito.spy(MockEc2Controller.class); @@ -731,6 +736,8 @@ public void Test_describeInstances() throws Exception { allMockEc2Instances); Whitebox.setInternalState(handler, "mockEc2Controller", controller); + createAndInjectMockSubnetController(handler); + Set instanceStateSet = new HashSet(); instanceStateSet.add(InstanceState.STOPPED.getName()); @@ -758,13 +765,15 @@ public void Test_describeInstances() throws Exception { String instanceId1 = runningSetType.getItem().get(0).getInstanceId(); - // check if default params were applied + // check if network params were applied Assert.assertTrue(runningSetType.getItem().get(0).getVpcId() - .equals(properties.get(Constants.PROP_NAME_VPC_ID))); + .equals(VPC_ID)); + Assert.assertTrue(runningSetType.getItem().get(0).getSubnetId() + .equals(SUBNET_ID)); + + // check if default params were applied Assert.assertTrue(runningSetType.getItem().get(0).getPrivateIpAddress() .equals(properties.get(Constants.PROP_NAME_PRIVATE_IP_ADDRESS))); - Assert.assertTrue(runningSetType.getItem().get(0).getSubnetId() - .equals(properties.get(Constants.PROP_NAME_SUBNET_ID))); Assert.assertTrue(runningSetType.getItem().get(0).getInstanceState().getName() .equals(InstanceState.STOPPED.getName())); @@ -772,13 +781,15 @@ public void Test_describeInstances() throws Exception { String instanceId2 = runningSetType.getItem().get(0).getInstanceId(); - // check if default params were applied + // check if network params were applied Assert.assertTrue(runningSetType.getItem().get(0).getVpcId() - .equals(properties.get(Constants.PROP_NAME_VPC_ID))); + .equals(VPC_ID)); + Assert.assertTrue(runningSetType.getItem().get(0).getSubnetId() + .equals(SUBNET_ID)); + + // check if default params were applied Assert.assertTrue(runningSetType.getItem().get(0).getPrivateIpAddress() .equals(properties.get(Constants.PROP_NAME_PRIVATE_IP_ADDRESS))); - Assert.assertTrue(runningSetType.getItem().get(0).getSubnetId() - .equals(properties.get(Constants.PROP_NAME_SUBNET_ID))); Assert.assertTrue(runningSetType.getItem().get(0).getInstanceState().getName() .equals(InstanceState.STOPPED.getName())); @@ -1106,6 +1117,35 @@ public void Test_handleRunInstances() throws IOException { Assert.assertTrue(responseString.equals(DUMMY_XML_RESPONSE)); } + @Test + public void Test_handleRunInstancesWithSubnetId() throws IOException { + + HttpServletResponse response = Mockito.spy(HttpServletResponse.class); + MockEC2QueryHandler handler = MockEC2QueryHandler.getInstance(); + + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + + Mockito.when(response.getWriter()).thenReturn(pw); + Mockito.when(JAXBUtil.marshall(Mockito.any(), Mockito.eq("RunInstancesResponse"), + Mockito.eq(VERSION_1))) + .thenReturn(DUMMY_XML_RESPONSE); + + Map queryParams = new HashMap(); + + queryParams.put(VERSION_KEY, new String[] { VERSION_1 }); + queryParams.put(ACTION_KEY, new String[] { "RunInstances" }); + queryParams.put("ImageId", new String[] { "img-1" }); + queryParams.put("MinCount", new String[] { "2" }); + queryParams.put("MaxCount", new String[] { "5" }); + queryParams.put("InstanceType", new String[] { "m1.small" }); + queryParams.put("SubnetId", new String[] { "subnetId" }); + handler.handle(queryParams, null, response); + + String responseString = sw.toString(); + Assert.assertTrue(responseString.equals(DUMMY_XML_RESPONSE)); + } + @Test public void Test_handleStartInstances() throws IOException { @@ -2315,4 +2355,14 @@ public void Test_handleNonSafeAPI_DescribeVolumes() throws IOException { String responseString = sw.toString(); Assert.assertTrue(responseString.contains("Response")); } + + private static void createAndInjectMockSubnetController(final MockEC2QueryHandler handler) { + final MockSubnet subnet = new MockSubnet(); + subnet.setSubnetId(SUBNET_ID); + subnet.setVpcId(VPC_ID); + + MockSubnetController subnetControllerMock = Mockito.spy(MockSubnetController.class); + Mockito.when(subnetControllerMock.describeSubnets()).thenReturn(Collections.singletonList(subnet)); + Whitebox.setInternalState(handler, "mockSubnetController", subnetControllerMock); + } } diff --git a/src/test/java/com/tlswe/awsmock/ec2/control/MockEc2ControllerTest.java b/src/test/java/com/tlswe/awsmock/ec2/control/MockEc2ControllerTest.java index 9e71164c..556c9896 100644 --- a/src/test/java/com/tlswe/awsmock/ec2/control/MockEc2ControllerTest.java +++ b/src/test/java/com/tlswe/awsmock/ec2/control/MockEc2ControllerTest.java @@ -27,6 +27,7 @@ @RunWith(PowerMockRunner.class) @PrepareForTest({ MockEc2Controller.class, DefaultMockEc2Instance.class }) public class MockEc2ControllerTest { + private static final String SUBNET_ID = "SubnetId"; @Test public void Test_getInstance() { @@ -375,7 +376,7 @@ public void Test_cleanupTerminatedInstances() throws Exception { public void Test_runInstancesBadRequestInstanceType() throws Exception { MockEc2Controller controller = Mockito.spy(MockEc2Controller.class); - controller.runInstances(DefaultMockEc2Instance.class, "ImageName", "InvalidName", 10, 1); + controller.runInstances(DefaultMockEc2Instance.class, "ImageName", "InvalidName", 10, 1, SUBNET_ID); } @Test(expected = BadEc2RequestException.class) @@ -383,7 +384,7 @@ public void Test_runInstancesBadRequestMaxCountHigh() throws Exception { MockEc2Controller controller = Mockito.spy(MockEc2Controller.class); controller.runInstances(DefaultMockEc2Instance.class, "ImageName", - InstanceType.C1_MEDIUM.getName(), 1, 10001); + InstanceType.C1_MEDIUM.getName(), 1, 10001, SUBNET_ID); } @Test(expected = BadEc2RequestException.class) @@ -391,7 +392,7 @@ public void Test_runInstancesBadRequestMinCountLow() throws Exception { MockEc2Controller controller = Mockito.spy(MockEc2Controller.class); controller.runInstances(DefaultMockEc2Instance.class, "ImageName", - InstanceType.C1_MEDIUM.getName(), 0, 10); + InstanceType.C1_MEDIUM.getName(), 0, 10, SUBNET_ID); } @Test(expected = BadEc2RequestException.class) @@ -399,7 +400,7 @@ public void Test_runInstancesMinCountGreaterThanMaxCount() throws Exception { MockEc2Controller controller = Mockito.spy(MockEc2Controller.class); controller.runInstances(DefaultMockEc2Instance.class, "ImageName", - InstanceType.C1_MEDIUM.getName(), 11, 10); + InstanceType.C1_MEDIUM.getName(), 11, 10, SUBNET_ID); } @Test(expected = AwsMockException.class) @@ -409,7 +410,7 @@ public void Test_runInstancesAwsMockException() throws Exception { // shouldn't be able to start abstract class controller.runInstances(AbstractMockEc2Instance.class, "ImageName", - InstanceType.C1_MEDIUM.getName(), 1, 1); + InstanceType.C1_MEDIUM.getName(), 1, 1, SUBNET_ID); } @Test @@ -417,7 +418,7 @@ public void Test_runInstances() throws Exception { MockEc2Controller controller = Mockito.spy(MockEc2Controller.class); controller.runInstances(DefaultMockEc2Instance.class, "ImageName", - InstanceType.C1_MEDIUM.getName(), 1, 1); + InstanceType.C1_MEDIUM.getName(), 1, 1, SUBNET_ID); } } diff --git a/src/test/java/com/tlswe/awsmock/ec2/util/JAXBUtilTest.java b/src/test/java/com/tlswe/awsmock/ec2/util/JAXBUtilTest.java index b4cfc3b3..85305e67 100644 --- a/src/test/java/com/tlswe/awsmock/ec2/util/JAXBUtilTest.java +++ b/src/test/java/com/tlswe/awsmock/ec2/util/JAXBUtilTest.java @@ -19,6 +19,7 @@ @RunWith(PowerMockRunner.class) @PrepareForTest({ MockEC2QueryHandler.class, PropertiesUtils.class }) public class JAXBUtilTest { + private static final String SUBNET_ID = "subnetId"; @Test public void Test_marshall() throws Exception { @@ -31,7 +32,7 @@ public void Test_marshall() throws Exception { MockEC2QueryHandler handler = MockEC2QueryHandler.getInstance(); RunInstancesResponseType runInstancesResponseType = Whitebox.invokeMethod(handler, "runInstances", imageID, - instanceType, minCount, maxCount); + instanceType, minCount, maxCount, SUBNET_ID); String xml = JAXBUtil.marshall(runInstancesResponseType, "RunInstancesResponse", "2012-02-10"); @@ -65,7 +66,7 @@ public void Test_mashallElasticFoxTrueVersionNull() throws Exception { MockEC2QueryHandler handler = MockEC2QueryHandler.getInstance(); RunInstancesResponseType runInstancesResponseType = Whitebox.invokeMethod(handler, "runInstances", imageID, - instanceType, minCount, maxCount); + instanceType, minCount, maxCount, SUBNET_ID); String xml = JAXBUtil.marshall(runInstancesResponseType, "RunInstancesResponse", null); @@ -89,7 +90,7 @@ public void Test_mashallNotElasticFox() throws Exception { MockEC2QueryHandler handler = MockEC2QueryHandler.getInstance(); RunInstancesResponseType runInstancesResponseType = Whitebox.invokeMethod(handler, "runInstances", imageID, - instanceType, minCount, maxCount); + instanceType, minCount, maxCount, SUBNET_ID); String xml = JAXBUtil.marshall(runInstancesResponseType, "RunInstancesResponse", null); @@ -109,7 +110,7 @@ public void Test_mashallReplaceVersionWithElasticFoxVersion() throws Exception { MockEC2QueryHandler handler = MockEC2QueryHandler.getInstance(); RunInstancesResponseType runInstancesResponseType = Whitebox.invokeMethod(handler, "runInstances", imageID, - instanceType, minCount, maxCount); + instanceType, minCount, maxCount, SUBNET_ID); String xml = JAXBUtil.marshall(runInstancesResponseType, "RunInstancesResponse", PropertiesUtils