1818
1919import  java .lang .annotation .Retention ;
2020import  java .lang .annotation .RetentionPolicy ;
21+ import  java .util .function .BiConsumer ;
2122
2223import  org .junit .jupiter .api .AfterEach ;
2324import  org .junit .jupiter .api .Test ;
2425import  org .testcontainers .containers .Container ;
26+ import  org .testcontainers .containers .MongoDBContainer ;
2527import  org .testcontainers .containers .PostgreSQLContainer ;
2628
29+ import  org .springframework .aot .test .generate .TestGenerationContext ;
2730import  org .springframework .boot .testcontainers .beans .TestcontainerBeanDefinition ;
2831import  org .springframework .boot .testcontainers .context .ImportTestcontainers ;
32+ import  org .springframework .boot .testcontainers .lifecycle .TestcontainersLifecycleApplicationContextInitializer ;
2933import  org .springframework .boot .testsupport .container .DisabledIfDockerUnavailable ;
3034import  org .springframework .boot .testsupport .container .TestImage ;
35+ import  org .springframework .context .ApplicationContextInitializer ;
3136import  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 ;
3244import  org .springframework .test .context .DynamicPropertyRegistry ;
3345import  org .springframework .test .context .DynamicPropertySource ;
3446
4355@ DisabledIfDockerUnavailable 
4456class  ImportTestcontainersTests  {
4557
58+ 	private  final  TestGenerationContext  generationContext  = new  TestGenerationContext ();
59+ 
4660	private  AnnotationConfigApplicationContext  applicationContext ;
4761
4862	@ AfterEach 
@@ -102,7 +116,7 @@ void importWhenHasNonStaticContainerFieldThrowsException() {
102116	@ Test 
103117	void  importWhenHasContainerDefinitionsWithDynamicPropertySource () {
104118		this .applicationContext  = new  AnnotationConfigApplicationContext (
105- 				ContainerDefinitionsWithDynamicPropertySource .class );
119+ 				ImportWithoutValueWithDynamicPropertySource .class );
106120		assertThat (this .applicationContext .getEnvironment ().containsProperty ("container.port" )).isTrue ();
107121	}
108122
@@ -122,6 +136,119 @@ void importWhenHasBadArgsDynamicPropertySourceMethod() {
122136			.withMessage ("@DynamicPropertySource method 'containerProperties' must be static" );
123137	}
124138
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+ 
125252	@ ImportTestcontainers 
126253	static  class  ImportWithoutValue  {
127254
@@ -161,13 +288,25 @@ interface ContainerDefinitions {
161288
162289	}
163290
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+ 
164303	@ Retention (RetentionPolicy .RUNTIME )
165304	@interface ContainerAnnotation  {
166305
167306	}
168307
169308	@ ImportTestcontainers 
170- 	static  class  ContainerDefinitionsWithDynamicPropertySource  {
309+ 	static  class  ImportWithoutValueWithDynamicPropertySource  {
171310
172311		static  PostgreSQLContainer <?> container  = TestImage .container (PostgreSQLContainer .class );
173312
@@ -196,4 +335,36 @@ void containerProperties() {
196335
197336	}
198337
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+ 
199370}
0 commit comments