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 ;
25
26
import org .testcontainers .containers .PostgreSQLContainer ;
26
27
28
+ import org .springframework .aot .test .generate .TestGenerationContext ;
27
29
import org .springframework .boot .testcontainers .beans .TestcontainerBeanDefinition ;
28
30
import org .springframework .boot .testcontainers .context .ImportTestcontainers ;
31
+ import org .springframework .boot .testcontainers .lifecycle .TestcontainersLifecycleApplicationContextInitializer ;
29
32
import org .springframework .boot .testsupport .container .DisabledIfDockerUnavailable ;
30
33
import org .springframework .boot .testsupport .container .TestImage ;
34
+ import org .springframework .context .ApplicationContextInitializer ;
31
35
import org .springframework .context .annotation .AnnotationConfigApplicationContext ;
36
+ import org .springframework .context .aot .ApplicationContextAotGenerator ;
37
+ import org .springframework .context .support .GenericApplicationContext ;
38
+ import org .springframework .core .test .tools .CompileWithForkedClassLoader ;
39
+ import org .springframework .core .test .tools .Compiled ;
40
+ import org .springframework .core .test .tools .TestCompiler ;
41
+ import org .springframework .javapoet .ClassName ;
32
42
import org .springframework .test .context .DynamicPropertyRegistry ;
33
43
import org .springframework .test .context .DynamicPropertySource ;
34
44
43
53
@ DisabledIfDockerUnavailable
44
54
class ImportTestcontainersTests {
45
55
56
+ private final TestGenerationContext generationContext = new TestGenerationContext ();
57
+
46
58
private AnnotationConfigApplicationContext applicationContext ;
47
59
48
60
@ AfterEach
@@ -102,7 +114,7 @@ void importWhenHasNonStaticContainerFieldThrowsException() {
102
114
@ Test
103
115
void importWhenHasContainerDefinitionsWithDynamicPropertySource () {
104
116
this .applicationContext = new AnnotationConfigApplicationContext (
105
- ContainerDefinitionsWithDynamicPropertySource .class );
117
+ ImportWithoutValueWithDynamicPropertySource .class );
106
118
assertThat (this .applicationContext .getEnvironment ().containsProperty ("container.port" )).isTrue ();
107
119
}
108
120
@@ -122,6 +134,100 @@ void importWhenHasBadArgsDynamicPropertySourceMethod() {
122
134
.withMessage ("@DynamicPropertySource method 'containerProperties' must be static" );
123
135
}
124
136
137
+ @ Test
138
+ @ CompileWithForkedClassLoader
139
+ void importTestcontainersImportWithoutValueAotContribution () {
140
+ this .applicationContext = new AnnotationConfigApplicationContext ();
141
+ this .applicationContext .register (ImportWithoutValue .class );
142
+ compile ((freshContext , compiled ) -> {
143
+ PostgreSQLContainer <?> container = freshContext .getBean (PostgreSQLContainer .class );
144
+ assertThat (container ).isSameAs (ImportWithoutValue .container );
145
+ });
146
+ }
147
+
148
+ @ Test
149
+ @ CompileWithForkedClassLoader
150
+ void importTestcontainersImportWithValueAotContribution () {
151
+ this .applicationContext = new AnnotationConfigApplicationContext ();
152
+ this .applicationContext .register (ImportWithValue .class );
153
+ compile ((freshContext , compiled ) -> {
154
+ PostgreSQLContainer <?> container = freshContext .getBean (PostgreSQLContainer .class );
155
+ assertThat (container ).isSameAs (ContainerDefinitions .container );
156
+ });
157
+ }
158
+
159
+ @ Test
160
+ @ CompileWithForkedClassLoader
161
+ void importTestcontainersImportWithoutValueWithDynamicPropertySourceAotContribution () {
162
+ this .applicationContext = new AnnotationConfigApplicationContext ();
163
+ this .applicationContext .register (ImportWithoutValueWithDynamicPropertySource .class );
164
+ compile ((freshContext , compiled ) -> {
165
+ PostgreSQLContainer <?> container = freshContext .getBean (PostgreSQLContainer .class );
166
+ assertThat (container ).isSameAs (ImportWithoutValueWithDynamicPropertySource .container );
167
+ assertThat (freshContext .getEnvironment ().getProperty ("container.port" , Integer .class ))
168
+ .isEqualTo (ImportWithoutValueWithDynamicPropertySource .container .getFirstMappedPort ());
169
+ });
170
+ }
171
+
172
+ @ Test
173
+ @ CompileWithForkedClassLoader
174
+ void importTestcontainersCustomPostgreSQLContainerDefinitionsAotContribution () {
175
+ this .applicationContext = new AnnotationConfigApplicationContext ();
176
+ this .applicationContext .register (CustomPostgreSQLContainerDefinitions .class );
177
+ compile ((freshContext , compiled ) -> {
178
+ CustomPostgreSQLContainer container = freshContext .getBean (CustomPostgreSQLContainer .class );
179
+ assertThat (container ).isSameAs (CustomPostgreSQLContainerDefinitions .container );
180
+ });
181
+ }
182
+
183
+ @ Test
184
+ @ CompileWithForkedClassLoader
185
+ void importTestcontainersImportWithoutValueNotAccessibleContainerAndDynamicPropertySourceAotContribution () {
186
+ this .applicationContext = new AnnotationConfigApplicationContext ();
187
+ this .applicationContext .register (ImportWithoutValueNotAccessibleContainerAndDynamicPropertySource .class );
188
+ compile ((freshContext , compiled ) -> {
189
+ PostgreSQLContainer <?> container = freshContext .getBean (PostgreSQLContainer .class );
190
+ assertThat (container ).isSameAs (ImportWithoutValueNotAccessibleContainerAndDynamicPropertySource .container );
191
+ assertThat (freshContext .getEnvironment ().getProperty ("container.port" , Integer .class )).isEqualTo (
192
+ ImportWithoutValueNotAccessibleContainerAndDynamicPropertySource .container .getFirstMappedPort ());
193
+ });
194
+ }
195
+
196
+ @ Test
197
+ @ CompileWithForkedClassLoader
198
+ void importTestcontainersWithNotAccessibleContainerAndDynamicPropertySourceAotContribution () {
199
+ this .applicationContext = new AnnotationConfigApplicationContext ();
200
+ this .applicationContext .register (ImportWithValueAndDynamicPropertySource .class );
201
+ compile ((freshContext , compiled ) -> {
202
+ PostgreSQLContainer <?> container = freshContext .getBean (PostgreSQLContainer .class );
203
+ assertThat (container ).isSameAs (ContainerDefinitionsWithDynamicPropertySource .container );
204
+ assertThat (freshContext .getEnvironment ().getProperty ("container.port" , Integer .class ))
205
+ .isEqualTo (ContainerDefinitionsWithDynamicPropertySource .container .getFirstMappedPort ());
206
+ });
207
+ }
208
+
209
+ @ SuppressWarnings ("unchecked" )
210
+ private void compile (BiConsumer <GenericApplicationContext , Compiled > result ) {
211
+ ClassName className = processAheadOfTime ();
212
+ TestCompiler .forSystem ().with (this .generationContext ).compile ((compiled ) -> {
213
+ try (GenericApplicationContext context = new GenericApplicationContext ()) {
214
+ new TestcontainersLifecycleApplicationContextInitializer ().initialize (context );
215
+ ApplicationContextInitializer <GenericApplicationContext > initializer = compiled
216
+ .getInstance (ApplicationContextInitializer .class , className .toString ());
217
+ initializer .initialize (context );
218
+ context .refresh ();
219
+ result .accept (context , compiled );
220
+ }
221
+ });
222
+ }
223
+
224
+ private ClassName processAheadOfTime () {
225
+ ClassName className = new ApplicationContextAotGenerator ().processAheadOfTime (this .applicationContext ,
226
+ this .generationContext );
227
+ this .generationContext .writeGeneratedContent ();
228
+ return className ;
229
+ }
230
+
125
231
@ ImportTestcontainers
126
232
static class ImportWithoutValue {
127
233
@@ -161,13 +267,25 @@ interface ContainerDefinitions {
161
267
162
268
}
163
269
270
+ private interface ContainerDefinitionsWithDynamicPropertySource {
271
+
272
+ @ ContainerAnnotation
273
+ PostgreSQLContainer <?> container = TestImage .container (PostgreSQLContainer .class );
274
+
275
+ @ DynamicPropertySource
276
+ static void containerProperties (DynamicPropertyRegistry registry ) {
277
+ registry .add ("container.port" , container ::getFirstMappedPort );
278
+ }
279
+
280
+ }
281
+
164
282
@ Retention (RetentionPolicy .RUNTIME )
165
283
@interface ContainerAnnotation {
166
284
167
285
}
168
286
169
287
@ ImportTestcontainers
170
- static class ContainerDefinitionsWithDynamicPropertySource {
288
+ static class ImportWithoutValueWithDynamicPropertySource {
171
289
172
290
static PostgreSQLContainer <?> container = TestImage .container (PostgreSQLContainer .class );
173
291
@@ -196,4 +314,36 @@ void containerProperties() {
196
314
197
315
}
198
316
317
+ @ ImportTestcontainers
318
+ static class CustomPostgreSQLContainerDefinitions {
319
+
320
+ private static final CustomPostgreSQLContainer container = new CustomPostgreSQLContainer ();
321
+
322
+ }
323
+
324
+ static class CustomPostgreSQLContainer extends PostgreSQLContainer <CustomPostgreSQLContainer > {
325
+
326
+ CustomPostgreSQLContainer () {
327
+ super ("postgres:14" );
328
+ }
329
+
330
+ }
331
+
332
+ @ ImportTestcontainers
333
+ static class ImportWithoutValueNotAccessibleContainerAndDynamicPropertySource {
334
+
335
+ private static final PostgreSQLContainer <?> container = TestImage .container (PostgreSQLContainer .class );
336
+
337
+ @ DynamicPropertySource
338
+ private static void containerProperties (DynamicPropertyRegistry registry ) {
339
+ registry .add ("container.port" , container ::getFirstMappedPort );
340
+ }
341
+
342
+ }
343
+
344
+ @ ImportTestcontainers (ContainerDefinitionsWithDynamicPropertySource .class )
345
+ static class ImportWithValueAndDynamicPropertySource {
346
+
347
+ }
348
+
199
349
}
0 commit comments