1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.integrationtests.docker;
35
36 import static com.github.dockerjava.api.model.ExposedPort.tcp;
37 import static com.github.dockerjava.api.model.Ports.Binding.bindPort;
38
39 import info.magnolia.integrationtests.IntegrationTestSettings;
40
41 import java.nio.file.Paths;
42 import java.time.Duration;
43 import java.time.temporal.ChronoUnit;
44 import java.util.function.UnaryOperator;
45 import java.util.stream.IntStream;
46 import java.util.stream.Stream;
47
48 import org.apache.commons.lang3.StringUtils;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51 import org.testcontainers.DockerClientFactory;
52 import org.testcontainers.containers.BindMode;
53 import org.testcontainers.containers.GenericContainer;
54 import org.testcontainers.containers.wait.LogMessageWaitStrategy;
55
56 import com.github.dockerjava.api.DockerClient;
57 import com.github.dockerjava.api.command.CreateNetworkResponse;
58 import com.github.dockerjava.api.command.RemoveContainerCmd;
59 import com.github.dockerjava.api.model.Container;
60 import com.github.dockerjava.api.model.PortBinding;
61
62
63
64
65
66
67
68
69
70 public class IntegrationTestEnvironment {
71
72 private static final Logger log = LoggerFactory.getLogger(IntegrationTestEnvironment.class);
73
74 private final IntegrationTestSettings testSettings;
75
76 private final DockerClient docker = DockerClientFactory.instance().client();
77
78 public IntegrationTestEnvironment(IntegrationTestSettings testSettings) {
79 this.testSettings = testSettings;
80 }
81
82 public IntegrationTestEnvironment() {
83 this(IntegrationTestSettings.access());
84 }
85
86 public void initialiseTestEnvironment() {
87 if (!testSettings.testEnvironmentSetupRequired()) {
88 return;
89 }
90
91 log.info("Preparing environment for the Selenium UI tests");
92
93
94 ensureTestNetworkIsUp();
95
96 launchSeleniumHub();
97
98 launchApplicationServer();
99
100 log.info("Done preparing environment for the Selenium UI tests");
101 }
102
103 private void ensureTestNetworkIsUp() {
104 boolean netWorkCreationRequired = docker.listNetworksCmd().withNameFilter(testSettings.testNetworkName()).exec().isEmpty();
105
106 if (netWorkCreationRequired) {
107 log.info("Creating Docker network [{}]", testSettings.testNetworkName());
108
109 final CreateNetworkResponse networkCreationResult =
110 docker.createNetworkCmd()
111 .withName(testSettings.testNetworkName())
112 .exec();
113
114 log.info("Successfully created Docker network [{}] with id [{}]", testSettings.testNetworkName(), networkCreationResult.getId());
115 } else {
116 log.info("[{}] network exists, will not try to create it");
117 }
118 }
119
120 private void launchSeleniumHub() {
121 log.info("Starting Selenium Hub container");
122 recreateContainer(
123 testSettings.seleniumHubContainerName(),
124 "selenium/hub:3.7.1",
125 hub -> hub
126 .withCreateContainerCmdModifier(cmd ->
127 cmd.withPortBindings(new PortBinding(
128 bindPort(testSettings.seleniumHubPort()),
129 tcp(testSettings.seleniumHubPort()))))
130 .withStartupTimeout(Duration.of(3, ChronoUnit.SECONDS))
131 .withLogConsumer(outputFrame -> log.info(outputFrame.getUtf8String()))
132 .withCreateContainerCmdModifier(cmd -> cmd.withNetworkMode(testSettings.testNetworkName())));
133
134
135 log.info("Starting {} Selenium Node containers", testSettings.concurrentTestCases());
136 IntStream.range(0, testSettings.concurrentTestCases()).mapToObj(index ->
137 new SeleniumGridNodeContainer()
138 .withDebugMode(testSettings.debugMode())
139 .withTestNetwork(testSettings.testNetworkName())
140 .withSeleniumHubHost(testSettings.seleniumHubContainerName())
141 .withSeleniumHubPort(testSettings.seleniumHubPort())
142 .withUploadDirectory(testSettings.uploadDirectory())
143 .withTargetBrowser(testSettings.seleniumBrowser()))
144 .forEach(GenericContainer::start);
145 }
146
147 private void launchApplicationServer() {
148 log.info("Starting application server");
149 recreateContainer(
150 "server",
151 "amd64/tomcat:8.5-jre8",
152 tomcat -> tomcat
153 .withCreateContainerCmdModifier(cmd -> cmd.withPortBindings(new PortBinding(bindPort(8599), tcp(8080))))
154 .withCreateContainerCmdModifier(cmd -> cmd.withNetworkMode(testSettings.testNetworkName()))
155 .withEnv("JAVA_OPTS", "-Xmx2048m -Dmagnolia.update.auto=true")
156 .waitingFor(new LogMessageWaitStrategy()
157 .withRegEx("^.*Catalina\\.start Server startup in [0-9]+ ms\n$")
158 .withStartupTimeout(Duration.of(testSettings.startupTimeout(), ChronoUnit.MINUTES)))
159 .withLogConsumer(outputFrame -> log.info(outputFrame.getUtf8String().replaceFirst("\n$", "")))
160 .withFileSystemBind(
161 Paths.get(testSettings.authorWarLocation()).toAbsolutePath().toString(),
162 String.format("/usr/local/tomcat/webapps/%s.war", StringUtils.removeEnd(testSettings.authorContextPath(), "/")),
163 BindMode.READ_WRITE)
164 .withFileSystemBind(
165 Paths.get(testSettings.publicWarLocation()).toAbsolutePath().toString(),
166 String.format("/usr/local/tomcat/webapps/%s.war", StringUtils.removeEnd(testSettings.publicContextPath(), "/")),
167 BindMode.READ_WRITE));
168 }
169
170 private void recreateContainer(String name, String image, UnaryOperator<GenericContainer<?>> containerConfigurer) {
171 docker.listContainersCmd()
172 .withShowAll(true)
173 .exec().stream()
174 .filter(container -> Stream.of(container.getNames()).anyMatch(containerName -> containerName.equals(String.format("/%s", name))))
175 .map(Container::getId)
176 .findFirst()
177 .map(containerId -> docker.removeContainerCmd(containerId).withForce(true))
178 .ifPresent(RemoveContainerCmd::exec);
179
180 containerConfigurer.apply(new GenericContainer<>(image).withCreateContainerCmdModifier(cmd -> cmd.withName(name))).start();
181 }
182 }