Skip to content

Commit b773dcd

Browse files
committed
Add ability to copy additional files when running Docker Compose tests
See gh-41137
1 parent 109fd6f commit b773dcd

File tree

2 files changed

+46
-16
lines changed

2 files changed

+46
-16
lines changed

spring-boot-project/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/service/connection/test/DockerComposeTest.java

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
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.
@@ -44,6 +44,7 @@
4444
* closed.
4545
*
4646
* @author Andy Wilkinson
47+
* @author Moritz Halbritter
4748
*/
4849
@Test
4950
@Target(ElementType.METHOD)
@@ -63,6 +64,13 @@
6364
*/
6465
String composeFile();
6566

67+
/**
68+
* Additional resources to copy next to the compose file. Loaded as a classpath
69+
* resource relative to the test class.
70+
* @return the additional resources to copy
71+
*/
72+
String[] additionalResources() default {};
73+
6674
/**
6775
* The Docker image reference.
6876
* @return the Docker image reference

spring-boot-project/spring-boot-docker-compose/src/dockerTest/java/org/springframework/boot/docker/compose/service/connection/test/DockerComposeTestExtension.java

+37-15
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
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.
@@ -39,28 +39,32 @@
3939
import org.springframework.context.annotation.Configuration;
4040
import org.springframework.core.io.ClassPathResource;
4141
import org.springframework.core.io.Resource;
42+
import org.springframework.util.FileSystemUtils;
4243

4344
import static org.assertj.core.api.Assertions.fail;
4445

4546
/**
4647
* {@link Extension} for {@link DockerComposeTest @DockerComposeTest}.
4748
*
4849
* @author Andy Wilkinson
50+
* @author Moritz Halbritter
4951
*/
5052
class DockerComposeTestExtension implements BeforeTestExecutionCallback, AfterTestExecutionCallback, ParameterResolver {
5153

5254
private static final Namespace NAMESPACE = Namespace.create(DockerComposeTestExtension.class);
5355

54-
private static final String STORE_KEY_COMPOSE_FILE = "compose-file";
56+
private static final String STORE_KEY_WORKSPACE = "workspace";
5557

5658
private static final String STORE_KEY_APPLICATION_CONTEXT = "application-context";
5759

5860
@Override
5961
public void beforeTestExecution(ExtensionContext context) throws Exception {
60-
Path transformedComposeFile = prepareComposeFile(context);
6162
Store store = context.getStore(NAMESPACE);
62-
store.put(STORE_KEY_COMPOSE_FILE, transformedComposeFile);
63+
Path workspace = Files.createTempDirectory("DockerComposeTestExtension-");
64+
store.put(STORE_KEY_WORKSPACE, workspace);
6365
try {
66+
Path transformedComposeFile = prepareComposeFile(workspace, context);
67+
copyAdditionalResources(workspace, context);
6468
SpringApplication application = prepareApplication(transformedComposeFile);
6569
store.put(STORE_KEY_APPLICATION_CONTEXT, application.run());
6670
}
@@ -70,26 +74,44 @@ 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 {
8387
Path composeFile = composeFileResource.getFile().toPath();
84-
Path transformedComposeFile = Files.createTempFile("", "-" + composeFile.getFileName().toString());
8588
String transformedContent = Files.readString(composeFile).replace("{imageName}", image.toString());
89+
Path transformedComposeFile = workspace.resolve("compose.yaml");
8690
Files.writeString(transformedComposeFile, transformedContent);
8791
return transformedComposeFile;
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;
96+
}
97+
}
98+
99+
private void copyAdditionalResources(Path workspace, ExtensionContext context) {
100+
DockerComposeTest dockerComposeTest = context.getRequiredTestMethod().getAnnotation(DockerComposeTest.class);
101+
for (String additionalResource : dockerComposeTest.additionalResources()) {
102+
Resource resource = new ClassPathResource(additionalResource, context.getRequiredTestClass());
103+
copyAdditionalResource(workspace, resource);
104+
}
105+
}
106+
107+
private void copyAdditionalResource(Path workspace, Resource resource) {
108+
try {
109+
Path source = resource.getFile().toPath();
110+
Files.copy(source, workspace.resolve(source.getFileName()));
111+
}
112+
catch (IOException ex) {
113+
fail("Error copying additional resource '" + resource + "': " + ex.getMessage(), ex);
91114
}
92-
return null;
93115
}
94116

95117
private SpringApplication prepareApplication(Path transformedComposeFile) {
@@ -110,18 +132,18 @@ public void afterTestExecution(ExtensionContext context) throws Exception {
110132
private void cleanUp(ExtensionContext context) throws Exception {
111133
Store store = context.getStore(NAMESPACE);
112134
runShutdownHandlers();
113-
deleteComposeFile(store);
135+
deleteWorkspace(store);
114136
}
115137

116138
private void runShutdownHandlers() {
117139
SpringApplicationShutdownHandlers shutdownHandlers = SpringApplication.getShutdownHandlers();
118140
((Runnable) shutdownHandlers).run();
119141
}
120142

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);
143+
private void deleteWorkspace(Store store) throws IOException {
144+
Path workspace = (Path) store.get(STORE_KEY_WORKSPACE);
145+
if (workspace != null) {
146+
FileSystemUtils.deleteRecursively(workspace);
125147
}
126148
}
127149

0 commit comments

Comments
 (0)