All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
io.trino.testing.containers.BaseTestContainer Maven / Gradle / Ivy
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.trino.testing.containers;
import com.github.dockerjava.api.command.CreateContainerCmd;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.net.HostAndPort;
import dev.failsafe.Failsafe;
import dev.failsafe.RetryPolicy;
import io.airlift.log.Logger;
import io.trino.testing.ResourcePresence;
import org.testcontainers.containers.BindMode;
import org.testcontainers.containers.Container;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network;
import org.testcontainers.containers.output.OutputFrame;
import org.testcontainers.containers.startupcheck.IsRunningStartupCheckStrategy;
import org.testcontainers.containers.wait.strategy.Wait;
import java.io.IOException;
import java.time.Duration;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.net.HostAndPort.fromParts;
import static java.lang.String.format;
import static java.util.Objects.requireNonNull;
import static org.testcontainers.utility.MountableFile.forClasspathResource;
import static org.testcontainers.utility.MountableFile.forHostPath;
public abstract class BaseTestContainer
implements AutoCloseable
{
private final Logger log;
private final String hostName;
private final Set ports;
private final Map filesToMount;
private final Map envVars;
private final Optional network;
private final int startupRetryLimit;
private GenericContainer> container;
protected BaseTestContainer(
String image,
String hostName,
Set ports,
Map filesToMount,
Map envVars,
Optional network,
int startupRetryLimit)
{
checkArgument(startupRetryLimit > 0, "startupRetryLimit needs to be greater or equal to 0");
this.log = Logger.get(this.getClass());
this.container = new GenericContainer<>(requireNonNull(image, "image is null"));
this.ports = requireNonNull(ports, "ports is null");
this.hostName = requireNonNull(hostName, "hostName is null");
this.filesToMount = requireNonNull(filesToMount, "filesToMount is null");
this.envVars = requireNonNull(envVars, "envVars is null");
this.network = requireNonNull(network, "network is null");
this.startupRetryLimit = startupRetryLimit;
setupContainer();
}
protected void setupContainer()
{
for (int port : this.ports) {
container.addExposedPort(port);
}
filesToMount.forEach((dockerPath, filePath) -> container.withCopyFileToContainer(forHostPath(filePath), dockerPath));
container.withEnv(envVars);
container.withCreateContainerCmdModifier(c -> c.withHostName(hostName))
.withStartupCheckStrategy(new IsRunningStartupCheckStrategy())
.waitingFor(Wait.forListeningPort())
.withStartupTimeout(Duration.ofMinutes(5));
network.ifPresent(net -> container.withNetwork(net).withNetworkAliases(hostName));
}
protected void withRunCommand(List runCommand)
{
container.withCommand(runCommand.toArray(new String[runCommand.size()]));
}
protected void withLogConsumer(Consumer logConsumer)
{
container.withLogConsumer(logConsumer);
}
protected void copyResourceToContainer(String resourcePath, String dockerPath)
{
container.withCopyFileToContainer(
forHostPath(
forClasspathResource(resourcePath)
// Container fails to mount jar:file:/! resources
// This assures that JAR resources are being copied out to tmp locations
// and mounted from there.
.getResolvedPath()),
dockerPath);
}
protected void mountDirectory(String hostPath, String dockerPath)
{
container.addFileSystemBind(hostPath, dockerPath, BindMode.READ_WRITE);
}
protected void withCreateContainerModifier(Consumer modifier)
{
container.withCreateContainerCmdModifier(modifier);
}
protected HostAndPort getMappedHostAndPortForExposedPort(int exposedPort)
{
return fromParts(container.getHost(), container.getMappedPort(exposedPort));
}
public void start()
{
GenericContainer> container = this.container;
try {
Failsafe.with(RetryPolicy.builder()
.withMaxRetries(startupRetryLimit)
.onRetry(event -> log.warn(
"%s initialization failed (attempt %s), will retry. Exception: %s",
this.getClass().getSimpleName(),
event.getAttemptCount(),
event.getLastException().getMessage()))
.build())
.get(() -> TestContainers.startOrReuse(container));
}
catch (Throwable e) {
try (container) {
throw e;
}
}
}
public void stop()
{
container.stop();
}
public String executeInContainerFailOnError(String... commandAndArgs)
{
Container.ExecResult execResult = executeInContainer(commandAndArgs);
if (execResult.getExitCode() != 0) {
String message = format("Command [%s] exited with %s", String.join(" ", commandAndArgs), execResult.getExitCode());
log.error("%s", message);
log.error("stderr: %s", execResult.getStderr());
log.error("stdout: %s", execResult.getStdout());
throw new RuntimeException(message);
}
return execResult.getStdout();
}
public Container.ExecResult executeInContainer(String... commandAndArgs)
{
try {
return container.execInContainer(commandAndArgs);
}
catch (IOException | InterruptedException e) {
throw new RuntimeException("Exception while running command: " + String.join(" ", commandAndArgs), e);
}
}
@Override
public void close()
{
stop();
}
@ResourcePresence
public boolean isPresent()
{
return container.isRunning() || container.getContainerId() != null;
}
protected abstract static class Builder, BUILD extends BaseTestContainer>
{
protected String image;
protected String hostName;
protected Set exposePorts = ImmutableSet.of();
protected Map filesToMount = ImmutableMap.of();
protected Map envVars = ImmutableMap.of();
protected Optional network = Optional.empty();
protected int startupRetryLimit = 1;
protected SELF self;
@SuppressWarnings("unchecked")
public Builder()
{
this.self = (SELF) this;
}
public SELF withImage(String image)
{
this.image = image;
return self;
}
public SELF withHostName(String hostName)
{
this.hostName = hostName;
return self;
}
public SELF withExposePorts(Set exposePorts)
{
this.exposePorts = exposePorts;
return self;
}
public SELF withFilesToMount(Map filesToMount)
{
this.filesToMount = filesToMount;
return self;
}
public SELF withEnvVars(Map envVars)
{
this.envVars = envVars;
return self;
}
public SELF withNetwork(Network network)
{
this.network = Optional.of(network);
return self;
}
public SELF withStartupRetryLimit(int startupRetryLimit)
{
this.startupRetryLimit = startupRetryLimit;
return self;
}
public abstract BUILD build();
}
}