package org.arquillian.cube.docker.impl.client; import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.nio.file.Paths; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.lang.SystemUtils; 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.OperatingSystemFamily; import org.arquillian.cube.docker.impl.util.OperatingSystemResolver; import org.arquillian.cube.docker.impl.util.Top; import org.arquillian.cube.spi.CubeConfiguration; import org.hamcrest.Matcher; import org.hamcrest.core.StringEndsWith; import org.jboss.arquillian.config.descriptor.api.ArquillianDescriptor; import org.jboss.arquillian.config.descriptor.api.ExtensionDef; import org.jboss.arquillian.core.api.annotation.ApplicationScoped; import org.jboss.arquillian.core.test.AbstractManagerTestBase; import org.junit.Assume; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.collection.IsMapContaining.hasEntry; import static org.hamcrest.collection.IsMapContaining.hasKey; import static org.junit.Assert.assertThat; import static org.junit.Assume.assumeThat; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) public class CubeConfiguratorTest extends AbstractManagerTestBase { @Mock CommandLineExecutor commandLineExecutor; @Mock ArquillianDescriptor arquillianDescriptor; @Mock ExtensionDef extensionDef; @Mock Top top; private static Matcher<String> defaultDockerMachineCertPath() { return containsString(".docker/machine/machines"); } private static Matcher<String> defaultBootToDockerCertPath() { return containsString(".boot2docker/certs"); } private static Matcher<String> pathEndsWith(String suffix) { return new PathStringEndsWithMatcher(suffix); } @Override protected void addExtensions(List<Class<?>> extensions) { extensions.add(CubeDockerConfigurator.class); super.addExtensions(extensions); } @Before public void setup() { bind(ApplicationScoped.class, Boot2Docker.class, new Boot2Docker(commandLineExecutor)); bind(ApplicationScoped.class, DockerMachine.class, new DockerMachine(commandLineExecutor)); bind(ApplicationScoped.class, ArquillianDescriptor.class, arquillianDescriptor); bind(ApplicationScoped.class, Top.class, top); when(top.isSpinning()).thenReturn(false); } @Test public void shouldChangeServerUriInCaseOfRunningDockerInsideDocker() { Map<String, String> config = new HashMap<>(); config.put(CubeDockerConfiguration.DOCKER_URI, "https://dockerHost:22222"); when(extensionDef.getExtensionProperties()).thenReturn(config); when(arquillianDescriptor.extension("docker")).thenReturn(extensionDef); when(commandLineExecutor.execCommand("boot2docker", "ip")).thenReturn("192.168.0.1"); when(top.isSpinning()).thenReturn(true); fire(new CubeConfiguration()); assertThat(config, hasEntry(CubeDockerConfiguration.DOCKER_URI, OperatingSystemFamily.DIND.getServerUri())); } @Test public void shouldNotChangeServerUriInCaseODockerInsideDockerIfItIsDisabled() { Map<String, String> config = new HashMap<>(); config.put(CubeDockerConfiguration.DOCKER_URI, "tcp://dockerHost:22222"); config.put(CubeDockerConfiguration.DIND_RESOLUTION, "false"); when(extensionDef.getExtensionProperties()).thenReturn(config); when(arquillianDescriptor.extension("docker")).thenReturn(extensionDef); when(commandLineExecutor.execCommand("boot2docker", "ip")).thenReturn("192.168.0.1"); when(top.isSpinning()).thenReturn(true); fire(new CubeConfiguration()); assertThat(config, hasEntry(CubeDockerConfiguration.DOCKER_URI, "tcp://192.168.0.1:22222")); } @Test public void shouldUseBoot2DockerIfDockerHostIsSetOnServerURIByDefault() { assumeThat(new OperatingSystemResolver().currentOperatingSystem().getFamily(), is(not(OperatingSystemFamily.LINUX))); Map<String, String> config = new HashMap<>(); config.put(CubeDockerConfiguration.DOCKER_URI, "tcp://dockerHost:22222"); when(extensionDef.getExtensionProperties()).thenReturn(config); when(arquillianDescriptor.extension("docker")).thenReturn(extensionDef); when(commandLineExecutor.execCommand("boot2docker", "ip")).thenReturn("192.168.0.1"); fire(new CubeConfiguration()); assertThat(config, hasEntry(CubeDockerConfiguration.DOCKER_URI, "tcp://192.168.0.1:22222")); assertThat(config, hasEntry(is(CubeDockerConfiguration.CERT_PATH), defaultBootToDockerCertPath())); } @Test public void shouldUseDockerMachineIfDockerHostIsSetOnServerURIAndMachineNameIsSet() { Map<String, String> config = new HashMap<>(); config.put(CubeDockerConfiguration.DOCKER_URI, "tcp://dockerHost:22222"); config.put(CubeDockerConfiguration.DOCKER_MACHINE_NAME, "dev"); when(extensionDef.getExtensionProperties()).thenReturn(config); when(arquillianDescriptor.extension("docker")).thenReturn(extensionDef); when(commandLineExecutor.execCommandAsArray("docker-machine", "ls", "--filter", "name=dev")) .thenReturn(Arrays.asList( "NAME ACTIVE DRIVER STATE URL SWARM", "dev * virtualbox Running tcp://192.168.0.2:222222 ")); when(commandLineExecutor.execCommand("docker-machine", "ip", "dev")).thenReturn("192.168.0.2"); fire(new CubeConfiguration()); assertThat(config, hasEntry(CubeDockerConfiguration.DOCKER_URI, "tcp://192.168.0.2:22222")); } @Test public void shouldStartDockerMachineIfItIsStoppedAndMachineNameIsSet() { Map<String, String> config = new HashMap<>(); config.put(CubeDockerConfiguration.DOCKER_URI, "tcp://dockerHost:22222"); config.put(CubeDockerConfiguration.DOCKER_MACHINE_NAME, "dev"); when(extensionDef.getExtensionProperties()).thenReturn(config); when(arquillianDescriptor.extension("docker")).thenReturn(extensionDef); when(commandLineExecutor.execCommandAsArray("docker-machine", "ls", "--filter", "name=dev")) .thenReturn(Arrays.asList( "NAME ACTIVE DRIVER STATE URL SWARM", "dev * virtualbox Stopped tcp://192.168.0.2:222222 ")); when(commandLineExecutor.execCommand("docker-machine", "ip", "dev")).thenReturn("192.168.0.2"); fire(new CubeConfiguration()); assertThat(config, hasEntry(CubeDockerConfiguration.DOCKER_URI, "tcp://192.168.0.2:22222")); verify(commandLineExecutor, times(1)).execCommand("docker-machine", "start", "dev"); } @Test public void shouldUseDockerMachineIfDockerHostIsNotSetAndOnlyOneMachineIsRunning() { Map<String, String> config = new HashMap<>(); when(extensionDef.getExtensionProperties()).thenReturn(config); when(arquillianDescriptor.extension("docker")).thenReturn(extensionDef); when(commandLineExecutor.execCommand("docker-machine", "ip", "dev")).thenReturn("192.168.99.100"); when(commandLineExecutor.execCommandAsArray("docker-machine", "ls", "--filter", "state=Running")) .thenReturn(Arrays.asList( "NAME ACTIVE DRIVER STATE URL SWARM", "dev * virtualbox Running tcp://192.168.99.100:2376 ")); // Docker Machine is installed when(commandLineExecutor.execCommand("docker-machine")) .thenReturn("Usage: docker-machine [OPTIONS] COMMAND [arg...]"); fire(new CubeConfiguration()); assertThat(config, hasEntry(CubeDockerConfiguration.DOCKER_URI, "tcp://192.168.99.100:2376")); assertThat(config, hasEntry(CubeDockerConfiguration.DOCKER_MACHINE_NAME, "dev")); } // Only works in case of running in MACOS or Windows since by default in // these systems boot2docker is the default @Test public void shouldNotUseDockerMachineIfDockerHostIsNotSetNotDockerMachineAndTwoMachineIsRunning() { Assume.assumeTrue(SystemUtils.IS_OS_MAC_OSX || SystemUtils.IS_OS_WINDOWS); Map<String, String> config = new HashMap<>(); when(extensionDef.getExtensionProperties()).thenReturn(config); when(arquillianDescriptor.extension("docker")).thenReturn(extensionDef); when(commandLineExecutor.execCommand("docker-machine", "ip", "dev")).thenReturn("192.168.99.100"); when(commandLineExecutor.execCommandAsArray("docker-machine", "ls", "--filter", "state=Running")) .thenReturn(Arrays.asList( "NAME ACTIVE DRIVER STATE URL SWARM", "dev * virtualbox Running tcp://192.168.99.100:2376 ", "dev2 * virtualbox Running tcp://192.168.99.100:2376 ")); when(commandLineExecutor.execCommand("boot2docker", "ip")).thenReturn("192.168.0.1"); // Docker-Machine is installed when(commandLineExecutor.execCommand("docker-machine")) .thenReturn("Usage: docker-machine [OPTIONS] COMMAND [arg...]"); fire(new CubeConfiguration()); assertThat(config, hasEntry(CubeDockerConfiguration.DOCKER_URI, "tcp://192.168.0.1:2376")); } // Only works in case of running in MACOS or Windows since by default in // these systems boot2docker is the default @Test public void shouldUseDefaultsInCaseOfNotHavingDockerMachineInstalledAndNoDockerUriNorMachineName() { Assume.assumeTrue(SystemUtils.IS_OS_MAC_OSX || SystemUtils.IS_OS_WINDOWS); Map<String, String> config = new HashMap<>(); when(extensionDef.getExtensionProperties()).thenReturn(config); when(arquillianDescriptor.extension("docker")).thenReturn(extensionDef); when(commandLineExecutor.execCommand("boot2docker", "ip")).thenReturn("192.168.0.1"); when(commandLineExecutor.execCommand("docker-machine")).thenThrow(new IllegalArgumentException()); fire(new CubeConfiguration()); assertThat(config, hasEntry(CubeDockerConfiguration.DOCKER_URI, "tcp://192.168.0.1:2376")); } @Test public void shouldSetServerIpWithLocalhostInCaseOfNativeLinuxInstallation() { String originalVar = System.getProperty(CubeDockerConfigurator.DOCKER_HOST); try { System.setProperty(CubeDockerConfigurator.DOCKER_HOST, "unix:///var/run/docker.sock"); Map<String, String> config = new HashMap<>(); when(extensionDef.getExtensionProperties()).thenReturn(config); when(arquillianDescriptor.extension("docker")).thenReturn(extensionDef); fire(new CubeConfiguration()); assertThat(config, hasEntry(CubeDockerConfiguration.DOCKER_URI, "unix:///var/run/docker.sock")); assertThat(config, hasEntry(CubeDockerConfiguration.DOCKER_SERVER_IP, "localhost")); } finally { if (originalVar != null) { System.setProperty(CubeDockerConfigurator.DOCKER_HOST, originalVar); } else { System.clearProperty(CubeDockerConfigurator.DOCKER_HOST); } } } @Test public void shouldUseHostEnvIfDockerHostIsSetOnServerURIAndSystemEnvironmentVarIsSet() { String originalVar = System.getProperty(CubeDockerConfigurator.DOCKER_HOST); try { System.setProperty(CubeDockerConfigurator.DOCKER_HOST, "tcp://127.0.0.1:22222"); Map<String, String> config = new HashMap<>(); when(extensionDef.getExtensionProperties()).thenReturn(config); when(arquillianDescriptor.extension("docker")).thenReturn(extensionDef); fire(new CubeConfiguration()); assertThat(config, hasEntry(CubeDockerConfiguration.DOCKER_URI, "tcp://127.0.0.1:22222")); assertThat(config, hasEntry(CubeDockerConfiguration.DOCKER_SERVER_IP, "127.0.0.1")); } finally { if (originalVar != null) { System.setProperty(CubeDockerConfigurator.DOCKER_HOST, originalVar); } else { System.clearProperty(CubeDockerConfigurator.DOCKER_HOST); } } } @Test public void tlsVerifyShouldBeTrueInCaseOfDockerMachine() { Map<String, String> config = new HashMap<>(); config.put(CubeDockerConfiguration.DOCKER_URI, "https://dockerHost:22222"); config.put(CubeDockerConfiguration.DOCKER_MACHINE_NAME, "dev"); when(extensionDef.getExtensionProperties()).thenReturn(config); when(arquillianDescriptor.extension("docker")).thenReturn(extensionDef); when(commandLineExecutor.execCommand("docker-machine", "ip", "dev")).thenReturn("192.168.0.2"); when(commandLineExecutor.execCommandAsArray("docker-machine", "ls", "--filter", "name=dev")) .thenReturn(Arrays.asList( "NAME ACTIVE DRIVER STATE URL SWARM", "dev * virtualbox Running tcp://192.168.0.2:222222 ")); fire(new CubeConfiguration()); assertThat(config, hasEntry(CubeDockerConfiguration.DOCKER_URI, "tcp://192.168.0.2:22222")); assertThat(config, hasEntry(CubeDockerConfiguration.TLS_VERIFY, "true")); assertThat(config, hasEntry(is(CubeDockerConfiguration.CERT_PATH), defaultDockerMachineCertPath())); } @Test public void tlsVerifyShouldBeTrueInCaseOfNotSetAndDockerHostTagNotPresent() { assumeThat(new OperatingSystemResolver().currentOperatingSystem().getFamily(), is(not(OperatingSystemFamily.LINUX))); Map<String, String> config = new HashMap<>(); config.put(CubeDockerConfiguration.DOCKER_URI, "tcp://192.168.0.2:22222"); when(extensionDef.getExtensionProperties()).thenReturn(config); when(arquillianDescriptor.extension("docker")).thenReturn(extensionDef); fire(new CubeConfiguration()); assertThat(config, hasEntry(CubeDockerConfiguration.DOCKER_URI, "tcp://192.168.0.2:22222")); assertThat(config, hasEntry(CubeDockerConfiguration.TLS_VERIFY, "true")); assertThat(config, hasEntry(is(CubeDockerConfiguration.CERT_PATH), defaultBootToDockerCertPath())); } @Test public void tlsVerifyShouldBeTrueInCaseOfSetToFalseAndDockerHostTagNotPresent() { Map<String, String> config = new HashMap<>(); config.put(CubeDockerConfiguration.DOCKER_URI, "tcp://192.168.0.2:22222"); config.put(CubeDockerConfiguration.TLS_VERIFY, "false"); when(extensionDef.getExtensionProperties()).thenReturn(config); when(arquillianDescriptor.extension("docker")).thenReturn(extensionDef); fire(new CubeConfiguration()); assertThat(config, hasEntry(CubeDockerConfiguration.DOCKER_URI, "tcp://192.168.0.2:22222")); assertThat(config, hasEntry(CubeDockerConfiguration.TLS_VERIFY, "false")); assertThat(config, not(hasKey(CubeDockerConfiguration.CERT_PATH))); } @Test public void tlsVerifyShouldBeFalseInCaseOfSetToFalseAndDockerHostTagPresent() { Map<String, String> config = new HashMap<>(); config.put(CubeDockerConfiguration.DOCKER_URI, "tcp://dockerHost:22222"); config.put(CubeDockerConfiguration.TLS_VERIFY, "false"); when(extensionDef.getExtensionProperties()).thenReturn(config); when(arquillianDescriptor.extension("docker")).thenReturn(extensionDef); when(commandLineExecutor.execCommand("boot2docker", "ip")).thenReturn("192.168.0.2"); fire(new CubeConfiguration()); assertThat(config, hasEntry(CubeDockerConfiguration.DOCKER_URI, "tcp://192.168.0.2:22222")); assertThat(config, hasEntry(CubeDockerConfiguration.TLS_VERIFY, "false")); assertThat(config, not(hasKey(CubeDockerConfiguration.CERT_PATH))); } @Test public void tlsVerifyShouldBeTrueInCaseOfNotSetAndDockerHostTagPresent() { assumeThat(new OperatingSystemResolver().currentOperatingSystem().getFamily(), is(not(OperatingSystemFamily.LINUX))); Map<String, String> config = new HashMap<>(); config.put(CubeDockerConfiguration.DOCKER_URI, "tcp://dockerHost:22222"); when(extensionDef.getExtensionProperties()).thenReturn(config); when(arquillianDescriptor.extension("docker")).thenReturn(extensionDef); when(commandLineExecutor.execCommand("boot2docker", "ip")).thenReturn("192.168.0.2"); fire(new CubeConfiguration()); assertThat(config, hasEntry(CubeDockerConfiguration.DOCKER_URI, "tcp://192.168.0.2:22222")); assertThat(config, hasEntry(CubeDockerConfiguration.TLS_VERIFY, "true")); assertThat(config, hasEntry(is(CubeDockerConfiguration.CERT_PATH), defaultBootToDockerCertPath())); } @Test public void tlsVerifyShouldBeTrueInCaseOfCertPathPresent() { assumeThat(new OperatingSystemResolver().currentOperatingSystem().getFamily(), is(not(OperatingSystemFamily.LINUX))); Map<String, String> config = new HashMap<>(); config.put(CubeDockerConfiguration.DOCKER_URI, "tcp://dockerHost:22222"); config.put(CubeDockerConfiguration.CERT_PATH, "~/.ssh"); when(extensionDef.getExtensionProperties()).thenReturn(config); when(arquillianDescriptor.extension("docker")).thenReturn(extensionDef); when(commandLineExecutor.execCommand("boot2docker", "ip")).thenReturn("192.168.0.2"); fire(new CubeConfiguration()); assertThat(config, hasEntry(CubeDockerConfiguration.DOCKER_URI, "tcp://192.168.0.2:22222")); assertThat(config, hasEntry(CubeDockerConfiguration.TLS_VERIFY, "true")); assertThat(config, hasEntry(is(CubeDockerConfiguration.CERT_PATH), pathEndsWith(".ssh"))); } @Test public void tlsVerifyShouldBeTrueInCaseOfHttpsServerUri() { Map<String, String> config = new HashMap<>(); config.put(CubeDockerConfiguration.DOCKER_URI, "https://192.168.0.2:22222"); when(extensionDef.getExtensionProperties()).thenReturn(config); when(arquillianDescriptor.extension("docker")).thenReturn(extensionDef); fire(new CubeConfiguration()); assertThat(config, hasEntry(CubeDockerConfiguration.DOCKER_URI, "tcp://192.168.0.2:22222")); assertThat(config, hasEntry(CubeDockerConfiguration.TLS_VERIFY, "true")); assertThat(config, hasEntry(is(CubeDockerConfiguration.CERT_PATH), defaultBootToDockerCertPath())); } @Test public void tlsVerifyShouldBeTrueInCaseOfSetToFalseAndHttpsServerUri() { Map<String, String> config = new HashMap<>(); config.put(CubeDockerConfiguration.DOCKER_URI, "https://192.168.0.2:22222"); config.put(CubeDockerConfiguration.TLS_VERIFY, "false"); when(extensionDef.getExtensionProperties()).thenReturn(config); when(arquillianDescriptor.extension("docker")).thenReturn(extensionDef); fire(new CubeConfiguration()); assertThat(config, hasEntry(CubeDockerConfiguration.DOCKER_URI, "tcp://192.168.0.2:22222")); assertThat(config, hasEntry(CubeDockerConfiguration.TLS_VERIFY, "true")); assertThat(config, hasEntry(is(CubeDockerConfiguration.CERT_PATH), defaultBootToDockerCertPath())); } @Test public void tlsVerifyShouldBeFalseInCaseOfHttpServerUri() throws Exception { Map<String, String> config = new HashMap<>(); config.put(CubeDockerConfiguration.DOCKER_URI, "http://192.168.0.2:22222"); when(extensionDef.getExtensionProperties()).thenReturn(config); when(arquillianDescriptor.extension("docker")).thenReturn(extensionDef); fire(new CubeConfiguration()); assertThat(config, hasEntry(CubeDockerConfiguration.DOCKER_URI, "tcp://192.168.0.2:22222")); assertThat(config, hasEntry(CubeDockerConfiguration.TLS_VERIFY, "false")); assertThat(config, not(hasKey(CubeDockerConfiguration.CERT_PATH))); } @Test public void tlsVerifyShouldBeFalseInCaseOfSetToTrueAndHttpServerUri() { Map<String, String> config = new HashMap<>(); config.put(CubeDockerConfiguration.DOCKER_URI, "http://192.168.0.2:22222"); config.put(CubeDockerConfiguration.TLS_VERIFY, "true"); when(extensionDef.getExtensionProperties()).thenReturn(config); when(arquillianDescriptor.extension("docker")).thenReturn(extensionDef); fire(new CubeConfiguration()); assertThat(config, hasEntry(CubeDockerConfiguration.DOCKER_URI, "tcp://192.168.0.2:22222")); assertThat(config, hasEntry(CubeDockerConfiguration.TLS_VERIFY, "false")); assertThat(config, not(hasKey(CubeDockerConfiguration.CERT_PATH))); } @Test public void dockerUriConfigurationParameterShouldTakePrecedenceOverSystemEnv() { assumeThat(new OperatingSystemResolver().currentOperatingSystem().getFamily(), is(not(OperatingSystemFamily.LINUX))); String originalVar = System.getProperty(CubeDockerConfigurator.DOCKER_HOST); try { System.setProperty(CubeDockerConfigurator.DOCKER_HOST, "tcp://127.0.0.1:22222"); Map<String, String> config = new HashMap<>(); config.put(CubeDockerConfiguration.DOCKER_URI, "tcp://dockerHost:22222"); when(extensionDef.getExtensionProperties()).thenReturn(config); when(arquillianDescriptor.extension("docker")).thenReturn(extensionDef); when(extensionDef.getExtensionProperties()).thenReturn(config); when(arquillianDescriptor.extension("docker")).thenReturn(extensionDef); when(commandLineExecutor.execCommand("boot2docker", "ip")).thenReturn("192.168.0.1"); fire(new CubeConfiguration()); assertThat(config, hasEntry(CubeDockerConfiguration.DOCKER_URI, "tcp://192.168.0.1:22222")); assertThat(config, hasEntry(is(CubeDockerConfiguration.CERT_PATH), defaultBootToDockerCertPath())); assertThat(config, hasEntry(CubeDockerConfiguration.DOCKER_SERVER_IP, "192.168.0.1")); } finally { if (originalVar != null) { System.setProperty(CubeDockerConfigurator.DOCKER_HOST, originalVar); } else { System.clearProperty(CubeDockerConfigurator.DOCKER_HOST); } } } @Test public void shouldDumpCubeConfiguration() throws Exception { Map<String, String> config = new HashMap<>(); config.put(CubeDockerConfiguration.DOCKER_URI, "https://dockerHost:22222"); when(extensionDef.getExtensionProperties()).thenReturn(config); when(arquillianDescriptor.extension("docker")).thenReturn(extensionDef); when(extensionDef.getExtensionProperties()).thenReturn(config); when(arquillianDescriptor.extension("docker")).thenReturn(extensionDef); when(commandLineExecutor.execCommand("boot2docker", "ip")).thenReturn("192.168.0.1"); PrintStream old = System.out; ByteArrayOutputStream baos = new ByteArrayOutputStream(); System.setOut(new PrintStream(baos)); CubeConfiguration cubeConfiguration = new CubeConfiguration(); fire(cubeConfiguration); System.out.flush(); System.setOut(old); assertThat(baos.toString(), containsString("CubeDockerConfiguration:")); } private static class PathStringEndsWithMatcher extends StringEndsWith { public PathStringEndsWithMatcher(String suffix) { super(suffix); } @Override protected boolean evalSubstringOf(String s) { return Paths.get(s).endsWith(substring); } } }