4
4
import com .amazonaws .auth .AWSStaticCredentialsProvider ;
5
5
import com .amazonaws .auth .BasicAWSCredentials ;
6
6
import com .amazonaws .client .builder .AwsClientBuilder ;
7
- import org .jetbrains .annotations .Nullable ;
8
- import org .junit .rules .ExternalResource ;
7
+ import lombok .Getter ;
8
+ import lombok .RequiredArgsConstructor ;
9
+ import lombok .experimental .FieldDefaults ;
9
10
import org .rnorth .ducttape .Preconditions ;
10
11
import org .testcontainers .containers .GenericContainer ;
11
- import org .testcontainers .containers .wait .LogMessageWaitStrategy ;
12
+ import org .testcontainers .containers .wait .strategy . Wait ;
12
13
13
14
import java .net .InetAddress ;
14
15
import java .net .UnknownHostException ;
16
+ import java .util .ArrayList ;
15
17
import java .util .Arrays ;
18
+ import java .util .List ;
16
19
import java .util .stream .Collectors ;
17
20
18
- import static org .testcontainers .containers .BindMode .READ_WRITE ;
19
-
20
21
/**
21
22
* <p>Container for Atlassian Labs Localstack, 'A fully functional local AWS cloud stack'.</p>
22
23
* <p>{@link LocalStackContainer#withServices(Service...)} should be used to select which services
25
26
* {@link LocalStackContainer#getDefaultCredentialsProvider()}
26
27
* be used to obtain compatible endpoint configuration and credentials, respectively.</p>
27
28
*/
28
- public class LocalStackContainer extends ExternalResource {
29
-
30
- @ Nullable private GenericContainer delegate ;
31
- private Service [] services ;
32
-
33
- @ Override
34
- protected void before () throws Throwable {
29
+ public class LocalStackContainer extends GenericContainer <LocalStackContainer > {
35
30
36
- Preconditions . check ( "services list must not be empty" , services != null && services . length > 0 ) ;
31
+ public static final String VERSION = "0.8.6" ;
37
32
38
- final String servicesList = Arrays
39
- .stream (services )
40
- .map (Service ::getLocalStackName )
41
- .collect (Collectors .joining ("," ));
33
+ private final List <Service > services = new ArrayList <>();
42
34
43
- final Integer [] portsList = Arrays
44
- .stream (services )
45
- .map (Service ::getPort )
46
- .collect (Collectors .toSet ()).toArray (new Integer []{});
35
+ public LocalStackContainer () {
36
+ this (VERSION );
37
+ }
47
38
48
- delegate = new GenericContainer ("localstack/localstack:0.8.5" )
49
- .withExposedPorts (portsList )
50
- .withFileSystemBind ("//var/run/docker.sock" , "/var/run/docker.sock" , READ_WRITE )
51
- .waitingFor (new LogMessageWaitStrategy ().withRegEx (".*Ready\\ .\n " ))
52
- .withEnv ("SERVICES" , servicesList );
39
+ public LocalStackContainer (String version ) {
40
+ super ("localstack/localstack:" + version );
53
41
54
- delegate .start ();
42
+ withFileSystemBind ("//var/run/docker.sock" , "/var/run/docker.sock" );
43
+ waitingFor (Wait .forLogMessage (".*Ready\\ .\n " , 1 ));
55
44
}
56
45
57
46
@ Override
58
- protected void after () {
47
+ protected void configure () {
48
+ super .configure ();
49
+
50
+ Preconditions .check ("services list must not be empty" , !services .isEmpty ());
59
51
60
- Preconditions . check ( "delegate must have been created by before()" , delegate != null );
52
+ withEnv ( "SERVICES" , services . stream (). map ( Service :: getLocalStackName ). collect ( Collectors . joining ( "," )) );
61
53
62
- delegate .stop ();
54
+ for (Service service : services ) {
55
+ addExposedPort (service .getPort ());
56
+ }
63
57
}
64
58
65
59
/**
@@ -68,8 +62,8 @@ protected void after() {
68
62
* @return this container object
69
63
*/
70
64
public LocalStackContainer withServices (Service ... services ) {
71
- this .services = services ;
72
- return this ;
65
+ this .services . addAll ( Arrays . asList ( services )) ;
66
+ return self () ;
73
67
}
74
68
75
69
/**
@@ -85,19 +79,14 @@ public LocalStackContainer withServices(Service... services) {
85
79
* @return an {@link AwsClientBuilder.EndpointConfiguration}
86
80
*/
87
81
public AwsClientBuilder .EndpointConfiguration getEndpointConfiguration (Service service ) {
88
-
89
- if (delegate == null ) {
90
- throw new IllegalStateException ("LocalStack has not been started yet!" );
91
- }
92
-
93
- final String address = delegate .getContainerIpAddress ();
82
+ final String address = getContainerIpAddress ();
94
83
String ipAddress = address ;
95
84
try {
96
85
ipAddress = InetAddress .getByName (address ).getHostAddress ();
97
86
} catch (UnknownHostException ignored ) {
98
87
99
88
}
100
- ipAddress = ipAddress + ".xip .io" ;
89
+ ipAddress = ipAddress + ".nip .io" ;
101
90
while (true ) {
102
91
try {
103
92
//noinspection ResultOfMethodCallIgnored
@@ -112,7 +101,7 @@ public AwsClientBuilder.EndpointConfiguration getEndpointConfiguration(Service s
112
101
"http://" +
113
102
ipAddress +
114
103
":" +
115
- delegate . getMappedPort (service .getPort ()), "us-east-1" );
104
+ getMappedPort (service .getPort ()), "us-east-1" );
116
105
}
117
106
118
107
/**
@@ -130,6 +119,9 @@ public AWSCredentialsProvider getDefaultCredentialsProvider() {
130
119
return new AWSStaticCredentialsProvider (new BasicAWSCredentials ("accesskey" , "secretkey" ));
131
120
}
132
121
122
+ @ RequiredArgsConstructor
123
+ @ Getter
124
+ @ FieldDefaults (makeFinal = true )
133
125
public enum Service {
134
126
API_GATEWAY ("apigateway" , 4567 ),
135
127
KINESIS ("kinesis" , 4568 ),
@@ -149,18 +141,8 @@ public enum Service {
149
141
CLOUDFORMATION ("cloudformation" , 4581 ),
150
142
CLOUDWATCH ("cloudwatch" , 4582 );
151
143
152
- private final String localStackName ;
153
- private final int port ;
154
-
155
- Service (String localstackName , int port ) {
156
- this .localStackName = localstackName ;
157
- this .port = port ;
158
- }
159
-
160
- public String getLocalStackName () {
161
- return localStackName ;
162
- }
144
+ String localStackName ;
163
145
164
- public Integer getPort () { return port ; }
146
+ int port ;
165
147
}
166
148
}
0 commit comments