All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.torodb.testing.docker.mysql.MysqlService Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2017 8Kdata Technology
 *
 * 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 com.torodb.testing.docker.mysql;

import com.google.common.base.Charsets;
import com.google.common.collect.Lists;
import com.google.common.net.HostAndPort;
import com.mysql.cj.jdbc.MysqlDataSource;
import com.spotify.docker.client.DockerClient;
import com.spotify.docker.client.exceptions.DockerException;
import com.spotify.docker.client.messages.ContainerConfig;
import com.spotify.docker.client.messages.HostConfig;
import com.spotify.docker.client.messages.PortBinding;
import com.spotify.docker.client.messages.Volume;
import com.torodb.testing.docker.ImageInstaller;
import com.torodb.testing.docker.ImagePuller;
import com.torodb.testing.docker.SimpleDockerService;
import com.torodb.testing.docker.UntilStdLineContains;
import com.torodb.testing.docker.WaitCondition;
import com.torodb.testing.docker.sql.ConnectionOwnerDslContext;
import com.torodb.testing.docker.sql.SqlService;
import org.jooq.DSLContext;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.sql.DataSource;

/**
 *
 */
public class MysqlService extends SimpleDockerService implements SqlService {
  private static final int MYSQL_PORT = 3306;
  private final MysqlConfig config;
  private HostAndPort bindingHostAndPort;
  private DataSource dataSource;

  public MysqlService(MysqlConfig config, WaitCondition waitCondition,
      ImageInstaller imageInstaller) {
    super(waitCondition, imageInstaller);
    this.config = config;
  }

  /**
   * Given a mysql version, creates a default service that, if needed, the image from Docker Hub.
   *
   * @param version the mysql version that will be used
   * @return a service ready to be started that creates a mysql docker with the default
   *         configuration.
   */
  public static MysqlService defaultService(MysqlVersion version) {
    MysqlConfig config = new MysqlConfig.Builder(version)
        .build();
    return defaultService(config);
  }

  /**
   * Given a mysql config, creates a default service that, if needed, the image from Docker Hub.
   *
   * @param config the mysql config that will be used
   * @return a service ready to be started that creates a mysql docker with the default
   *         configuration.
   */
  public static MysqlService defaultService(MysqlConfig config) {
    UntilStdLineContains waitCondition = new UntilStdLineContains("Database started");
    ImagePuller imageInstaller = new ImagePuller(
        config.getVersion().getDockerImageRef()
    );

    return new MysqlService(config, waitCondition, imageInstaller);
  }

  @Override
  protected String getImageRef() {
    return config.getVersion().getDockerImageRef();
  }

  private String getMyDataVolumeName() {
    return "mysql-" + System.identityHashCode(this);
  }

  @Override
  protected void additionalHostConfiguration(DockerClient client,
      HostConfig.Builder builder) throws DockerException, InterruptedException {
    Volume volume = client.createVolume(Volume.builder()
        .name(getMyDataVolumeName())
        .build()
    );
    builder.appendBinds(
        HostConfig.Bind.from(volume).to("/var/lib/mysql").build()
    );


    Map> portBindings = new HashMap<>();
    portBindings.put(
        Integer.toString(MYSQL_PORT),
        Lists.newArrayList(PortBinding.randomPort("0.0.0.0"))
    );
    
    builder.portBindings(portBindings);
  }

  @Override
  protected void additionalContainerConfiguration(DockerClient client,
      ContainerConfig.Builder builder) throws DockerException, InterruptedException {
    builder.exposedPorts(Integer.toString(MYSQL_PORT));
  }

  @Override
  protected Stream streamVolumesNamesToRemove() {
    return Stream.of(getMyDataVolumeName());
  }

  @Override
  protected void afterStarted(DockerClient client, String containerId) throws DockerException,
      InterruptedException {

    bindingHostAndPort = getBindingTcpPort(MYSQL_PORT)
        .orElseThrow(() ->
            new RuntimeException("There is no binding port for the mysql instance")
        );
    dataSource = createDataSource(bindingHostAndPort);
  }
  
  protected DataSource createDataSource(HostAndPort bindingHostAndPort) {

    MysqlDataSource ds = new MysqlDataSource();

    ds.setPortNumber(bindingHostAndPort.getPort());
    ds.setServerName(bindingHostAndPort.getHost());
    ds.setUser(config.getUsername());
    ds.setPassword(config.getPassword());
    ds.setDatabaseName(config.getDb());

    try (
        Connection conn = ds.getConnection();
        Statement stat = conn.createStatement();
        ResultSet rs = stat.executeQuery("SELECT 1")) {
      rs.next();
    } catch (SQLException ex) {
      throw new RuntimeException(ex.getLocalizedMessage());
    }
    return ds;
  }

  @Override
  public HostAndPort getAddress() {
    checkRunning();
    return bindingHostAndPort;
  }

  @Override
  public DataSource getDatasource() {
    checkRunning();
    return dataSource;
  }

  public MysqlConfig getConfig() {
    return config;
  }

  @Override
  public DSLContext getDslContext() {
    checkRunning();
    return new ConnectionOwnerDslContext(dataSource, config.getVersion().getDialect());
  }

  @Override
  protected List getCmd() {
    try (InputStream is = MysqlService.class.getResourceAsStream("mysql-docker-cmd.sh");
        BufferedReader reader = new BufferedReader(new InputStreamReader(is, Charsets.UTF_8))) {
      String script = reader.lines().collect(Collectors.joining("\n"));
      return Lists.newArrayList(
          "bash",
          "-c",
          script
      );
    } catch (IOException ex) {
      throw new RuntimeException(ex);
    }
  }

  @Override
  protected List getEnv() {
    return Lists.newArrayList(
        "MYSQL_ROOT_PASSWORD=" + config.getPassword(),
        "MYSQL_USER=" + config.getUsername(),
        "MYSQL_PASSWORD=" + config.getPassword(),
        "MYSQL_DATABASE=" + config.getDb()
    );
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy