11/*
2- * Copyright 2012-2024 the original author or authors.
2+ * Copyright 2012-2025 the original author or authors.
33 *
44 * Licensed under the Apache License, Version 2.0 (the "License");
55 * you may not use this file except in compliance with the License.
1717package org .springframework .boot .docker .compose .service .connection .test ;
1818
1919import java .io .IOException ;
20+ import java .nio .charset .StandardCharsets ;
2021import java .nio .file .Files ;
2122import java .nio .file .Path ;
2223import java .util .LinkedHashMap ;
3940import org .springframework .context .annotation .Configuration ;
4041import org .springframework .core .io .ClassPathResource ;
4142import org .springframework .core .io .Resource ;
43+ import org .springframework .util .FileSystemUtils ;
4244
4345import static org .assertj .core .api .Assertions .fail ;
4446
4547/**
4648 * {@link Extension} for {@link DockerComposeTest @DockerComposeTest}.
4749 *
4850 * @author Andy Wilkinson
51+ * @author Moritz Halbritter
4952 */
5053class DockerComposeTestExtension implements BeforeTestExecutionCallback , AfterTestExecutionCallback , ParameterResolver {
5154
5255 private static final Namespace NAMESPACE = Namespace .create (DockerComposeTestExtension .class );
5356
54- private static final String STORE_KEY_COMPOSE_FILE = "compose-file " ;
57+ private static final String STORE_KEY_WORKSPACE = "workspace " ;
5558
5659 private static final String STORE_KEY_APPLICATION_CONTEXT = "application-context" ;
5760
5861 @ Override
5962 public void beforeTestExecution (ExtensionContext context ) throws Exception {
60- Path transformedComposeFile = prepareComposeFile (context );
6163 Store store = context .getStore (NAMESPACE );
62- store .put (STORE_KEY_COMPOSE_FILE , transformedComposeFile );
64+ Path workspace = Files .createTempDirectory ("DockerComposeTestExtension-" );
65+ store .put (STORE_KEY_WORKSPACE , workspace );
6366 try {
64- SpringApplication application = prepareApplication (transformedComposeFile );
67+ Path composeFile = prepareComposeFile (workspace , context );
68+ SpringApplication application = prepareApplication (composeFile );
6569 store .put (STORE_KEY_APPLICATION_CONTEXT , application .run ());
6670 }
6771 catch (Exception ex ) {
@@ -70,33 +74,33 @@ public void beforeTestExecution(ExtensionContext context) throws Exception {
7074 }
7175 }
7276
73- private Path prepareComposeFile (ExtensionContext context ) {
77+ private Path prepareComposeFile (Path workspace , ExtensionContext context ) {
7478 DockerComposeTest dockerComposeTest = context .getRequiredTestMethod ().getAnnotation (DockerComposeTest .class );
7579 TestImage image = dockerComposeTest .image ();
7680 Resource composeResource = new ClassPathResource (dockerComposeTest .composeFile (),
7781 context .getRequiredTestClass ());
78- return transformedComposeFile (composeResource , image );
82+ return transformedComposeFile (workspace , composeResource , image );
7983 }
8084
81- private Path transformedComposeFile (Resource composeFileResource , TestImage image ) {
85+ private Path transformedComposeFile (Path workspace , Resource composeFileResource , TestImage image ) {
8286 try {
83- Path composeFile = composeFileResource .getFile (). toPath ( );
84- Path transformedComposeFile = Files . createTempFile ( " " , "-" + composeFile . getFileName () .toString ());
85- String transformedContent = Files . readString ( composeFile ). replace ( "{imageName}" , image . toString () );
86- Files .writeString (transformedComposeFile , transformedContent );
87- return transformedComposeFile ;
87+ String template = composeFileResource .getContentAsString ( StandardCharsets . UTF_8 );
88+ String content = template . replace ( "{imageName} " , image .toString ());
89+ Path composeFile = workspace . resolve ( "compose.yaml" );
90+ Files .writeString (composeFile , content );
91+ return composeFile ;
8892 }
8993 catch (IOException ex ) {
90- fail ("Error transforming Docker compose file '" + composeFileResource + "': " + ex .getMessage ());
94+ fail ("Error transforming Docker compose file '" + composeFileResource + "': " + ex .getMessage (), ex );
95+ return null ;
9196 }
92- return null ;
9397 }
9498
95- private SpringApplication prepareApplication (Path transformedComposeFile ) {
99+ private SpringApplication prepareApplication (Path composeFile ) {
96100 SpringApplication application = new SpringApplication (Config .class );
97101 Map <String , Object > properties = new LinkedHashMap <>();
98102 properties .put ("spring.docker.compose.skip.in-tests" , "false" );
99- properties .put ("spring.docker.compose.file" , transformedComposeFile );
103+ properties .put ("spring.docker.compose.file" , composeFile );
100104 properties .put ("spring.docker.compose.stop.command" , "down" );
101105 application .setDefaultProperties (properties );
102106 return application ;
@@ -110,18 +114,18 @@ public void afterTestExecution(ExtensionContext context) throws Exception {
110114 private void cleanUp (ExtensionContext context ) throws Exception {
111115 Store store = context .getStore (NAMESPACE );
112116 runShutdownHandlers ();
113- deleteComposeFile (store );
117+ deleteWorkspace (store );
114118 }
115119
116120 private void runShutdownHandlers () {
117121 SpringApplicationShutdownHandlers shutdownHandlers = SpringApplication .getShutdownHandlers ();
118122 ((Runnable ) shutdownHandlers ).run ();
119123 }
120124
121- private void deleteComposeFile (Store store ) throws IOException {
122- Path composeFile = store .get (STORE_KEY_COMPOSE_FILE , Path . class );
123- if (composeFile != null ) {
124- Files . delete ( composeFile );
125+ private void deleteWorkspace (Store store ) throws IOException {
126+ Path workspace = ( Path ) store .get (STORE_KEY_WORKSPACE );
127+ if (workspace != null ) {
128+ FileSystemUtils . deleteRecursively ( workspace );
125129 }
126130 }
127131
0 commit comments