Java tutorial
package org.awesomeagile.dao.testing; /* * ================================================================================================ * Awesome Agile * %% * Copyright (C) 2015 Mark Warren, Phillip Heller, Matt Kubej, Linghong Chen, Stanislav Belov, Qanit Al * %% * 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. * ------------------------------------------------------------------------------------------------ */ import static java.util.Arrays.asList; import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.base.Strings; import com.spotify.docker.client.DefaultDockerClient; import com.spotify.docker.client.messages.ContainerConfig; import com.spotify.docker.client.messages.ContainerCreation; import com.spotify.docker.client.messages.HostConfig; import com.spotify.docker.client.messages.PortBinding; import org.awesomeagile.testutils.NetworkUtils; import org.flywaydb.core.Flyway; import org.junit.rules.ExternalResource; import org.springframework.core.io.ClassPathResource; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.ConnectionCallback; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.datasource.DriverManagerDataSource; import org.springframework.jdbc.datasource.init.ScriptUtils; import java.sql.Connection; import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.sql.DataSource; /** * @author sbelov@google.com (Stan Belov) */ public class TestDatabase extends ExternalResource { public static final int TIMEOUT = 5; public static final int RETRIES = 30; public static final int POSTGRESQL_PORT = 5432; public static final String POSTGRES_9_2_IMAGE = "postgres:9.4"; private static final String USERNAME = "postgres"; private static final String PASSWORD = ""; private String hostName; private ContainerCreation container; private DefaultDockerClient docker; private int localPort; private final String databaseName; private final List<String> scripts; public TestDatabase(String databaseName, String... scripts) { Preconditions.checkArgument(!Strings.isNullOrEmpty(databaseName)); this.databaseName = databaseName; this.scripts = asList(scripts); } @Override protected void before() throws Throwable { // Create a client based on DOCKER_HOST and DOCKER_CERT_PATH env vars docker = DefaultDockerClient.fromEnv().build(); hostName = docker.getHost(); docker.pull(POSTGRES_9_2_IMAGE); // Bind container ports to host ports localPort = NetworkUtils.findAvailablePort(); final HostConfig hostConfig = HostConfig.builder() .portBindings(createPortBinding(POSTGRESQL_PORT, localPort)).build(); this.container = docker.createContainer(ContainerConfig.builder().image(POSTGRES_9_2_IMAGE) .hostConfig(hostConfig).exposedPorts(String.valueOf(POSTGRESQL_PORT)).build()); docker.startContainer(container.id()); waitForDatabase(RETRIES); createDatabase(); Flyway flyway = new Flyway(); flyway.setSqlMigrationPrefix("v"); flyway.setSqlMigrationSeparator("-"); flyway.setDataSource(getDataSource(databaseName)); flyway.migrate(); for (String script : scripts) { executeScript(script); } } public void executeScript(final String script) { executeScript(Optional.of(databaseName), script); } public JdbcTemplate jdbcTemplate() { return new JdbcTemplate(getDataSource()); } public DriverManagerDataSource getDataSource() { return new DriverManagerDataSource(/* url */ getUrl(), /* username */ "postgres", /* password */ ""); } public JdbcTemplate jdbcTemplate(String database) { return new JdbcTemplate(getDataSource(database)); } public DataSource getDataSource(String database) { return new DriverManagerDataSource(/* url */ getUrl(database), /* username */ "postgres", /* password */ ""); } public String getUrl() { return String.format("jdbc:postgresql://%s:%d/", hostName, localPort); } public String getUrl(String database) { return String.format("jdbc:postgresql://%s:%d/%s", hostName, localPort, database); } @Override protected void after() { try { docker.stopContainer(container.id(), TIMEOUT); docker.removeContainer(container.id()); } catch (Exception ex) { throw new RuntimeException("Unable to stop the Docker container", ex); } } private static Map<String, List<PortBinding>> createPortBinding(int from, int to) { final Map<String, List<PortBinding>> portBindings = new HashMap<>(); List<PortBinding> hostPorts = new ArrayList<>(); hostPorts.add(PortBinding.of("0.0.0.0", to)); portBindings.put(String.valueOf(from), hostPorts); return portBindings; } private void waitForDatabase(int retries) { JdbcTemplate jdbcTemplate = jdbcTemplate(); int left = retries; while (left > 0) { left--; System.out.println(left + " attempts left"); try { Thread.sleep(1000); jdbcTemplate.execute("select 1"); return; } catch (Exception ex) { // ignore } } throw new RuntimeException("Database did not come up after " + retries + " attempts"); } private void executeScript(Optional<String> databaseName, final String script) { JdbcTemplate jdbcTemplate = databaseName.isPresent() ? jdbcTemplate(databaseName.get()) : jdbcTemplate(); jdbcTemplate.execute(new ConnectionCallback<Object>() { @Override public Object doInConnection(Connection con) throws SQLException, DataAccessException { ScriptUtils.executeSqlScript(con, new ClassPathResource(script)); return null; } }); } private void createDatabase() { JdbcTemplate jdbcTemplate = jdbcTemplate(); jdbcTemplate.execute(String.format("DROP DATABASE IF EXISTS %s", databaseName)); jdbcTemplate.execute(String.format("CREATE DATABASE %s", databaseName)); } public String getUserName() { return USERNAME; } public String getPassword() { return PASSWORD; } }