18
18
19
19
import java .lang .annotation .Retention ;
20
20
import java .lang .annotation .RetentionPolicy ;
21
+ import java .util .function .BiConsumer ;
21
22
22
23
import org .junit .jupiter .api .AfterEach ;
23
24
import org .junit .jupiter .api .Test ;
24
25
import org .testcontainers .containers .Container ;
26
+ import org .testcontainers .containers .MongoDBContainer ;
25
27
import org .testcontainers .containers .PostgreSQLContainer ;
26
28
29
+ import org .springframework .aot .test .generate .TestGenerationContext ;
27
30
import org .springframework .boot .testcontainers .beans .TestcontainerBeanDefinition ;
28
31
import org .springframework .boot .testcontainers .context .ImportTestcontainers ;
32
+ import org .springframework .boot .testcontainers .lifecycle .TestcontainersLifecycleApplicationContextInitializer ;
29
33
import org .springframework .boot .testsupport .container .DisabledIfDockerUnavailable ;
30
34
import org .springframework .boot .testsupport .container .TestImage ;
35
+ import org .springframework .context .ApplicationContextInitializer ;
31
36
import org .springframework .context .annotation .AnnotationConfigApplicationContext ;
37
+ import org .springframework .context .aot .ApplicationContextAotGenerator ;
38
+ import org .springframework .context .support .GenericApplicationContext ;
39
+ import org .springframework .core .env .ConfigurableEnvironment ;
40
+ import org .springframework .core .test .tools .CompileWithForkedClassLoader ;
41
+ import org .springframework .core .test .tools .Compiled ;
42
+ import org .springframework .core .test .tools .TestCompiler ;
43
+ import org .springframework .javapoet .ClassName ;
32
44
import org .springframework .test .context .DynamicPropertyRegistry ;
33
45
import org .springframework .test .context .DynamicPropertySource ;
34
46
43
55
@ DisabledIfDockerUnavailable
44
56
class ImportTestcontainersTests {
45
57
58
+ private final TestGenerationContext generationContext = new TestGenerationContext ();
59
+
46
60
private AnnotationConfigApplicationContext applicationContext ;
47
61
48
62
@ AfterEach
@@ -102,7 +116,7 @@ void importWhenHasNonStaticContainerFieldThrowsException() {
102
116
@ Test
103
117
void importWhenHasContainerDefinitionsWithDynamicPropertySource () {
104
118
this .applicationContext = new AnnotationConfigApplicationContext (
105
- ContainerDefinitionsWithDynamicPropertySource .class );
119
+ ImportWithoutValueWithDynamicPropertySource .class );
106
120
assertThat (this .applicationContext .getEnvironment ().containsProperty ("container.port" )).isTrue ();
107
121
}
108
122
@@ -122,6 +136,119 @@ void importWhenHasBadArgsDynamicPropertySourceMethod() {
122
136
.withMessage ("@DynamicPropertySource method 'containerProperties' must be static" );
123
137
}
124
138
139
+ @ Test
140
+ @ CompileWithForkedClassLoader
141
+ void importTestcontainersImportWithoutValueAotContribution () {
142
+ this .applicationContext = new AnnotationConfigApplicationContext ();
143
+ this .applicationContext .register (ImportWithoutValue .class );
144
+ compile ((freshContext , compiled ) -> {
145
+ PostgreSQLContainer <?> container = freshContext .getBean (PostgreSQLContainer .class );
146
+ assertThat (container ).isSameAs (ImportWithoutValue .container );
147
+ });
148
+ }
149
+
150
+ @ Test
151
+ @ CompileWithForkedClassLoader
152
+ void importTestcontainersImportWithValueAotContribution () {
153
+ this .applicationContext = new AnnotationConfigApplicationContext ();
154
+ this .applicationContext .register (ImportWithValue .class );
155
+ compile ((freshContext , compiled ) -> {
156
+ PostgreSQLContainer <?> container = freshContext .getBean (PostgreSQLContainer .class );
157
+ assertThat (container ).isSameAs (ContainerDefinitions .container );
158
+ });
159
+ }
160
+
161
+ @ Test
162
+ @ CompileWithForkedClassLoader
163
+ void importTestcontainersImportWithoutValueWithDynamicPropertySourceAotContribution () {
164
+ this .applicationContext = new AnnotationConfigApplicationContext ();
165
+ this .applicationContext .register (ImportWithoutValueWithDynamicPropertySource .class );
166
+ compile ((freshContext , compiled ) -> {
167
+ PostgreSQLContainer <?> container = freshContext .getBean (PostgreSQLContainer .class );
168
+ assertThat (container ).isSameAs (ImportWithoutValueWithDynamicPropertySource .container );
169
+ assertThat (freshContext .getEnvironment ().getProperty ("container.port" , Integer .class ))
170
+ .isEqualTo (ImportWithoutValueWithDynamicPropertySource .container .getFirstMappedPort ());
171
+ });
172
+ }
173
+
174
+ @ Test
175
+ @ CompileWithForkedClassLoader
176
+ void importTestcontainersCustomPostgreSQLContainerDefinitionsAotContribution () {
177
+ this .applicationContext = new AnnotationConfigApplicationContext ();
178
+ this .applicationContext .register (CustomPostgreSQLContainerDefinitions .class );
179
+ compile ((freshContext , compiled ) -> {
180
+ CustomPostgreSQLContainer container = freshContext .getBean (CustomPostgreSQLContainer .class );
181
+ assertThat (container ).isSameAs (CustomPostgreSQLContainerDefinitions .container );
182
+ });
183
+ }
184
+
185
+ @ Test
186
+ @ CompileWithForkedClassLoader
187
+ void importTestcontainersImportWithoutValueNotAccessibleContainerAndDynamicPropertySourceAotContribution () {
188
+ this .applicationContext = new AnnotationConfigApplicationContext ();
189
+ this .applicationContext .register (ImportWithoutValueNotAccessibleContainerAndDynamicPropertySource .class );
190
+ compile ((freshContext , compiled ) -> {
191
+ MongoDBContainer container = freshContext .getBean (MongoDBContainer .class );
192
+ assertThat (container ).isSameAs (ImportWithoutValueNotAccessibleContainerAndDynamicPropertySource .container );
193
+ assertThat (freshContext .getEnvironment ().getProperty ("mongo.port" , Integer .class )).isEqualTo (
194
+ ImportWithoutValueNotAccessibleContainerAndDynamicPropertySource .container .getFirstMappedPort ());
195
+ });
196
+ }
197
+
198
+ @ Test
199
+ @ CompileWithForkedClassLoader
200
+ void importTestcontainersWithNotAccessibleContainerAndDynamicPropertySourceAotContribution () {
201
+ this .applicationContext = new AnnotationConfigApplicationContext ();
202
+ this .applicationContext .register (ImportWithValueAndDynamicPropertySource .class );
203
+ compile ((freshContext , compiled ) -> {
204
+ PostgreSQLContainer <?> container = freshContext .getBean (PostgreSQLContainer .class );
205
+ assertThat (container ).isSameAs (ContainerDefinitionsWithDynamicPropertySource .container );
206
+ assertThat (freshContext .getEnvironment ().getProperty ("postgres.port" , Integer .class ))
207
+ .isEqualTo (ContainerDefinitionsWithDynamicPropertySource .container .getFirstMappedPort ());
208
+ });
209
+ }
210
+
211
+ @ Test
212
+ @ CompileWithForkedClassLoader
213
+ void importTestcontainersMultipleContainersAndDynamicPropertySourcesAotContribution () {
214
+ this .applicationContext = new AnnotationConfigApplicationContext ();
215
+ this .applicationContext .register (ImportWithoutValueNotAccessibleContainerAndDynamicPropertySource .class );
216
+ this .applicationContext .register (ImportWithValueAndDynamicPropertySource .class );
217
+ compile ((freshContext , compiled ) -> {
218
+ MongoDBContainer mongo = freshContext .getBean (MongoDBContainer .class );
219
+ PostgreSQLContainer <?> postgres = freshContext .getBean (PostgreSQLContainer .class );
220
+ assertThat (mongo ).isSameAs (ImportWithoutValueNotAccessibleContainerAndDynamicPropertySource .container );
221
+ assertThat (postgres ).isSameAs (ContainerDefinitionsWithDynamicPropertySource .container );
222
+ ConfigurableEnvironment environment = freshContext .getEnvironment ();
223
+ assertThat (environment .getProperty ("postgres.port" , Integer .class ))
224
+ .isEqualTo (ContainerDefinitionsWithDynamicPropertySource .container .getFirstMappedPort ());
225
+ assertThat (environment .getProperty ("mongo.port" , Integer .class )).isEqualTo (
226
+ ImportWithoutValueNotAccessibleContainerAndDynamicPropertySource .container .getFirstMappedPort ());
227
+ });
228
+ }
229
+
230
+ @ SuppressWarnings ("unchecked" )
231
+ private void compile (BiConsumer <GenericApplicationContext , Compiled > result ) {
232
+ ClassName className = processAheadOfTime ();
233
+ TestCompiler .forSystem ().with (this .generationContext ).compile ((compiled ) -> {
234
+ try (GenericApplicationContext context = new GenericApplicationContext ()) {
235
+ new TestcontainersLifecycleApplicationContextInitializer ().initialize (context );
236
+ ApplicationContextInitializer <GenericApplicationContext > initializer = compiled
237
+ .getInstance (ApplicationContextInitializer .class , className .toString ());
238
+ initializer .initialize (context );
239
+ context .refresh ();
240
+ result .accept (context , compiled );
241
+ }
242
+ });
243
+ }
244
+
245
+ private ClassName processAheadOfTime () {
246
+ ClassName className = new ApplicationContextAotGenerator ().processAheadOfTime (this .applicationContext ,
247
+ this .generationContext );
248
+ this .generationContext .writeGeneratedContent ();
249
+ return className ;
250
+ }
251
+
125
252
@ ImportTestcontainers
126
253
static class ImportWithoutValue {
127
254
@@ -161,13 +288,25 @@ interface ContainerDefinitions {
161
288
162
289
}
163
290
291
+ private interface ContainerDefinitionsWithDynamicPropertySource {
292
+
293
+ @ ContainerAnnotation
294
+ PostgreSQLContainer <?> container = TestImage .container (PostgreSQLContainer .class );
295
+
296
+ @ DynamicPropertySource
297
+ static void containerProperties (DynamicPropertyRegistry registry ) {
298
+ registry .add ("postgres.port" , container ::getFirstMappedPort );
299
+ }
300
+
301
+ }
302
+
164
303
@ Retention (RetentionPolicy .RUNTIME )
165
304
@interface ContainerAnnotation {
166
305
167
306
}
168
307
169
308
@ ImportTestcontainers
170
- static class ContainerDefinitionsWithDynamicPropertySource {
309
+ static class ImportWithoutValueWithDynamicPropertySource {
171
310
172
311
static PostgreSQLContainer <?> container = TestImage .container (PostgreSQLContainer .class );
173
312
@@ -196,4 +335,36 @@ void containerProperties() {
196
335
197
336
}
198
337
338
+ @ ImportTestcontainers
339
+ static class CustomPostgreSQLContainerDefinitions {
340
+
341
+ private static final CustomPostgreSQLContainer container = new CustomPostgreSQLContainer ();
342
+
343
+ }
344
+
345
+ static class CustomPostgreSQLContainer extends PostgreSQLContainer <CustomPostgreSQLContainer > {
346
+
347
+ CustomPostgreSQLContainer () {
348
+ super ("postgres:14" );
349
+ }
350
+
351
+ }
352
+
353
+ @ ImportTestcontainers
354
+ static class ImportWithoutValueNotAccessibleContainerAndDynamicPropertySource {
355
+
356
+ private static final MongoDBContainer container = TestImage .container (MongoDBContainer .class );
357
+
358
+ @ DynamicPropertySource
359
+ private static void containerProperties (DynamicPropertyRegistry registry ) {
360
+ registry .add ("mongo.port" , container ::getFirstMappedPort );
361
+ }
362
+
363
+ }
364
+
365
+ @ ImportTestcontainers (ContainerDefinitionsWithDynamicPropertySource .class )
366
+ static class ImportWithValueAndDynamicPropertySource {
367
+
368
+ }
369
+
199
370
}
0 commit comments