Skip to content

Commit 1b8ccde

Browse files
committed
add test to assert EntityAlreadyExistsException for IAM roles
1 parent 73065f6 commit 1b8ccde

File tree

6 files changed

+36
-14
lines changed

6 files changed

+36
-14
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ publish-maven: ## Publish artifacts to Maven Central
1010
ADDITIONAL_MVN_TARGETS=deploy ADDITIONAL_MVN_ARGS=" " make build
1111

1212
test: ## Run tests for Java/JUnit compatibility
13-
USE_SSL=1 SERVICES=serverless,kinesis,sns,sqs,cloudwatch mvn $(MVN_ARGS) test
13+
USE_SSL=1 SERVICES=serverless,kinesis,sns,sqs,iam,cloudwatch mvn $(MVN_ARGS) test
1414

1515
.PHONY: usage clean install test

src/main/java/cloud/localstack/Localstack.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,10 @@ public String getEndpointStepFunctions() {
195195
return endpointForService(ServiceName.STEPFUNCTIONS);
196196
}
197197

198+
public String getEndpointIAM() {
199+
return endpointForService(ServiceName.IAM);
200+
}
201+
198202
public String endpointForService(String serviceName) {
199203
if (serviceToPortMap == null) {
200204
throw new IllegalStateException("Service to port mapping has not been determined yet.");

src/main/java/cloud/localstack/ServiceName.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,5 @@ public class ServiceName {
2121
public static final String SECRETSMANAGER = "secretsmanager";
2222
public static final String STEPFUNCTIONS = "stepfunctions";
2323
public static final String EC2 = "ec2";
24-
24+
public static final String IAM = "iam";
2525
}

src/main/java/cloud/localstack/TestUtils.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
1313
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBStreams;
1414
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBStreamsClientBuilder;
15+
import com.amazonaws.services.identitymanagement.AmazonIdentityManagement;
16+
import com.amazonaws.services.identitymanagement.AmazonIdentityManagementClientBuilder;
1517
import com.amazonaws.services.kinesis.AmazonKinesis;
1618
import com.amazonaws.services.kinesis.AmazonKinesisAsync;
1719
import com.amazonaws.services.kinesis.AmazonKinesisAsyncClientBuilder;
@@ -175,6 +177,16 @@ public static AmazonCloudWatch getClientCloudWatch() {
175177
withCredentials(getCredentialsProvider()).build();
176178
}
177179

180+
public static AmazonIdentityManagement getClientIAM() {
181+
return AmazonIdentityManagementClientBuilder.standard().
182+
withEndpointConfiguration(getEndpointConfigurationIAM()).
183+
withCredentials(getCredentialsProvider()).build();
184+
}
185+
186+
protected static AwsClientBuilder.EndpointConfiguration getEndpointConfigurationIAM() {
187+
return getEndpointConfiguration(Localstack.INSTANCE.getEndpointIAM());
188+
}
189+
178190
protected static AwsClientBuilder.EndpointConfiguration getEndpointConfigurationLambda() {
179191
return getEndpointConfiguration(Localstack.INSTANCE.getEndpointLambda());
180192
}

src/main/java/cloud/localstack/docker/Container.java

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public class Container {
2222
private static final Logger LOG = Logger.getLogger(Container.class.getName());
2323

2424
private static final String LOCALSTACK_NAME = "localstack/localstack";
25-
private static final String LOCALSTACK_PORTS = "4567-4584";
25+
private static final String LOCALSTACK_PORTS = "4566-4593";
2626

2727
private static final int MAX_PORT_CONNECTION_ATTEMPTS = 10;
2828

@@ -92,13 +92,11 @@ public static Container getRunningLocalstackContainer(String containerId) {
9292
return new Container(containerId, portMappingsList);
9393
}
9494

95-
9695
private Container(String containerId, List<PortMapping> ports) {
9796
this.containerId = containerId;
9897
this.ports = Collections.unmodifiableList(ports);
9998
}
10099

101-
102100
/**
103101
* Given an internal port, retrieve the publicly addressable port that maps to it
104102
*/
@@ -110,12 +108,10 @@ public int getExternalPortFor(int internalPort) {
110108
.orElseThrow(() -> new IllegalArgumentException("Port: " + internalPort + " does not exist"));
111109
}
112110

113-
114111
public void waitForAllPorts(String ip) {
115112
ports.forEach(port -> waitForPort(ip, port));
116113
}
117114

118-
119115
private void waitForPort(String ip, PortMapping port) {
120116
int attempts = 0;
121117
do {
@@ -129,7 +125,6 @@ private void waitForPort(String ip, PortMapping port) {
129125
throw new IllegalStateException("Could not open port:" + port.getExternalPort() + " on ip:" + port.getIp());
130126
}
131127

132-
133128
private boolean isPortOpen(String ip, PortMapping port) {
134129
try (Socket socket = new Socket()) {
135130
socket.connect(new InetSocketAddress(ip, port.getExternalPort()), 1000);
@@ -139,7 +134,6 @@ private boolean isPortOpen(String ip, PortMapping port) {
139134
}
140135
}
141136

142-
143137
/**
144138
* Poll the docker logs until a specific token appears, then return. Primarily
145139
* used to look for the "Ready." token in the LocalStack logs.
@@ -159,18 +153,15 @@ public void waitForLogToken(Pattern pattern) {
159153
throw new IllegalStateException("Could not find token: " + pattern + " in Docker logs: " + logs);
160154
}
161155

162-
163156
private boolean logContainsPattern(Pattern pattern) {
164157
String logs = getContainerLogs();
165158
return pattern.matcher(logs).find();
166159
}
167160

168-
169161
private String getContainerLogs() {
170162
return new LogCommand(containerId).withNumberOfLines(NUM_LOG_LINES).execute();
171163
}
172164

173-
174165
private void waitForLogs(){
175166
try {
176167
Thread.sleep(POLL_INTERVAL);
@@ -180,7 +171,6 @@ private void waitForLogs(){
180171
}
181172
}
182173

183-
184174
/**
185175
* Stop the container
186176
*/
@@ -192,7 +182,6 @@ public void stop() {
192182
LOG.info("Stopped container: " + containerId);
193183
}
194184

195-
196185
/**
197186
* Run a command on the container via docker exec
198187
*/

src/test/java/cloud/localstack/docker/BasicDockerFunctionalityTest.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
import com.amazonaws.auth.AWSStaticCredentialsProvider;
1010
import com.amazonaws.services.cloudwatch.*;
1111
import com.amazonaws.services.cloudwatch.model.*;
12+
import com.amazonaws.services.identitymanagement.AmazonIdentityManagement;
13+
import com.amazonaws.services.identitymanagement.model.CreateRoleRequest;
14+
import com.amazonaws.services.identitymanagement.model.EntityAlreadyExistsException;
1215
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
1316
import com.amazonaws.services.dynamodbv2.model.AttributeDefinition;
1417
import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
@@ -203,6 +206,20 @@ public void testCloudWatch() throws Exception {
203206
Assert.assertNotNull(response);
204207
}
205208

209+
@org.junit.Test
210+
@org.junit.jupiter.api.Test
211+
public void testCreateDuplicateRoleException() {
212+
AmazonIdentityManagement iamClient = TestUtils.getClientIAM();
213+
try {
214+
CreateRoleRequest request = new CreateRoleRequest().withRoleName("role1234");
215+
iamClient.createRole(request);
216+
iamClient.createRole(request);
217+
throw new RuntimeException("EntityAlreadyExistsException should be thrown");
218+
} catch (EntityAlreadyExistsException e) {
219+
// this exception is expected here
220+
}
221+
}
222+
206223
private SQSConnection createSQSConnection() throws Exception {
207224
SQSConnectionFactory connectionFactory = SQSConnectionFactory.builder().withEndpoint(
208225
Localstack.INSTANCE.getEndpointSQS()).withAWSCredentialsProvider(

0 commit comments

Comments
 (0)