From 356dc5eb19cc1da60cd59925bc521315d8c67bf8 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Thu, 13 Jan 2022 15:02:38 +1300 Subject: [PATCH 1/2] #2487 - ebean-test support Docker In Docker - docker container's hostname rather than hardcoded "localhost" --- .../test/config/platform/ClickHouseSetup.java | 2 +- .../test/config/platform/CockroachSetup.java | 2 +- .../io/ebean/test/config/platform/Config.java | 22 +++++++++++++++++-- .../ebean/test/config/platform/Db2Setup.java | 2 +- .../ebean/test/config/platform/HanaSetup.java | 2 +- .../test/config/platform/MariaDBSetup.java | 2 +- .../test/config/platform/MySqlSetup.java | 2 +- .../test/config/platform/PostgisSetup.java | 2 +- .../test/config/platform/PostgresSetup.java | 4 ++-- .../test/config/platform/SqlServerSetup.java | 2 +- 10 files changed, 30 insertions(+), 12 deletions(-) diff --git a/ebean-test/src/main/java/io/ebean/test/config/platform/ClickHouseSetup.java b/ebean-test/src/main/java/io/ebean/test/config/platform/ClickHouseSetup.java index 4dcb472b4..a2a6ca0e0 100644 --- a/ebean-test/src/main/java/io/ebean/test/config/platform/ClickHouseSetup.java +++ b/ebean-test/src/main/java/io/ebean/test/config/platform/ClickHouseSetup.java @@ -11,7 +11,7 @@ class ClickHouseSetup implements PlatformSetup { config.setDefaultPort(8123); config.setUsername("default"); config.setPassword(""); - config.setUrl("jdbc:clickhouse://localhost:${port}/${databaseName}"); + config.setUrl("jdbc:clickhouse://${host}:${port}/${databaseName}"); config.setDriver("ru.yandex.clickhouse.ClickHouseDriver"); config.datasourceDefaults(); diff --git a/ebean-test/src/main/java/io/ebean/test/config/platform/CockroachSetup.java b/ebean-test/src/main/java/io/ebean/test/config/platform/CockroachSetup.java index 879f895ee..b68ca912e 100644 --- a/ebean-test/src/main/java/io/ebean/test/config/platform/CockroachSetup.java +++ b/ebean-test/src/main/java/io/ebean/test/config/platform/CockroachSetup.java @@ -11,7 +11,7 @@ class CockroachSetup implements PlatformSetup { config.setDefaultPort(26257); config.setUsername("root"); config.setPassword(""); - config.setUrl("jdbc:postgresql://localhost:${port}/${databaseName}?sslmode=disable"); + config.setUrl("jdbc:postgresql://${host}:${port}/${databaseName}?sslmode=disable"); config.setDriver("org.postgresql.Driver"); config.datasourceDefaults(); diff --git a/ebean-test/src/main/java/io/ebean/test/config/platform/Config.java b/ebean-test/src/main/java/io/ebean/test/config/platform/Config.java index cefae4ce4..7fdd44a07 100644 --- a/ebean-test/src/main/java/io/ebean/test/config/platform/Config.java +++ b/ebean-test/src/main/java/io/ebean/test/config/platform/Config.java @@ -4,8 +4,8 @@ import io.ebean.config.DatabaseConfig; import io.ebean.datasource.DataSourceConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import java.io.File; +import java.util.Locale; import java.util.Properties; /** @@ -26,7 +26,6 @@ class Config { private final String db; private final String platform; private String dockerPlatform; - private String databaseName; private final Properties properties; @@ -231,11 +230,30 @@ class Config { void setUrl(String urlPattern) { String val = getPlatformKey("url", urlPattern); + val = val.replace("${host}", host()); val = val.replace("${port}", String.valueOf(port)); val = val.replace("${databaseName}", databaseName); this.url = val; } + String host() { + String defaultHost = isInDocker() ? dockerHost() : "localhost"; + return getPlatformKey("host", defaultHost); + } + + static String dockerHost() { + String os = System.getProperty("os.name", "generic").toLowerCase(Locale.ENGLISH); + if (os.contains("mac") || os.contains("darwin") || os.contains("win")) { + return "host.docker.internal"; + } else { + return "172.17.0.1"; + } + } + + boolean isInDocker() { + return new File("/.dockerenv").exists(); + } + /** * Append to the connection URL. */ diff --git a/ebean-test/src/main/java/io/ebean/test/config/platform/Db2Setup.java b/ebean-test/src/main/java/io/ebean/test/config/platform/Db2Setup.java index fd65472ef..70fa4fc2c 100644 --- a/ebean-test/src/main/java/io/ebean/test/config/platform/Db2Setup.java +++ b/ebean-test/src/main/java/io/ebean/test/config/platform/Db2Setup.java @@ -11,7 +11,7 @@ class Db2Setup implements PlatformSetup { config.setDefaultPort(50000); config.setUsernameDefault(); config.setPasswordDefault(); - config.setUrl("jdbc:db2://localhost:${port}/${databaseName}"); + config.setUrl("jdbc:db2://${host}:${port}/${databaseName}"); config.setDriver("com.ibm.db2.jcc.DB2Driver"); config.datasourceDefaults(); diff --git a/ebean-test/src/main/java/io/ebean/test/config/platform/HanaSetup.java b/ebean-test/src/main/java/io/ebean/test/config/platform/HanaSetup.java index 8ad014b70..a5137686f 100644 --- a/ebean-test/src/main/java/io/ebean/test/config/platform/HanaSetup.java +++ b/ebean-test/src/main/java/io/ebean/test/config/platform/HanaSetup.java @@ -20,7 +20,7 @@ class HanaSetup implements PlatformSetup { config.setUsername("SYSTEM"); config.setPassword("HXEHana1"); config.setDatabaseName("HXE"); - config.setUrl("jdbc:sap://localhost:${port}/?databaseName=${databaseName}"); + config.setUrl("jdbc:sap://${host}:${port}/?databaseName=${databaseName}"); String schema = config.getSchema(); if (schema != null && !schema.equals(config.getUsername())) { config.urlAppend("¤tSchema=" + schema); diff --git a/ebean-test/src/main/java/io/ebean/test/config/platform/MariaDBSetup.java b/ebean-test/src/main/java/io/ebean/test/config/platform/MariaDBSetup.java index 4e242d4b0..f2ff22cc4 100644 --- a/ebean-test/src/main/java/io/ebean/test/config/platform/MariaDBSetup.java +++ b/ebean-test/src/main/java/io/ebean/test/config/platform/MariaDBSetup.java @@ -13,7 +13,7 @@ class MariaDBSetup implements PlatformSetup { config.setDefaultPort(defaultPort); config.setUsernameDefault(); config.setPasswordDefault(); - config.setUrl("jdbc:mariadb://localhost:${port}/${databaseName}?useLegacyDatetimeCode=false"); + config.setUrl("jdbc:mariadb://${host}:${port}/${databaseName}?useLegacyDatetimeCode=false"); config.datasourceDefaults(); return dockerProperties(config); diff --git a/ebean-test/src/main/java/io/ebean/test/config/platform/MySqlSetup.java b/ebean-test/src/main/java/io/ebean/test/config/platform/MySqlSetup.java index 3939ffbec..c865c41b7 100644 --- a/ebean-test/src/main/java/io/ebean/test/config/platform/MySqlSetup.java +++ b/ebean-test/src/main/java/io/ebean/test/config/platform/MySqlSetup.java @@ -13,7 +13,7 @@ class MySqlSetup implements PlatformSetup { config.setDefaultPort(defaultPort); config.setUsernameDefault(); config.setPasswordDefault(); - config.setUrl("jdbc:mysql://localhost:${port}/${databaseName}"); + config.setUrl("jdbc:mysql://${host}:${port}/${databaseName}"); config.setDriver(defaultDriver()); config.datasourceDefaults(); diff --git a/ebean-test/src/main/java/io/ebean/test/config/platform/PostgisSetup.java b/ebean-test/src/main/java/io/ebean/test/config/platform/PostgisSetup.java index 8180dc425..bd5a38387 100644 --- a/ebean-test/src/main/java/io/ebean/test/config/platform/PostgisSetup.java +++ b/ebean-test/src/main/java/io/ebean/test/config/platform/PostgisSetup.java @@ -20,7 +20,7 @@ class PostgisSetup implements PlatformSetup { config.setUsernameDefault(); config.setPasswordDefault(); config.setDriver("org.postgis.DriverWrapperLW"); - config.setUrl("jdbc:postgresql_lwgis://localhost:${port}/${databaseName}"); + config.setUrl("jdbc:postgresql_lwgis://${host}:${port}/${databaseName}"); String schema = config.getSchema(); if (schema != null && !schema.equals(config.getUsername())) { diff --git a/ebean-test/src/main/java/io/ebean/test/config/platform/PostgresSetup.java b/ebean-test/src/main/java/io/ebean/test/config/platform/PostgresSetup.java index 8e9045408..e5d1206f7 100644 --- a/ebean-test/src/main/java/io/ebean/test/config/platform/PostgresSetup.java +++ b/ebean-test/src/main/java/io/ebean/test/config/platform/PostgresSetup.java @@ -13,7 +13,7 @@ class PostgresSetup implements PlatformSetup { config.setDefaultPort(defaultPort); config.setUsernameDefault(); config.setPasswordDefault(); - config.setUrl("jdbc:postgresql://localhost:${port}/${databaseName}"); + config.setUrl("jdbc:postgresql://${host}:${port}/${databaseName}"); String schema = config.getSchema(); if (schema != null && !schema.equals(config.getUsername())) { @@ -44,7 +44,7 @@ class PostgresSetup implements PlatformSetup { config.setDefaultPort(defaultPort); config.setExtraUsernameDefault(); config.setExtraDbPasswordDefault(); - config.setUrl("jdbc:postgresql://localhost:${port}/${databaseName}"); + config.setUrl("jdbc:postgresql://${host}:${port}/${databaseName}"); config.setDriver("org.postgresql.Driver"); config.extraDatasourceDefaults(); } diff --git a/ebean-test/src/main/java/io/ebean/test/config/platform/SqlServerSetup.java b/ebean-test/src/main/java/io/ebean/test/config/platform/SqlServerSetup.java index 09b76323e..3428fb43e 100644 --- a/ebean-test/src/main/java/io/ebean/test/config/platform/SqlServerSetup.java +++ b/ebean-test/src/main/java/io/ebean/test/config/platform/SqlServerSetup.java @@ -13,7 +13,7 @@ class SqlServerSetup implements PlatformSetup { config.setDefaultPort(1433); config.setUsernameDefault(); config.setPassword("SqlS3rv#r"); - config.setUrl("jdbc:sqlserver://localhost:${port};databaseName=${databaseName};sendTimeAsDateTime=false"); + config.setUrl("jdbc:sqlserver://${host}:${port};databaseName=${databaseName};sendTimeAsDateTime=false"); config.setDriver("com.microsoft.sqlserver.jdbc.SQLServerDriver"); config.datasourceDefaults(); From 38bc5b2fea13a841f4ce5eb2650d3b7be1444059 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Fri, 14 Jan 2022 16:27:04 +1300 Subject: [PATCH 2/2] #2488 - refactor extract logic into DockerHost helper, fix RedisSetup, pass docker host to ebean-test-docker --- ebean-test/pom.xml | 2 +- .../io/ebean/test/config/platform/Config.java | 28 ++---- .../test/config/platform/DockerHost.java | 55 ++++++++++++ .../test/config/platform/RedisSetup.java | 6 +- .../test/config/platform/DockerHostTest.java | 87 +++++++++++++++++++ 5 files changed, 155 insertions(+), 23 deletions(-) create mode 100644 ebean-test/src/main/java/io/ebean/test/config/platform/DockerHost.java create mode 100644 ebean-test/src/test/java/io/ebean/test/config/platform/DockerHostTest.java diff --git a/ebean-test/pom.xml b/ebean-test/pom.xml index 4a2cdf3be..17041e36c 100644 --- a/ebean-test/pom.xml +++ b/ebean-test/pom.xml @@ -56,7 +56,7 @@ io.ebean ebean-test-docker - 4.3 + 4.4 diff --git a/ebean-test/src/main/java/io/ebean/test/config/platform/Config.java b/ebean-test/src/main/java/io/ebean/test/config/platform/Config.java index 7fdd44a07..117c04a18 100644 --- a/ebean-test/src/main/java/io/ebean/test/config/platform/Config.java +++ b/ebean-test/src/main/java/io/ebean/test/config/platform/Config.java @@ -29,7 +29,6 @@ class Config { private String databaseName; private final Properties properties; - private int port; private String url; @@ -37,12 +36,10 @@ class Config { private String schema; private String username; private String password; - private final DatabaseConfig config; - private boolean containerDropCreate; - private final Properties dockerProperties = new Properties(); + private final DockerHost dockerHost = new DockerHost(); Config(String db, String platform, String databaseName, DatabaseConfig config) { this.db = db; @@ -237,21 +234,8 @@ class Config { } String host() { - String defaultHost = isInDocker() ? dockerHost() : "localhost"; - return getPlatformKey("host", defaultHost); - } - - static String dockerHost() { - String os = System.getProperty("os.name", "generic").toLowerCase(Locale.ENGLISH); - if (os.contains("mac") || os.contains("darwin") || os.contains("win")) { - return "host.docker.internal"; - } else { - return "172.17.0.1"; - } - } - - boolean isInDocker() { - return new File("/.dockerenv").exists(); + String explicitDockerHost = getKey("dockerHost", null); + return getKey("host", dockerHost.dockerHost(explicitDockerHost)); } /** @@ -340,7 +324,6 @@ class Config { void setDockerVersion(String version) { String val = getPlatformKey("version", version); dockerProperties.setProperty(dockerKey("version"), val); - if (containerDropCreate) { dockerProperties.setProperty(dockerKey("startMode"), "dropCreate"); } @@ -387,7 +370,10 @@ class Config { } private void initDockerProperties() { - + if (dockerHost.runningInDocker()) { + // tell ebean-docker-test we are not using localhost (for jdbc DB setup commands) + dockerProperties.setProperty(dockerKey("host"), dockerHost.dockerHost()); + } dockerProperties.setProperty(dockerKey("port"), String.valueOf(port)); dockerProperties.setProperty(dockerKey("dbName"), databaseName); if (schema != null) { diff --git a/ebean-test/src/main/java/io/ebean/test/config/platform/DockerHost.java b/ebean-test/src/main/java/io/ebean/test/config/platform/DockerHost.java new file mode 100644 index 000000000..5e3f0ce94 --- /dev/null +++ b/ebean-test/src/main/java/io/ebean/test/config/platform/DockerHost.java @@ -0,0 +1,55 @@ +package io.ebean.test.config.platform; + +import java.io.File; +import java.util.Locale; + +/** + * Helper to detect if running inside docker and determine host name for that case. + */ +class DockerHost { + + private final boolean runningInDocker; + private String dockerHost; + + DockerHost() { + runningInDocker = initInDocker(); + } + + boolean runningInDocker() { + return runningInDocker; + } + + String dockerHost() { + return dockerHost; + } + + String dockerHost(String explicitHost) { + if (!runningInDocker) { + return "localhost"; + } + dockerHost = explicitHost != null ? explicitHost : defaultDockerHost(); + return dockerHost; + } + + /** + * Return true if running inside a docker container (we are using docker in docker). + */ + boolean initInDocker() { + return new File("/.dockerenv").exists(); + } + + /** + * Return the default host name to use when running in docker. + *

