Java tutorial
/** * JBoss, Home of Professional Open Source. * Copyright 2014 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * 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 org.jboss.pnc.environment.docker; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.junit.Arquillian; import org.jboss.pnc.common.Configuration; import org.jboss.pnc.common.json.ConfigurationParseException; import org.jboss.pnc.common.json.moduleconfig.DockerEnvironmentDriverModuleConfig; import org.jboss.pnc.common.json.moduleprovider.PncConfigProvider; import org.jboss.pnc.common.util.HttpUtils; import org.jboss.pnc.model.BuildType; import org.jboss.pnc.model.RepositoryType; import org.jboss.pnc.spi.environment.RunningEnvironment; import org.jboss.pnc.spi.environment.exception.EnvironmentDriverException; import org.jboss.pnc.spi.repositorymanager.RepositoryManagerException; import org.jboss.pnc.spi.repositorymanager.RepositoryManagerResult; import org.jboss.pnc.spi.repositorymanager.model.RepositoryConnectionInfo; import org.jboss.pnc.spi.repositorymanager.model.RepositorySession; import org.jboss.pnc.test.category.ContainerTest; import org.jboss.pnc.test.category.RemoteTest; import org.jboss.shrinkwrap.api.ShrinkWrap; import org.jboss.shrinkwrap.api.asset.EmptyAsset; import org.jboss.shrinkwrap.api.spec.WebArchive; import org.jboss.shrinkwrap.resolver.api.maven.Maven; import org.junit.Before; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; import org.slf4j.LoggerFactory; import javax.inject.Inject; import java.io.File; import java.io.IOException; import java.lang.invoke.MethodHandles; import java.net.Socket; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; /** * Unit tests for DockerEnnvironmentDriver * * @author Jakub Bartecek <jbartece@redhat.com> */ @RunWith(Arquillian.class) @Category({ RemoteTest.class, ContainerTest.class }) public class DockerEnvironmentDriverRemoteTest { private static final org.slf4j.Logger logger = LoggerFactory .getLogger(MethodHandles.lookup().lookupClass().getName()); private static final String APROX_DEPENDENCY_URL = "AProx dependency URL"; private static final String APROX_DEPLOY_URL = "AProx deploy URL"; private static final RepositorySession DUMMY_REPOSITORY_CONFIGURATION = new DummyRepositoryConfiguration(); /** Maximum test duration in seconds */ private static final int MAX_TEST_DURATION = 100; @Inject private DockerEnvironmentDriver dockerEnvDriver; @Inject private Configuration configurationService; private String dockerIp; private String dockerControlEndpoint; private String dockerProxyHost; private String dockerProxyPort; private boolean isInitialized = false; @Deployment public static WebArchive createDeployment() { final WebArchive testedEjb = ShrinkWrap.create(WebArchive.class) .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml").addAsResource("pnc-config.json") .addPackage(RemoteTest.class.getPackage()) .addPackages(true, DockerEnvironmentDriver.class.getPackage()); File[] libs = Maven.resolver().loadPomFromFile("pom.xml").importRuntimeDependencies().resolve() .withTransitivity().asFile(); testedEjb.addAsLibraries(libs); logger.info("Deployment: " + testedEjb.toString(true)); return testedEjb; } @Before public void init() throws ConfigurationParseException { if (!isInitialized) { final DockerEnvironmentDriverModuleConfig config = configurationService .getModuleConfig(new PncConfigProvider<DockerEnvironmentDriverModuleConfig>( DockerEnvironmentDriverModuleConfig.class)); dockerIp = config.getIp(); dockerControlEndpoint = "http://" + dockerIp + ":2375"; dockerProxyHost = config.getProxyServer(); dockerProxyPort = config.getProxyPort(); isInitialized = true; } } @Test public void injectedTypeTest() { assertNotNull(dockerEnvDriver); } @Test public void canBuildEnvironmentTest() { assertTrue(dockerEnvDriver.canBuildEnvironment(BuildType.JAVA)); assertFalse(dockerEnvDriver.canBuildEnvironment(null)); assertFalse(dockerEnvDriver.canBuildEnvironment(BuildType.DOCKER)); } @Test public void buildDestroyEnvironmentTest() throws EnvironmentDriverException, InterruptedException { final Semaphore mutex = new Semaphore(0); // Create container final DockerStartedEnvironment startedEnv = (DockerStartedEnvironment) dockerEnvDriver .buildEnvironment(BuildType.JAVA, DUMMY_REPOSITORY_CONFIGURATION); Consumer<RunningEnvironment> onComplete = (generalRunningEnv) -> { DockerRunningEnvironment runningEnv = (DockerRunningEnvironment) generalRunningEnv; boolean containerDestroyed = false; try { testRunningContainer(runningEnv, true, "Environment wasn't successfully built."); testRunningEnvContainer(runningEnv, true, "Environment wasn't set up correctly."); // Destroy container dockerEnvDriver.destroyEnvironment(runningEnv.getId()); containerDestroyed = true; testRunningContainer(runningEnv, false, "Environment wasn't successfully destroyed."); mutex.release(); } catch (Throwable e) { fail(e.getMessage()); } finally { if (!containerDestroyed) destroyEnvironmentWithReport(runningEnv.getId()); } }; Consumer<Exception> onError = (e) -> { destroyEnvironmentWithReport(startedEnv.getId()); fail("Failed to init docker container. " + e.getMessage()); }; startedEnv.monitorInitialization(onComplete, onError); mutex.tryAcquire(MAX_TEST_DURATION, TimeUnit.SECONDS); } /** * Checks if container was started and the services are on. * * @param runningEnv Connection data about environment to test * @param shouldBeRunning Indicates, if the environment should be running or should be not available * @param baseErrorMsg Prefix of error message, which is printed if the container is not in expected state */ private void testRunningContainer(final DockerRunningEnvironment runningEnv, final boolean shouldBeRunning, final String baseErrorMsg) { final int sshPort = runningEnv.getSshPort(); final String containerId = runningEnv.getId(); // Test if the container is running try { HttpUtils.testResponseHttpCode(200, dockerControlEndpoint + "/containers/" + containerId + "/json"); assertEquals(baseErrorMsg + " Container is running", shouldBeRunning, true); } catch (final Exception e) { assertEquals(baseErrorMsg + " Container is not running", shouldBeRunning, false); } // Test if Jenkins is running try { HttpUtils.testResponseHttpCode(200, runningEnv.getBuildAgentUrl()); if (!shouldBeRunning) { fail("Jenkins is running, but should be down"); } } catch (final Exception e) { if (shouldBeRunning) { fail("Jenkins wasn't started successully"); } } // Test it the SSH port is opened assertEquals(baseErrorMsg + " Test opened SSH port", shouldBeRunning, testOpenedPort(sshPort)); } private void testRunningEnvContainer(final DockerRunningEnvironment runningEnv, final boolean shouldBeRunning, final String baseErrorMsg) { final int sshPort = runningEnv.getSshPort(); final String containerId = runningEnv.getId(); // Test if the container is running try { HttpUtils.testResponseHttpCode(200, dockerControlEndpoint + "/containers/" + containerId + "/json"); String containerJSON = HttpUtils .processGetRequest(dockerControlEndpoint + "/containers/" + containerId + "/json"); Map<String, Object> jsonMap = getJSONFromString(containerJSON); Map<String, Object> envMap = getEnvJSONFromDocker(jsonMap); String proxyIP = (String) envMap.get("proxyIPAddress"); String proxyPort = (String) envMap.get("proxyPort"); String isHttpActive = (String) envMap.get("isHttpActive"); assertEquals(dockerProxyHost, proxyIP); assertEquals(dockerProxyPort, proxyPort); assertEquals(((dockerProxyHost == null) || (dockerProxyPort == null)), isHttpActive); assertEquals(baseErrorMsg + " Container is running", shouldBeRunning, true); } catch (final Exception e) { assertEquals(baseErrorMsg + " Container is not running", shouldBeRunning, false); } // Test if Jenkins is running try { HttpUtils.testResponseHttpCode(200, runningEnv.getBuildAgentUrl()); if (!shouldBeRunning) { fail("Jenkins is running, but should be down"); } } catch (final Exception e) { if (shouldBeRunning) { fail("Jenkins wasn't started successully"); } } // Test it the SSH port is opened assertEquals(baseErrorMsg + " Test opened SSH port", shouldBeRunning, testOpenedPort(sshPort)); } static private Map<String, Object> getJSONFromString(String str) { Map<String, Object> result = new HashMap<String, Object>(); try { result = (Map<String, Object>) new ObjectMapper().readValue(str, Map.class); } catch (JsonMappingException jme) { logger.error("Error while converting container JSON to Map - " + jme.getLocalizedMessage()); } catch (IOException ioe) { logger.error("Error while converting container JSON to Map - " + ioe.getLocalizedMessage()); } return result; } private void destroyEnvironmentWithReport(String id) { try { dockerEnvDriver.destroyEnvironment(id); } catch (Exception e1) { logger.warn("Environment LEAK! The running environment couldn't be removed. ID: " + id + "\n" + e1); } } private boolean testOpenedPort(final int port) { try { final Socket echoSocket = new Socket(dockerIp, port); echoSocket.close(); } catch (final IOException e) { return false; } return true; } /** * Get Environment variables from Map created from JSON * @param map * @return */ @SuppressWarnings("unchecked") static private Map<String, Object> getEnvJSONFromDocker(Map<String, Object> map) { Map<String, Object> result = new HashMap<String, Object>(); Map<String, Object> configMap = ((Map<String, Object>) map.get("Config")); Object envConfig = configMap.get("Env"); if (envConfig instanceof ArrayList<?>) { List<?> configEnv = (ArrayList<?>) envConfig; for (Object object : configEnv) { String valuePair = (String) object; String[] splitStrings = valuePair.split("="); result.put(splitStrings[0], splitStrings[1]); } } return result; } private static class DummyRepositoryConfiguration implements RepositorySession { @Override public RepositoryType getType() { return null; } @Override public String getBuildRepositoryId() { return null; } @Override public RepositoryConnectionInfo getConnectionInfo() { return new RepositoryConnectionInfo() { @Override public String getToolchainUrl() { return null; } @Override public Map<String, String> getProperties() { return null; } @Override public String getDeployUrl() { return APROX_DEPLOY_URL; } @Override public String getDependencyUrl() { return APROX_DEPENDENCY_URL; } }; } @Override public RepositoryManagerResult extractBuildArtifacts() throws RepositoryManagerException { return null; } } }