Skip to content

Commit a3c784d

Browse files
authored
Code refactoring to add support for AWS SDK v2; add SNS integration test using SDK v2 (localstack#16)
1 parent 8c772e6 commit a3c784d

23 files changed

+336
-134
lines changed

pom.xml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,12 @@
8888
<artifactId>aws-java-sdk</artifactId>
8989
<version>${aws.sdk.version}</version>
9090
<scope>provided</scope>
91+
<exclusions>
92+
<exclusion>
93+
<groupId>com.amazonaws</groupId>
94+
<artifactId>aws-java-sdk-kinesisvideo</artifactId>
95+
</exclusion>
96+
</exclusions>
9197
</dependency>
9298
<dependency>
9399
<groupId>com.amazonaws</groupId>
@@ -115,6 +121,28 @@
115121
<version>${aws.sdk.version}</version>
116122
</dependency>
117123

124+
<!-- AWS SDK version 2 libs -->
125+
<dependency>
126+
<groupId>software.amazon.awssdk</groupId>
127+
<artifactId>sns</artifactId>
128+
<version>2.13.36</version>
129+
</dependency>
130+
<dependency>
131+
<groupId>software.amazon.awssdk</groupId>
132+
<artifactId>sqs</artifactId>
133+
<version>2.13.36</version>
134+
</dependency>
135+
<dependency>
136+
<groupId>software.amazon.awssdk</groupId>
137+
<artifactId>kinesis</artifactId>
138+
<version>2.13.36</version>
139+
</dependency>
140+
<dependency>
141+
<groupId>software.amazon.awssdk</groupId>
142+
<artifactId>netty-nio-client</artifactId>
143+
<version>2.13.36</version>
144+
</dependency>
145+
118146

119147
<!-- test dependencies -->
120148
<dependency>
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
package cloud.localstack;
2+
3+
import cloud.localstack.Constants;
4+
import cloud.localstack.Localstack;
5+
6+
import java.io.*;
7+
import java.nio.file.*;
8+
import java.util.*;
9+
import java.lang.reflect.Field;
10+
import java.nio.channels.FileChannel;
11+
import java.util.stream.Stream;
12+
13+
/**
14+
* Common utility methods
15+
*/
16+
public class CommonUtils {
17+
18+
private static final String[] EXCLUDED_DIRECTORIES = {
19+
".github", ".git", ".idea", ".venv", "target", "node_modules"
20+
};
21+
22+
public static void disableSslCertChecking() {
23+
System.setProperty("com.amazonaws.sdk.disableCertChecking", "true");
24+
}
25+
26+
public static void setEnv(String key, String value) {
27+
Map<String, String> newEnv = new HashMap<String, String>(System.getenv());
28+
newEnv.put(key, value);
29+
setEnv(newEnv);
30+
}
31+
32+
protected static void setEnv(Map<String, String> newEnv) {
33+
try {
34+
Class<?> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
35+
Field theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment");
36+
theEnvironmentField.setAccessible(true);
37+
Map<String, String> env = (Map<String, String>) theEnvironmentField.get(null);
38+
env.putAll(newEnv);
39+
Field theCaseInsensitiveEnvironmentField = processEnvironmentClass
40+
.getDeclaredField("theCaseInsensitiveEnvironment");
41+
theCaseInsensitiveEnvironmentField.setAccessible(true);
42+
Map<String, String> cienv = (Map<String, String>) theCaseInsensitiveEnvironmentField.get(null);
43+
cienv.putAll(newEnv);
44+
} catch (NoSuchFieldException e) {
45+
try {
46+
Class[] classes = Collections.class.getDeclaredClasses();
47+
Map<String, String> env = System.getenv();
48+
for (Class cl : classes) {
49+
if ("java.util.Collections$UnmodifiableMap".equals(cl.getName())) {
50+
Field field = cl.getDeclaredField("m");
51+
field.setAccessible(true);
52+
Object obj = field.get(env);
53+
Map<String, String> map = (Map<String, String>) obj;
54+
map.clear();
55+
map.putAll(newEnv);
56+
}
57+
}
58+
} catch (Exception e2) {
59+
e2.printStackTrace();
60+
}
61+
} catch (Exception e1) {
62+
e1.printStackTrace();
63+
}
64+
}
65+
66+
public static void copyFolder(Path src, Path dest) throws IOException {
67+
try(Stream<Path> stream = Files.walk(src)) {
68+
stream.forEach(source -> {
69+
boolean isExcluded = Arrays.stream(EXCLUDED_DIRECTORIES)
70+
.anyMatch( excluded -> source.toAbsolutePath().toString().contains(excluded));
71+
if (!isExcluded) {
72+
copy(source, dest.resolve(src.relativize(source)));
73+
}
74+
});
75+
}
76+
}
77+
78+
public static void copy(Path source, Path dest) {
79+
try {
80+
CopyOption[] options = new CopyOption[] {StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING};
81+
if(Files.isDirectory(dest)) {
82+
// continue without copying
83+
return;
84+
}
85+
if (Files.exists(dest)) {
86+
try(FileChannel sourceFile = FileChannel.open(source)) {
87+
try (FileChannel destFile = FileChannel.open(dest)) {
88+
if (!Files.getLastModifiedTime(source).equals(Files.getLastModifiedTime(dest))
89+
|| sourceFile.size() != destFile.size()
90+
) {
91+
Files.copy(source, dest, options);
92+
}
93+
}
94+
}
95+
} else {
96+
Files.copy(source, dest, options);
97+
}
98+
} catch (Exception e) {
99+
throw new RuntimeException(e.getMessage(), e);
100+
}
101+
}
102+
}

src/main/java/cloud/localstack/Constants.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ public class Constants {
88

99
public static final String LOCALHOST_DOMAIN_NAME = "localhost.localstack.cloud";
1010

11+
public static final String DEFAULT_REGION = "us-east-1";
12+
public static final String TEST_ACCESS_KEY = "test";
13+
public static final String TEST_SECRET_KEY = "test";
14+
1115
static {
1216
DEFAULT_PORTS.put("apigateway", 4567);
1317
DEFAULT_PORTS.put("kinesis", 4568);
@@ -34,4 +38,5 @@ public class Constants {
3438
DEFAULT_PORTS.put("ec2", 4597);
3539
DEFAULT_PORTS.put("kms", 4599);
3640
}
41+
3742
}

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import cloud.localstack.Constants;
44
import cloud.localstack.ServiceName;
5+
import cloud.localstack.CommonUtils;
56
import cloud.localstack.docker.*;
67
import cloud.localstack.docker.command.*;
78
import cloud.localstack.docker.annotation.LocalstackDockerConfiguration;
@@ -54,7 +55,7 @@ public class Localstack {
5455

5556
static {
5657
// make sure we avoid any errors related to locally generated SSL certificates
57-
TestUtils.disableSslCertChecking();
58+
CommonUtils.disableSslCertChecking();
5859
}
5960

6061
private Localstack() { }
@@ -237,6 +238,6 @@ public static boolean isEnvConfigSet(String configName) {
237238
}
238239

239240
public static String getDefaultRegion() {
240-
return TestUtils.DEFAULT_REGION;
241+
return Constants.DEFAULT_REGION;
241242
}
242243
}

src/main/java/cloud/localstack/TestUtils.java renamed to src/main/java/cloud/localstack/awssdkv1/TestUtils.java

Lines changed: 11 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package cloud.localstack;
1+
package cloud.localstack.awssdkv1;
22

33
import com.amazonaws.auth.AWSCredentials;
44
import com.amazonaws.auth.AWSCredentialsProvider;
@@ -33,36 +33,16 @@
3333
import com.amazonaws.services.secretsmanager.AWSSecretsManagerClientBuilder;
3434
import com.amazonaws.services.sqs.AmazonSQS;
3535
import com.amazonaws.services.sqs.AmazonSQSClientBuilder;
36-
import java.io.IOException;
37-
import java.lang.reflect.Field;
38-
import java.nio.channels.FileChannel;
39-
import java.nio.file.CopyOption;
40-
import java.nio.file.Files;
41-
import java.nio.file.Path;
42-
import java.nio.file.StandardCopyOption;
43-
import java.util.Arrays;
44-
import java.util.Collections;
45-
import java.util.HashMap;
46-
import java.util.Map;
47-
import java.util.stream.Stream;
36+
37+
import cloud.localstack.Constants;
38+
import cloud.localstack.Localstack;
39+
import cloud.localstack.CommonUtils;
4840

4941
@SuppressWarnings("all")
5042
public class TestUtils {
5143

52-
public static final String DEFAULT_REGION = "us-east-1";
53-
public static final String TEST_ACCESS_KEY = "test";
54-
public static final String TEST_SECRET_KEY = "test";
55-
public static final AWSCredentials TEST_CREDENTIALS = new BasicAWSCredentials(TEST_ACCESS_KEY, TEST_SECRET_KEY);
56-
57-
private static final String[] EXCLUDED_DIRECTORIES = {
58-
".github", ".git", ".idea", ".venv", "target", "node_modules"
59-
};
60-
61-
public static void setEnv(String key, String value) {
62-
Map<String, String> newEnv = new HashMap<String, String>(System.getenv());
63-
newEnv.put(key, value);
64-
setEnv(newEnv);
65-
}
44+
public static final AWSCredentials TEST_CREDENTIALS = new BasicAWSCredentials(
45+
Constants.TEST_ACCESS_KEY, Constants.TEST_SECRET_KEY);
6646

6747
public static AmazonSQS getClientSQS() {
6848
return getClientSQS(null);
@@ -227,87 +207,16 @@ protected static AwsClientBuilder.EndpointConfiguration getEndpointConfiguration
227207
return getEndpointConfiguration(Localstack.INSTANCE.getEndpointStepFunctions());
228208
}
229209

230-
protected static void setEnv(Map<String, String> newEnv) {
231-
try {
232-
Class<?> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
233-
Field theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment");
234-
theEnvironmentField.setAccessible(true);
235-
Map<String, String> env = (Map<String, String>) theEnvironmentField.get(null);
236-
env.putAll(newEnv);
237-
Field theCaseInsensitiveEnvironmentField = processEnvironmentClass
238-
.getDeclaredField("theCaseInsensitiveEnvironment");
239-
theCaseInsensitiveEnvironmentField.setAccessible(true);
240-
Map<String, String> cienv = (Map<String, String>) theCaseInsensitiveEnvironmentField.get(null);
241-
cienv.putAll(newEnv);
242-
} catch (NoSuchFieldException e) {
243-
try {
244-
Class[] classes = Collections.class.getDeclaredClasses();
245-
Map<String, String> env = System.getenv();
246-
for (Class cl : classes) {
247-
if ("java.util.Collections$UnmodifiableMap".equals(cl.getName())) {
248-
Field field = cl.getDeclaredField("m");
249-
field.setAccessible(true);
250-
Object obj = field.get(env);
251-
Map<String, String> map = (Map<String, String>) obj;
252-
map.clear();
253-
map.putAll(newEnv);
254-
}
255-
}
256-
} catch (Exception e2) {
257-
e2.printStackTrace();
258-
}
259-
} catch (Exception e1) {
260-
e1.printStackTrace();
261-
}
262-
}
263-
264-
public static void disableSslCertChecking() {
265-
System.setProperty("com.amazonaws.sdk.disableCertChecking", "true");
266-
}
267-
268-
public static void copyFolder(Path src, Path dest) throws IOException {
269-
try(Stream<Path> stream = Files.walk(src)) {
270-
stream.forEach(source -> {
271-
boolean isExcluded = Arrays.stream(EXCLUDED_DIRECTORIES)
272-
.anyMatch( excluded -> source.toAbsolutePath().toString().contains(excluded));
273-
if (!isExcluded) {
274-
copy(source, dest.resolve(src.relativize(source)));
275-
}
276-
});
277-
}
278-
}
279-
280-
public static void copy(Path source, Path dest) {
281-
try {
282-
CopyOption[] options = new CopyOption[] {StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING};
283-
if(Files.isDirectory(dest)) {
284-
// continue without copying
285-
return;
286-
}
287-
if (Files.exists(dest)) {
288-
try(FileChannel sourceFile = FileChannel.open(source)) {
289-
try (FileChannel destFile = FileChannel.open(dest)) {
290-
if (!Files.getLastModifiedTime(source).equals(Files.getLastModifiedTime(dest))
291-
|| sourceFile.size() != destFile.size()
292-
) {
293-
Files.copy(source, dest, options);
294-
}
295-
}
296-
}
297-
} else {
298-
Files.copy(source, dest, options);
299-
}
300-
} catch (Exception e) {
301-
throw new RuntimeException(e.getMessage(), e);
302-
}
303-
}
210+
/**
211+
* UTIL METHODS
212+
*/
304213

305214
public static AWSCredentialsProvider getCredentialsProvider() {
306215
return new AWSStaticCredentialsProvider(TEST_CREDENTIALS);
307216
}
308217

309218
protected static AwsClientBuilder.EndpointConfiguration getEndpointConfiguration(String endpointURL) {
310-
return new AwsClientBuilder.EndpointConfiguration(endpointURL, DEFAULT_REGION);
219+
return new AwsClientBuilder.EndpointConfiguration(endpointURL, Constants.DEFAULT_REGION);
311220
}
312221

313222
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package cloud.localstack.awssdkv2;
2+
3+
import software.amazon.awssdk.regions.Region;
4+
import software.amazon.awssdk.utils.*;
5+
import software.amazon.awssdk.http.*;
6+
import software.amazon.awssdk.services.kinesis.*;
7+
import software.amazon.awssdk.services.sns.*;
8+
import software.amazon.awssdk.services.sqs.*;
9+
import software.amazon.awssdk.http.nio.netty.NettyNioAsyncHttpClient;
10+
11+
import cloud.localstack.Localstack;
12+
13+
import java.net.*;
14+
15+
@SuppressWarnings("all")
16+
public class TestUtils {
17+
18+
/**
19+
* AWS SDK V2 METHODS
20+
*/
21+
22+
public static KinesisAsyncClient getClientKinesisAsyncV2() {
23+
return wrapApiClientV2(KinesisAsyncClient.builder(), Localstack.INSTANCE.getEndpointKinesis()).build();
24+
}
25+
26+
public static SqsAsyncClient getClientSQSAsyncV2() {
27+
return wrapApiClientV2(SqsAsyncClient.builder(), Localstack.INSTANCE.getEndpointSQS()).build();
28+
}
29+
30+
public static SnsAsyncClient getClientSNSAsyncV2() {
31+
return wrapApiClientV2(SnsAsyncClient.builder(), Localstack.INSTANCE.getEndpointSNS()).build();
32+
}
33+
34+
public static <T extends software.amazon.awssdk.core.client.builder.SdkAsyncClientBuilder> T wrapApiClientV2(T builder, String endpointURL) {
35+
try {
36+
return (T) ((software.amazon.awssdk.awscore.client.builder.AwsClientBuilder)builder
37+
.httpClient(NettyNioAsyncHttpClient.builder().buildWithDefaults(
38+
AttributeMap.builder().put(
39+
SdkHttpConfigurationOption.TRUST_ALL_CERTIFICATES, java.lang.Boolean.TRUE).build())))
40+
.credentialsProvider(getCredentialsV2())
41+
.region(Region.of(Localstack.INSTANCE.getDefaultRegion()))
42+
.endpointOverride(new URI(endpointURL));
43+
} catch (Exception e) {
44+
throw new RuntimeException(e);
45+
}
46+
}
47+
48+
private static software.amazon.awssdk.auth.credentials.AwsCredentialsProvider getCredentialsV2() throws Exception {
49+
return software.amazon.awssdk.auth.credentials.StaticCredentialsProvider.create(
50+
software.amazon.awssdk.auth.credentials.AwsBasicCredentials.create("access", "secret"));
51+
}
52+
53+
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import cloud.localstack.Constants;
2323
import cloud.localstack.ServiceName;
24+
import cloud.localstack.CommonUtils;
2425

2526
/**
2627
* Singleton class that automatically downloads, installs, starts,
@@ -385,7 +386,7 @@ public void setupInfrastructure() {
385386
ensureInstallation(true);
386387

387388
// make sure we avoid any errors related to locally generated SSL certificates
388-
TestUtils.disableSslCertChecking();
389+
CommonUtils.disableSslCertChecking();
389390

390391
if (INFRA_STARTED.get() != null) return;
391392
String[] cmd = new String[]{"make", "-C", TMP_INSTALL_DIR, "infra"};

0 commit comments

Comments
 (0)