package org.arquillian.cube.docker.junit.rule;
import org.arquillian.cube.HostIpContext;
import org.arquillian.cube.docker.impl.client.CubeDockerConfiguration;
import org.arquillian.cube.docker.impl.client.CubeDockerConfigurationResolver;
import org.arquillian.cube.docker.impl.client.config.Await;
import org.arquillian.cube.docker.impl.client.config.BuildImage;
import org.arquillian.cube.docker.impl.client.containerobject.dsl.BindMode;
import org.arquillian.cube.docker.impl.client.containerobject.dsl.Container;
import org.arquillian.cube.docker.impl.client.containerobject.dsl.ContainerBuilder;
import org.arquillian.cube.docker.impl.docker.DockerClientExecutor;
import org.arquillian.cube.docker.impl.model.DockerCube;
import org.arquillian.cube.docker.impl.util.Boot2Docker;
import org.arquillian.cube.docker.impl.util.CommandLineExecutor;
import org.arquillian.cube.docker.impl.util.DockerMachine;
import org.arquillian.cube.docker.impl.util.OperatingSystemResolver;
import org.arquillian.cube.docker.impl.util.Top;
import org.arquillian.cube.impl.model.LocalCubeRegistry;
import org.arquillian.cube.spi.CubeOutput;
import org.arquillian.cube.spi.CubeRegistry;
import org.arquillian.cube.spi.event.lifecycle.CubeLifecyleEvent;
import org.jboss.arquillian.core.api.Event;
import org.jboss.arquillian.core.api.Injector;
import org.jboss.arquillian.core.api.Instance;
import org.jboss.shrinkwrap.api.Archive;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.MultipleFailureException;
import org.junit.runners.model.Statement;
import java.io.File;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
public class ContainerDslRule implements TestRule {
private DockerClientExecutor dockerClientExecutor;
private ContainerBuilder.ContainerOptionsBuilder containerBuilder;
private Container container;
public ContainerDslRule(File directory, String imageId) {
this.containerBuilder = Container.withContainerName(imageId)
.fromBuildDirectory(directory.getAbsolutePath());
initializeDockerClient();
}
public ContainerDslRule(Archive<?> buildDirectory, String imageId) {
this.containerBuilder = Container.withContainerName(imageId)
.fromBuildDirectory(buildDirectory);
initializeDockerClient();
}
public ContainerDslRule(String image) {
this(image, convertImageToId(image));
}
public ContainerDslRule(String image, String id) {
this.containerBuilder = Container.withContainerName(id)
.fromImage(image);
initializeDockerClient();
}
private static String convertImageToId(String imageId) {
return imageId
.replace('/', '_')
.replace(':', '_')
.replace('.', '_');
}
private void initializeDockerClient() {
this.dockerClientExecutor = DockerClientInitializer.initialize();
}
public ContainerDslRule withExposedPorts(Integer... ports) {
containerBuilder.withExposedPorts(ports);
return this;
}
public ContainerDslRule withExposedPorts(String... ports) {
containerBuilder.withExposedPorts(ports);
return this;
}
public ContainerDslRule withPortBinding(Integer... ports) {
containerBuilder.withPortBinding(ports);
return this;
}
public ContainerDslRule withPortBinding(String... ports) {
containerBuilder.withPortBinding(ports);
return this;
}
public ContainerDslRule withEnvironment(String key, Object value, Object...keyValues) {
containerBuilder.withEnvironment(key, value, keyValues);
return this;
}
public ContainerDslRule withCommand(String command) {
containerBuilder.withCommand(command);
return this;
}
public ContainerDslRule withCommand(String... command) {
containerBuilder.withCommand(command);
return this;
}
public ContainerDslRule withVolume(String hostPath, String containerPath) {
return withVolume(hostPath, containerPath, BindMode.READ_WRITE);
}
public ContainerDslRule withVolume(String hostPath, String containerPath, BindMode bindMode) {
containerBuilder.withVolume(hostPath, containerPath, bindMode);
return this;
}
public ContainerDslRule withNetworkMode(String networkMode) {
containerBuilder.withNetworkMode(networkMode);
return this;
}
public ContainerDslRule withNetworkMode(NetworkDslRule networkMode) {
return this.withNetworkMode(networkMode.getNetworkName());
}
public ContainerDslRule withNetworks(String... networks) {
containerBuilder.withNetworks(networks);
return this;
}
public ContainerDslRule withPriviledgedMode(boolean mode) {
containerBuilder.withPriviledgedMode(mode);
return this;
}
public ContainerDslRule withLink(String link) {
containerBuilder.withLink(link);
return this;
}
public ContainerDslRule withLink(String service, String alias) {
return withLink(service + ":" + alias);
}
public ContainerDslRule withAwaitStrategy(Await awaitStrategy) {
containerBuilder.withAwaitStrategy(awaitStrategy);
return this;
}
public String getIpAddress() {
return this.container.getIpAddress();
}
public int getBindPort(int exposedPort) {
return this.container.getBindPort(exposedPort);
}
public String getLog() {
return this.container.getLog();
}
public CubeOutput exec(String... commands) {
return this.container.exec(commands);
}
@Override
public Statement apply(Statement base, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
List<Throwable> errors = new ArrayList<>();
// Inject Arquillian resources
container = containerBuilder.build();
final Optional<Field> hostIpContextField = Reflections.findFieldByGenericType(Container.class, Instance.class, HostIpContext.class);
if (hostIpContextField.isPresent()) {
Reflections.injectObject(container, hostIpContextField.get(), (Instance) () -> new HostIpContext(dockerClientExecutor.getDockerServerIp()));
}
final Optional<Field> dockerClientExecutorField = Reflections.findFieldByGenericType(Container.class, Instance.class, DockerClientExecutor.class);
if (dockerClientExecutorField.isPresent()) {
Reflections.injectObject(container, dockerClientExecutorField.get(), (Instance) () -> dockerClientExecutor);
}
DockerCube dockerCube = new DockerCube(container.getContainerName(), container.getCubeContainer(), dockerClientExecutor);
LocalCubeRegistry localCubeRegistry = new LocalCubeRegistry();
localCubeRegistry.addCube(dockerCube);
final Optional<Field> cubeRegistryField = Reflections.findFieldByGenericType(Container.class, Instance.class, CubeRegistry.class);
if (cubeRegistryField.isPresent()) {
Reflections.injectObject(container, cubeRegistryField.get(), (Instance) () -> localCubeRegistry);
}
final Optional<Field> eventField = Reflections.findFieldByGenericType(DockerCube.class, Event.class, CubeLifecyleEvent.class);
if (eventField.isPresent()) {
Reflections.injectObject(dockerCube, eventField.get(), (Event) o -> {
});
}
try {
dockerCube.create();
dockerCube.start();
// Run tests
base.evaluate();
} catch (Throwable t) {
errors.add(t);
} finally {
// stop container
dockerCube.stop();
dockerCube.destroy();
}
MultipleFailureException.assertEmpty(errors);
}
};
}
}