+ * Can instead be explicitly specified via ebean.test.dockerHost. + */ + String defaultDockerHost() { + String os = System.getProperty("os.name", "generic").toLowerCase(Locale.ENGLISH); + if (os.contains("mac") || os.contains("darwin") || os.contains("win")) { + return "host.docker.internal"; + } else { + return "172.17.0.1"; + } + } + +} diff --git a/ebean-test/src/main/java/io/ebean/test/config/platform/RedisSetup.java b/ebean-test/src/main/java/io/ebean/test/config/platform/RedisSetup.java index 70580bd81..c8fc01671 100644 --- a/ebean-test/src/main/java/io/ebean/test/config/platform/RedisSetup.java +++ b/ebean-test/src/main/java/io/ebean/test/config/platform/RedisSetup.java @@ -8,10 +8,14 @@ import java.util.Properties; class RedisSetup { static void run(Properties properties) { - String version = properties.getProperty("ebean.test.redis"); version = properties.getProperty("ebean.test.redis.version", version); if (version != null) { + DockerHost dockerHost = new DockerHost(); + if (dockerHost.runningInDocker()) { + String host = dockerHost.dockerHost(properties.getProperty("ebean.test.dockerHost")); + properties.setProperty("redis.host", host); + } RedisConfig redisConfig = new RedisConfig(version, properties); RedisContainer container = new RedisContainer(redisConfig); container.start(); diff --git a/ebean-test/src/test/java/io/ebean/test/config/platform/DockerHostTest.java b/ebean-test/src/test/java/io/ebean/test/config/platform/DockerHostTest.java new file mode 100644 index 000000000..0be8a5d43 --- /dev/null +++ b/ebean-test/src/test/java/io/ebean/test/config/platform/DockerHostTest.java @@ -0,0 +1,87 @@ +package io.ebean.test.config.platform; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class DockerHostTest { + + @Test + void runningInDocker_when_false_alwaysUseLocalhost() { + DockerHost dockerHost = new DockerHost(); + assertFalse(dockerHost.runningInDocker()); + assertEquals("localhost", dockerHost.dockerHost("foo")); + } + + @Test + void runningInDocker_when_true_useExplicit() { + TDDockerHost dockerHost = new TDDockerHost(); + assertTrue(dockerHost.runningInDocker()); + + assertEquals("my-host", dockerHost.dockerHost("my-host")); + } + + @Disabled + @Test + void runningInDocker_when_trueAndLinux_useDefault() { + TDDockerHost dockerHost = new TDDockerHost(); + assertTrue(dockerHost.runningInDocker()); + + assertEquals("172.17.0.1", dockerHost.dockerHost(null)); + } + + @Test + void runningInDocker_when_windowsDefault() { + TDDockerHost dockerHost = new TDDockerHost(); + assertTrue(dockerHost.runningInDocker()); + + String origName = System.getProperty("os.name"); + System.setProperty("os.name", "win"); + try { + assertEquals("host.docker.internal",dockerHost.defaultDockerHost()); + assertEquals("host.docker.internal", dockerHost.dockerHost(null)); + } finally { + System.setProperty("os.name", origName); + } + } + + @Test + void runningInDocker_when_macDefault() { + TDDockerHost dockerHost = new TDDockerHost(); + assertTrue(dockerHost.runningInDocker()); + + String origName = System.getProperty("os.name"); + System.setProperty("os.name", "mac"); + try { + assertEquals("host.docker.internal",dockerHost.defaultDockerHost()); + assertEquals("host.docker.internal", dockerHost.dockerHost(null)); + } finally { + System.setProperty("os.name", origName); + } + } + + + @Test + void runningInDocker_when_linuxDefault() { + TDDockerHost dockerHost = new TDDockerHost(); + assertTrue(dockerHost.runningInDocker()); + + String origName = System.getProperty("os.name"); + System.setProperty("os.name", "linux"); + try { + assertEquals("172.17.0.1",dockerHost.defaultDockerHost()); + assertEquals("172.17.0.1", dockerHost.dockerHost(null)); + } finally { + System.setProperty("os.name", origName); + } + } + + static class TDDockerHost extends DockerHost { + + @Override + boolean initInDocker() { + return true; + } + } +}